Crop portrait/landscape to square without resizing or knowing the width/height

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
weavermedia
Posts: 4
Joined: 2015-08-30T16:32:08-07:00
Authentication code: 1151

Crop portrait/landscape to square without resizing or knowing the width/height

Post by weavermedia »

I have portrait and landscape images of varying dimensions.

I'd like to crop them all to square, from the center, based on the shortest out of width and height.

In math terms I think of it like this: (Math.min(width, height)) x (Math.min(width,height))

For example:
500x1000 > crops to 500x500
1000x500 > crops to 500x500
500x500 > either goes unprocessed, or is cropped to 500x500

I've done a ton of reading and searching but I can't figure out how to reference the image width and height in a single-line command (Mac terminal).

I tried referencing %w and %h in -crop but can't get it to compare. I thought a ternary like this might work, but no luck:

Code: Select all

mogrify -gravity Center -crop "((%w>%h)?%h:%w)"x"((%w>%h)?%h:%w)"+0+0 +repage *.jpg
How do I do this in a single line?
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Crop portrait/landscape to square without resizing or knowing the width/height

Post by snibgo »

Sadly, "-crop" can't take expressions. You can use one "identify" command to find the minimum of (width, height), then crop to that dimension in each direction. Bash syntax:

Code: Select all

#!/bin/bash

DD=`identify -format "%[fx:min(w,h)]" rose:`

convert rose: -gravity center -crop ${DD}x${DD}+0+0 +repage out.png
snibgo's IM pages: im.snibgo.com
weavermedia
Posts: 4
Joined: 2015-08-30T16:32:08-07:00
Authentication code: 1151

Re: Crop portrait/landscape to square without resizing or knowing the width/height

Post by weavermedia »

Thanks again snibgo!

Is it possible to nest -identify inside a mogrify command so I can process a whole folder with a one-liner?

Or will I have to loop through all files with this bash script. No problem to do that, I just like one-liners :D
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Crop portrait/landscape to square without resizing or knowing the width/height

Post by snibgo »

Sorry, I don't know mogrify. You'll have to RTFM.

Nesting commands is a feature of bash, not IM. It's a shortcut that avoids variables. My commands above can be written as:

Code: Select all

convert rose: -gravity center -crop `identify -format "%[fx:min(w,h)]x%[fx:min(w,h)]+0+0" rose:` +repage out.png
I have to mention the filename (the built-in "rose:") twice: one for identify, and once for convert. Nesting identify within mogrify wouldn't help because identify would be run once, and the same result used for all files that mogrify processes.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop portrait/landscape to square without resizing or knowing the width/height

Post by fmw42 »

You can do it with viewport cropping and -distort SRT. See http://www.imagemagick.org/Usage/distor ... t_viewport.

Assume you have your images in test1 on the desktop. Create a new empty directory test2 also on the desktop, so that the output from mogrify does not overwrite you input images in test1

Code: Select all

cd desktop/test1
mogrify -path ../test2 -format jpg -set option:distort:viewport \
"%[fx:w>h?h:w]x%[fx:w>h?h:w]+%[fx:w>h?(w-h)/2:0]+%[fx:w>h?0:(h-w)/2]" \
-filter point -distort SRT 0 +repage *

With IM 7, you can do the same computations in -crop.
Post Reply