How to Batch Resize Millions of Images to Fit a Max Width and Height

How to batch resize millions of images to fit a max width and height?

The best way I found to convert millions of images like these is by creating a simple bash script which starts converting all the images it finds, like the one listed below:

To edit this bash script, I use nano if you don't have nano: "apt-get install nano" for Ubuntu/Debian or "yum install nano" for CentOS/CloudLinux.. for other distributions: use Google) but you're free to use any editor you want.

Bash script

First, create the bash script by starting your favorite editor (mine's nano):

nano -w ~/imgconv.sh

Then fill it with this content:

#!/bin/bash
find ./ -type f -iname "*.jpeg" -exec mogrify -verbose -format jpeg -layers Dispose -resize 1024\>x1024\> -quality 75% {} +
find ./ -type f -iname "*.jpg" -exec mogrify -verbose -format jpg -layers Dispose -resize 1024\>x1024\> -quality 75% {} +
find ./ -type f -iname "*.png" -exec mogrify -verbose -format png -alpha on -layers Dispose -resize 1024\>x1024\> {} +

Then all you need to do is make it executable with chmod +x ~/imgconv.sh and run it from the main images directory where you want to resize the images in all subdirectories:

cd /var/www/webshop.example.com/public_html/media/
~/imgconv.sh

That should start the conversion process.

Explanation

The way the script works is that it uses find to find the file with extension .jpeg of any capitalization and then runs a command:

find ./ -type f -iname "*.jpeg" -exec <COMMAND> {} +

.. and then execute the appropriate convert job using the "-exec {} +" parameter:

mogrify -verbose -format jpeg -layers Dispose -resize 1024\>x1024\> -quality 75% <### the filename goes here, in this case *.jpeg ###>

If you're working with files older than today and you want to prevent re-doing files you've already converted today, you could even tell the 'find' command only convert the files older than today by adding the option -mtime +1 like so:

#!/bin/bash
find ./ -type f -mtime +1 -iname "*.jpeg" -exec mogrify -verbose -format jpeg -layers Dispose -resize 1024\>x1024\> -quality 75% {} +
find ./ -type f -mtime +1 -iname "*.jpg" -exec mogrify -verbose -format jpg -layers Dispose -resize 1024\>x1024\> -quality 75% {} +
find ./ -type f -mtime +1 -iname "*.png" -exec mogrify -verbose -format png -alpha on -layers Dispose -resize 1024\>x1024\> {} +

Performance

A really simple way to use more cores to perform this process is to fork each job to the background by adding a & after each line. Another way would be to use GNU Parallel, especially with the -X parameter as it will use all your CPU cores and get the job done many times quicker.

But no matter what kind of parallelization technique you'll be using, be sure only to do that on your own system and not on a shared disk system where your production platform resides, since going for maximum performance will bog down your hardware or hypervisor performance.

This job is going to take a while, so be sure to set up a screen or a terminal without timeout/noop packets beforehand. On my system, it churned through about 5000 files per minute, so the entire job should take less than ~50-60 hours... sounds like a fine job to run over the weekend.

Just be sure to separate all file extensions from each other by writing separate commands; Piling all options on top of each other and having 'mogrify' using all options for all image formats won't work.

ImageMagick is a powerful tool in the right hands.

How do I batch-resize images in ImageMagick while maintaining aspect ratio and a max width and height?

ImageMagick command line mogrify is likely what you want and can do what you need. It processes a folder full of images. See https://imagemagick.org/Usage/basics/#mogrify and https://imagemagick.org/script/command-line-options.php#resize. The command would like be something like the following:

Create a new directory to hold your output, say, thumbnails.
Change directory to your folder with the images

mogrify -path path_to/thumbnails -resize 488x220 *



That command will process every file in your folder. If you have other formats, such as txt or other images that you do not want to process, then modify the command to restrict to just png and jpg as follows:

mogrify -path path_to/thumbnails -resize 488x220 *.png *.jpg



add *.PNG *.JPG *.jpeg *.JPEG to the end of the line, if you have different caps and spellings for suffixes in your directory.

There are different APIs for other programming languages. See https://imagemagick.org/script/sitemap.php#program-interfaces

File size of images are not getting reduced after resize

You are probably getting more colors in your output file than in the input. If you want to preserve the orginal color set, use nearest-neighbor sampling instead of other types of filtering such as used by default when resizing. If you are using the command line, try

convert image_in -sample WxH image_out

instead of

convert image_in -resize WxH image_out

The result might be more jaggy than you'd like, so it's your choice to trade off appearance for filesize.

EDIT: The question was edited after this answer. The added information indicates that the image is in JPEG format (so adding colors is probably not the explanation) and it contains a SWOP color profile. The profile could be large, and is preserved by ImageMagick. For details, type "identify file.jpg", which will give you among other things the size of the color profile. If you want to remove the profile, use the "-strip" option.

How would I use ImageMagick in a .bat file (Windows) to resize all images in all sub-directories?

So, the information in the links from fmw42 was enough to cobble together an answer.

FOR /R %f IN (*.jpg) DO mogrify -verbose -resize "1200x1200>" "%f"

This will recursively affect every .jpg file in and under the folder this is run from (FOR /R %f IN (*.jpg) DO).

Each file will be shrunk to fit within a 1200x1200 box, maintaining the images aspect ratio, if the image in question is larger than 1200px in either direction.

How to resize image only if width exceeds with Graphics/Image Magick

You can easily achieve that by using an 'unlikely large' height value:

convert  orig.png  -resize '64x10000>'  scaled.png

This will resize the original PNG only if its width was larger than 64 pixels or if its height is larger than 10 000 pixels. But the chance that the command will ever encounter an input that's higher than 10 000 pixels is very low. So it will (almost) only encounter input files where the width value matches.

Original PNGs with widths lower than 64 pixels will remain untouched (unless their height is above 10 000 pixels...).



Related Topics



Leave a reply



Submit