LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Batch processing images. (https://www.linuxquestions.org/questions/slackware-14/batch-processing-images-831640/)

JamesGT 09-11-2010 09:06 PM

Batch processing images.
 
I have 15,000 PNG images in 6000 folders and subfolders.

What would be the best way to batch process them to scale them all down 50% and save them as a jpg?

ghostdog74 09-11-2010 09:16 PM

if you have imagemagick, you can use the convert command. see man convert.

You can also fire up your favourite language and do image editing yourself using Imaging libraries.
Code:

#!/usr/bin/env python
import Image
import sys
import os
root="/home"
for r,d,f in os.walk( os.path.join(root,"path","to","images") ):
    for files in f:
        if files[-3:].lower() == "png":
            filename=os.path.join(r,files)
            img = Image.open(filename)
            width,height=img.size
            img.thumbnail( (width/2,height/2), Image.ANTIALIAS)
            img.save(filename[:-3]+"jpg","JPEG")


rob.rice 09-11-2010 09:22 PM

http://www.imagemagick.org/script/index.php
this is a collection of command line image processing utils
so you will have to write a script to do what you want and most
likely let the computer work on it over night
don't forget to make a backup
REMEMBER TO MAKE BACKUP COPES !!!!!!

T3slider 09-11-2010 10:05 PM

Code:

find /path/to/top/level -iname "*.png" -exec bash -c 'convert "{}" -resize 50% `dirname "{}"`/`basename "{}" .png`.jpg' \;
That should do the trick. Had to use `bash -c` since otherwise {} will not be replaced in subshells. This will not remove the original .png files.

JamesGT 09-11-2010 10:58 PM

Quote:

Originally Posted by T3slider (Post 4094863)
Code:

find /path/to/top/level -iname "*.png" -exec bash -c 'convert "{}" -resize 50% `dirname "{}"`/`basename "{}" .png`.jpg' \;
That should do the trick. Had to use `bash -c` since otherwise {} will not be replaced in subshells. This will not remove the original .png files.

Thanks Tslider :)

I tried it, but it doesn't seem to work. It just sits there. I tried just the find portion and it does find all the PNG images, but it doesn't actually process them.

T3slider 09-12-2010 01:59 AM

Quote:

Originally Posted by JamesGT (Post 4094878)
Thanks Tslider :)

I tried it, but it doesn't seem to work. It just sits there. I tried just the find portion and it does find all the PNG images, but it doesn't actually process them.

You should make sure you have ImageMagick installed (`which convert` should return something). It will appear as though it is doing nothing -- that command doesn't echo anything to the display. With so many pictures it will take quite a long time. This might be better for tracking progress:
Code:

find /path/to/top/level -iname "*.png" -exec bash -c 'convert "{}" -verbose -resize 50% `dirname "{}"`/`basename "{}" .png`.jpg' \;
That will display information about the conversion. Make sure to adjust /path/to/top/level, of course.

JamesGT 09-12-2010 09:28 AM

ImageMagick is installed. I have been able to convert images within each folder, one by one, without a problem.

I let it run all night, there were no jpg images created.

Using just the find command, it displays all the images in their subdirectories just fine. Something with the "-exec bash -c" is not working properly on my system.

qweasd 09-12-2010 12:42 PM

Quote:

Originally Posted by JamesGT (Post 4095136)
ImageMagick is installed. I have been able to convert images within each folder, one by one, without a problem.

I let it run all night, there were no jpg images created.

Using just the find command, it displays all the images in their subdirectories just fine. Something with the "-exec bash -c" is not working properly on my system.

Hi! The script you were using may fail if some paths contain spaces or other fancy characters. Try this:

Code:

find /your/path -iname "*.png" | while read fname ; do convert "$fname" -verbose -resize 50% "`echo "$fname" | sed 's/\.png$/\.jpg/i'`" ; done

JamesGT 09-12-2010 03:04 PM

Ok, can you explain to me why that works?

T3slider 09-12-2010 05:23 PM

Yep, sorry about that, it was late and obviously I neglected the spaces. This would have worked:
Code:

find /path/to/top/level -iname "*.png" -exec bash -c 'convert "{}" -verbose -resize 50% "$(dirname "{}")/$(basename "{}" .png).jpg"' \;
since it quotes the filename being passed to convert (before the filename was being quoted when passed to dirname and basename but the final filename was unquoted and thus did not work).

qweasd's solution should work as well, and just spawns a subshell instead of using find's -exec option (and since my example spawned a subshell with `bash -c` anyway there isn't really an advantage to sticking 100% with find). `| while read variable` stores the entire contents of the line into $variable instead of breaking the line up into spaces. As long as you quote "$variable" then it will pass the entire line instead of just the first element. My solution relies on find directly launching a process for conversion, while qweasd's solution relies on getting the output from find and passing it through a loop. `| while read variable` was my favourite syntax in bash scripting for a while; unfortunately any variables set within the loop are unset outside of the loop because a new subshell is spawned, so I've tried to script around that syntax as of late. In this example it makes no difference, of course, so it is a viable solution.

[edit] I've also noticed that basename is case-sensitive and I don't believe there's a way around it, so using sed is probably a better solution to avoid .png.jpg names. [/edit]

ghostdog74 09-12-2010 06:43 PM

Quote:

Originally Posted by qweasd (Post 4095272)
Hi! The script you were using may fail if some paths contain spaces or other fancy characters. Try this:

Code:

find /your/path -iname "*.png" | while read fname ; do convert "$fname" -verbose -resize 50% "`echo "$fname" | sed 's/\.png$/\.jpg/i'`" ; done

Code:

find /your/path -iname "*.png" | while read -r fname
do
  convert "$fname" -verbose -resize 50% "${fname%.png}.jpg"
done


qweasd 09-12-2010 08:59 PM

Quote:

Originally Posted by JamesGT (Post 4095369)
Ok, can you explain to me why that works?

Code:

find /your/path -iname "*.png" | while read fname ; do
  convert "$fname" -verbose -resize 50% "`echo "$fname" | sed 's/\.png$/\.jpg/i'`"
done

find finds all files ending in .png, regardless of case, and passes it to bash. while read fname reads each line until the end of the stream into a variable fname. Double quotes around "$fname" prevent it from breaking up into multiple arguments. The sed command is a suffix replacement: s for substitution, i for ignoring case.

"${fname%.png}.jpg" by ghostdog74 is an even bashier way to do the substitution (good to know : ), although if I was worried about the case I could write "${fname%.[Pp][Nn][Gg]}.jpg"

JamesGT 09-13-2010 07:16 PM

Thank you very much! 10 hours later, all the files had been resized and convert to JPG at 70% quality.

I was also able to remove all the PNGs(they are backed up on DVDs)

You guys are awesome!


All times are GMT -5. The time now is 10:49 PM.