4

Is there a way to crop an image centered horizontally, but not centered vertically? For example, here is how I would want an image cropped:

expected

However, using the command mogrify -crop 250x250 -gravity North cat.jpg, I get:

gotted

Note I’m going to be doing this in a batch with around 10,000 images of different sizes, so I can’t explicitly pick an exact region to crop.

1

Off the top of my head, mathematically you should be dealing with coordinates that are starting at the top left 0,0 (aka: NorthWest in ImageMagick terminology) so you would want to position the crop box area to be something like this:

(width of image - width of crop area) / 2

So you could then conceptually do something like this with your example mogrify command:

mogrify -crop 250x250+[(width of image - 250)/2]+0 -gravity NorthWest cat.jpg

Which is fairly a nice concept, but is not a useful reality. But I just experimented a bit and got this to work for a single test image:

CROP_W=250
CROP_H=250
IMG_W=$(identify -format %w test.jpg)
X_OFFSET=$((($IMG_W-$CROP_W)/2))
mogrify -crop ${CROP_W}x${CROP_H}+${X_OFFSET}+0 -gravity NorthWest test.jpg

Since ImageMagick’s -gravity default is NorthWest anyway, you can simplify it by removing the -gravity option altogether like this:

CROP_W=250
CROP_H=250
IMG_W=$(identify -format %w test.jpg)
X_OFFSET=$((($IMG_W-$CROP_W)/2))
mogrify -crop ${CROP_W}x${CROP_H}+${X_OFFSET}+0 test.jpg

And after testing that concept out, I whipped up this Bash script and it works as expected. Just change the DIRECTORY value to match the actual directory you plan on acting on. And that echo mogrify allows you to see exactly what would be happening if the command were run; remove that echo and then let the script go at it if you are happy with the results:

#!/bin/bash

# Set the crop width and height.
CROP_W=250
CROP_H=250

# Set the directory to act on.
DIRECTORY='/path/to/images'

# Use find to find all of the images; in this case JPEG images.
find ${DIRECTORY} -type f \( -name "*.jpg" -o -name "*.JPG" \) |\
  while read FULL_IMAGE_PATH
  do
    # Get the image width with identify.
    IMG_W=$(identify -format %w ${FULL_IMAGE_PATH})

    # Calculate the X offset for the crop.
    X_OFFSET=$((($IMG_W-$CROP_W)/2))

    # Run the actual mogrify command.
    # mogrify -crop ${CROP_W}x${CROP_H}+${X_OFFSET}+0 ${FULL_IMAGE_PATH}
    echo mogrify -crop ${CROP_W}x${CROP_H}+${X_OFFSET}+0 ${FULL_IMAGE_PATH}

  done
  • 1
    That seems to have done the trick. You'd think that ImageMagick would have a NorthCenter gravity or something. – Steven Jeffries Oct 19 '15 at 2:52
  • @StevenJeffries I thought the same about 5 years ago for a client project I was working on. 5 years later, no dice. But hey, the math works for this method so no biggie. – Giacomo1968 Oct 19 '15 at 2:59
1

JakeGould gave a working solution, but I think a much easier solution is not to script it, but to use two step conversion. First reduce the height to 250 pixels with North gravity, then reduce the width to 250 pixels with Center gravity:

mogrify -gravity North -crop x250+0+0  cat.jpg
mogrify -gravity Center -crop 250x250+0+0  cat.jpg

Alternatively, you could use convert with a non-jpg intermediate image to prevent loss of quality due to the extra conversion to jpg:

convert -gravity North -crop x250+0+0 cat.jpg png:- | convert -gravity Center -crop 250x250+0+0 png:- cat.jpg
  • I think this is a better answer/solution than a complex script. – Harry Beadle Jan 14 '19 at 12:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.