Resize all images to same absolute width with IM - imagemagick

I have a bunch of images of varying sizes and aspect ratios, most (but not all) in "portrait" mode. How do I scale them all to the exact same absolute width (say, 600px) and let IM use the appropriate height to keep the aspect ratio)? The doc and examples that I have seen for -geometry always use both width and height, unless they use relative scales, which I don't want to do here.

Try this - it will write the output files to a subdirectory called results:
mkdir results
magick mogrify -path results -resize 600x *.jpg
Omit the magick if using v6 or older.

Related

How to fit multiple images in a page optimally using ImageMagick

Suppose I have a bunch of images in a folder with different sizes. The goal is to fit images in a number of pages (e.g. A4) in a way that the whitespace is minimal. There shouldn't be any compression or resizing involved. It is acceptable that some images would be rotated.
Here is what I came up with but doesn't try to "fit" images in any way:
montage *.jpg -mode concatenate -tile 2x2 -page A4 -geometry +20+20 out.pdf
Is it possible using imagemagick and montage switches?
I guess the computational geometry algorithm should change the 2x2 and +20+20 part of the command above, right?
In ImageMagick 7 (7.0.10-23 or higher), there is a new feature for doing collages called Ashlar. But it resizes to fit all the provided images into the space allocated.
See https://imagemagick.org/script/formats.php#pseudo
magick *.jpg -define ashlar:best-fit=true ashlar:canvas.png[1000x1000+5+5]
The [1000x1000+5+5] specifies the output dimensions and the minimum spacing in x and y between images.
Here is A4 size result:
magick *.jpg -define ashlar:best-fit=true ashlar:canvas2.jpg[595x842++0+0]

ImageMagick: resize with borders in batch

I have a few images I want to convert in batch using ImageMagick.
All images should be converted to a specific width, lets say 500px.
If an image's width is larger than 500px, scale it down and preserve the aspect ratio.
If an image's width is less than 500px, add borders to the sides to make it 500px wide.
The first one is possible using magick mogrify -resize 500x *, but this also scales images with a smaller width up. How can I prevent that from happening and add borders instead?
I figured I could just add -background black -gravity center but I don't know how to prevent upscaling.
Solved it using two separate commands for now:
Resize images larger than 500px wide:
magick mogrify -resize '500x>' *
Add borders to images smaller than 500px wide:
magick mogrify -gravity center -extent '735x<' *

ImageMagick: get biggest square out of image

I do have thousands of images in different sizes; now I would like to get the biggest square out of it that's possible without transparent/black background. Of course, the ratio should be kept, if it's e.g. a landscape image all height should be in the destination image but the left and right should be cropped; for portrait images, the other way round.
How's that possible?
I think you mean this. If you start with a landscape image bean.jpg:
magick bean.jpg -gravity center -extent "%[fx:h<w?h:w]x%[fx:h<w?h:w]" result.jpg
If you start with a portrait image, scooby.jpg:
magick scooby.jpg -gravity center -extent "%[fx:h<w?h:w]x%[fx:h<w?h:w]" result2.jpg
The part inside the double-quotes is the interesting part. It is basically setting the extent of the image, like:
-extent 100x100
where 100 is the width and the height. Rather than that though, I am using a calculated expression which tests whether the height (h) is less than the width (w) using a ternary operator. That results in taking whatever is smaller out of the current height and width as the new height and width, So there are really two calculated expressions in there, with an x between them, similar to 100x100.
Note that this method requires ImageMagick v7 or better - i.e. it uses the magick command rather than v6's convert command. If you have v6, you need to use more steps. First, get the width and the height of the image, then choose the smaller of the two and then issue a convert command with the gravity and extent both set. In bash:
# Get width and height
read w h < <(identify -format "%w %h" scooby.jpg)
# Check them
echo $w,$h
272,391
# Set `n` to lesser of width and height
n=$w
[ $h -lt $n ] && n=$h
# Now do actual crop
convert scooby.jpg -gravity center -extent "${n}x${n}" result.jpg
If you have thousands to do, I would suggest using GNU Parallel if you are on macOS or Linux. If you are on Windows, sorry, you'll need a loop and be unable to easily use all your CPU cores.
I have not tested the following, so only try it out on a small, COPIED, sample of a few files:
# Create output directory
mkdir output
# Crop all JPEG files, in parallel, storing result in output directory
parallel --dry-run magick {} -gravity center -extent "%[fx:h<w?h:w]x%[fx:h<w?h:w]" output/{} ::: *.jpg
If the commands look good, remove the --dry-run part to do it for real.
If you're using ImageMagick v7, Mark Setchell has provided a simple method above (or below). If you're using IMv6, you can crop the largest center square from any image using a command lke this...
convert input.png -set option:distort:viewport "%[fx:min(w,h)]x%[fx:min(w,h)]" \
-distort affine "%[fx:w>h?(w-h)/2:0],%[fx:w<h?(h-w)/2:0] 0,0" output.png
That sets the output viewport size to the largest square you can crop from the input image. Then it adjusts the position of the input image so it is centered within that square viewport.
This command should work from a command prompt or script on most *nix systems. If you're using Windows, replace that continued line backslash "\" with a caret "^". If you're using a BAT script in Windows you'll also have to make all the single percent signs "%" into doubles "%%".
You can also simply change "convert" to "magick" to run this command using IMv7.
I find this easier to remember:
convert in.png -gravity Center -extent 1:1 out.png

Batch crop images to fixed height (CLI)

I have images of variable height and width, and I want to crop them all to be 200 pixels high, without any resizing. i.e. their width will remain the same, and height will be 200px. I want to use "north" gravity for this.
Any CLI tool that allows batch processing would be OK - imagemagick/mogrify, gm, etc. I've tried to figure this out but can't find any option to just leave width unspecified.
mogrify *.png -gravity North -extent x200 -path ./complete
The mogrify utility would suite your batch task with -gravity, -extent, and -path options:
You could leave the width unspecified by, well, leaving the width unspecified, and use extent to do the cropping:
convert in.png -extent x200 out.png
or, say,
mogrify -extent x200 *.png
For the wizard example image, that would turn this into this. You can see more resizing examples on the examples site, as well as some different ways of doing cropping.

Imagemagick: Convert to fixed height, proportional width

Using Imagemagick, I'd like to convert a batch of PNGs to a fixed height of 1080px and a proportional width. With proportional I mean this: If the original Image is scaled down 16.8% to 1080px, the width also needs to be scaled down by 16.8%.
Any way of using convert without having to calculate the exact geometry before (using identify and some bash calculation shenanigans) ?
Try this:
convert -resize x1080 {from_path} {to_path}
Image geometry is an option described to use with -resize
xheight Height given, width automagically selected to preserve aspect ratio.
So you only have to specify the height
There is one additional example. give it some values to the resize parameters and it'll automatically resize your image. Plus you can chose other parameters (gravity center or crop etc.).
convert image_example: \
-resize x160 -resize '160x<' -resize 50% \
-gravity center -crop 80x80+0+0 +repage image_example.jpg
Cheers

Resources