Say I wanted to change the size of a picture and keep the name the same, in terminal I would type: convert picture1.jpg -resize 1280x720! picture1.jpg Now what if I had a folder with hundred of these pictures and I wanted to change them all to 1280x720 and keep the same name. Is there any easier way then typing out that line for each picture?
cd myfolder
for file in *.jpg
do
convert "$file" -resize 1280x720! "$file"
done
In case there is tons of images you might run into trouble using an for f in *.jpg approach. In this case you might want to do something like:
find myfolder -maxdepth 1 -name *.jpg -exec convert \{\} -resize 1280x720! \{\} \;
That's exactly what mogrify is for:
mogrify -resize 1280x720! *.jpg
Related
This question already has answers here:
Ignore case when trying to match file names using find command in Linux
(5 answers)
Closed 5 years ago.
I wrote a bash script a while back that resizes and compresses all images in directory with Image Magick.
# Usage: smartResize "2400x2400>"
function smartResize() {
find ./ -name "*.jpg" -exec magick mogrify -resize $1 -sampling-factor 4:2:0 -strip -interlace JPEG -quality 85 -colorspace RGB {} \;
find ./ -name "*.JPG" -exec magick mogrify -resize $1 -sampling-factor 4:2:0 -strip -interlace JPEG -quality 85 -colorspace RGB {} \;
find ./ -name "*.jpeg" -exec magick mogrify -resize $1 -sampling-factor 4:2:0 -strip -interlace JPEG -quality 85 -colorspace RGB {} \;
find ./ -name "*.JPEG" -exec magick mogrify -resize $1 -sampling-factor 4:2:0 -strip -interlace JPEG -quality 85 -colorspace RGB {} \;
}
I had to add extra lines to find some alternative cases for .jpg extensions. Which I don't particularly like but got the job done.
Does anybody have a better idea of how to handle case sensitivity and the optional e in jpeg extensions?
n.b. I'm running this in Cmder: Git Bash on Windows.
GNU versions of find have an -iname flag which enables case insensitive matching of file name globs,
find ./ -iname '*.jpg'
or if you are on a system without GNU utilities, use the bracket expressions to the glob
find ./ -name '*.[Jj][Pp][Gg]'
If you are interested in multiple name filters, just use the -o expression for including multiple name globs
find ./ \( -iname "*.jpg" -o -iname "*.jpeg" \)
I have the code below for image conversion.
I have a directory with many images, I would like to convert all images that the width was less than 200 pixel.
Regardless of the extension, jpg, gif or png
find . -iname \*.jpg -exec convert -verbose -resize 200x140! "{}" "{}" \;
I think you want this - or something very close to it - so make a backup first!
find . \( -iname \*.jpg -o -iname \*.png -o -iname \*.gif \) \
-exec bash -c '[ $(identify -format %w "$0" ) -lt 200 ] && convert "$0" -resize 200x140\! "$0"' {} \;
That says... "find, starting in the current directory (.), any files whose names end, in a case-insensitive fashion (-iname), in JPG, PNG or GIF and start a new bash shell for each one. Once inside the shell, get the width of the file and if it is less than 200 pixels, execute the convert command to resize the file to 200x140, ignoring aspect ratio."
The "first" part in there is: acquiring the width of all images in that folder. And if I read your question correctly, that is where you have problems with; thus you can look into the identify command coming with ImageMagick. It works like this
identify -format "%wx%h" pic.jpg
See here for handling formatting. As soon as you got your list of "width matching" files, you should be able to further convert them.
The situation
I'm looking for a way to batch-resize approximately 15 million images of different file types to fit a certain bounding box resolution (in this case the image(s) cannot be bigger than 1024*1024), without distorting the image and thus retaining the correct aspect ratio. All files are currently located on a Linux server on which I have sudo access, so if I need to install anything, I'm good to go.
Things I've tried
After dabbling around with some tools under Windows (Adobe Photoshop and other tools) I am no longer willing to run this on my own machine as this renders it virtually unusable when rendering. Considering the size of this job, I'm really looking for some command-line magic to directly run it on Linux, but my endeavors with ImageMagick so far haven't given me anything to work with as I'm getting nothing but errors.
To be honest, ImageMagick's documentation could use some work... or someone should put in the effort to make a good web-interface to create one of these mythical image convertion one-liners.
Required output format
I need the images to be resized to the same filename and of a format which will fit inside a certain maximum dimension, for example 1024*1024, meaning:
a JPG of 2048*1024 becomes a JPG of 1024*512 at 75% quality
a PNG of 1024*2048 becomes a PNG of 512*1024
The resulting image should contain no additional transparent pixels to fill up the remaining pixels; I'm just looking for a way to convert the images to a limited resolution.
Thanks for any help!
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.
I am using mogrify to resize the images in a directory using the following command
mogrify -resize 100x100 *.jpg
due to the huge number of images, I get the following error
/usr/bin/mogrify: Argument list too long
Any suggestions?
Thanks
Actually, the answer is surprisingly simple. Rather than having the shell expand the argument list (which it cannot cope with), let ImageMagick expand the list itself internally, by protecting the arguments from the shell with single quotes.
So, your command becomes:
mogrify -resize 100x100 '*.jpg'
If the built-in glob expression does not work for you (eg. special file ordering), you may also use the special character '#':
mogrify -resize 100x100 #my_jpegs.txt
find or xargs come to mind, eg.
find . -name \*.jpg -exec mogrify '{}' -resize 100x100 \;
Cheers,
magick
said
Most shells limit the length of the command line. You can get around this by using ImageMagick filename globbing methods. So instead of mogrify -resize 50% *.jpg use mogrify -resize 50% "*.jpg"
Your case would be
mogrify -resize 100x100 "*.jpg"
I have the two folders under the same level directory
folder1 and folder 2
now I try to convert all images in folder1 to folder2 and with same file name.
here is what i have now:
for f in folder1/*.jpg
do
convert $f -resize 80%X80% +profile "*" -quality 85 folder2/$f
done
and it throws the following message from each file it tried to convert:
convert: unable to open image `folder1/folder2/st-3474827-1.jpg': No such file or directory # blob.c/OpenBlob/2440.
and I know its directory problem but google for two days already still dont know how to fix it. Can you help me with this?
There's two ways you could deal with it.
Use mogrify:
mogrify -path folder2 -thumbnail 50x50 folder1/*.jpg
Use basename:
for filename in folder1/*.jpg; do
basename="$(basename "$filename" .jpg)"
convert "folder1/$basename.jpg" -thumbnail 50x50 "folder2/$basename.jpg"
done
The former option is probably better, but the latter may be clearer.
I posted a couple of wrong answers. Sorry I just assumed that mogrify or convert would behave well with outputting to a different path. Shouldn't assume. I don't know if Imagemagick can output to a different directory. You may have to just mv the output(no suggestions here) to the new directory. I tried this( I was trying to be as simple as possible without any loops...
convert -resize 500x500 * ../test2/ #output was 2 files named -0 -1 in the new dir
mogrify -resize 200x150 ~/Pictures/rome/test/*.jpg -path ~/Pictures/rome/test2/ # gotta *.jpg in new dir YAY!
mogrify -resize 200x150 -path ~/Pictures/rome/test2/*.jpg ~/Pictures/rome/test/*.jpg # blob error
The manpages don't mention output to a new directory and I searched around a little. The exception codes for ImageMagick are here Good luck and sorry for the faulty gouge. I will edit if I find anything new.