Tell me more ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Does anyone know a good way to batch-convert a bunch of PNGs into JPGs in linux? (I'm using Ubuntu).

A png2jpg binary that I could just drop into a shell script would be ideal.

share|improve this question

6 Answers

up vote 40 down vote accepted

Your best bet would be to use Imagemagick

I am not an expert in the actual usage, but I know you can pretty much do anything image related with this!

An example is:

convert image.png image.jpg

and it will keep the original as well as creating the converted image. As for batch. I think you need to use the Morgify tool (from the same command line when in imagemagick). Keep in mind that this overwrites the old images.

The command is:

mogrify -format jpg *.png  
share|improve this answer
+1, ImageMagick is good! – nik Nov 16 '09 at 2:30
3  
Awesome, that's exactly what I was after and will be using again. By the way, just to clarify as I didn't realise this is what you meant: convert is used to generate a separate output file, mogrify is used to modify the original image. – humble coffee Nov 16 '09 at 4:11
Thanks +1, I wasn't very clear - hopefully a tiny bit better. – William Hilsum Nov 16 '09 at 4:29
Is Morgify a typo? – Hello71 Jul 19 '10 at 16:37
1  
png images with transparent background does not convert properly to jpg. – vishnu Nov 28 '11 at 4:33
show 4 more comments

There is no reason to install ImageMagick if it won't ever be used again. The linux convert command, as pointed out by Jeffrey, is enough. To avoid that double extension problem this is what the bash code should look like:

for img in *.png; do
    filename=${img%.*}
    convert "$filename.png" "$filename.jpg"
done
share|improve this answer
7  
According to the man page for convert: "The convert program is a member of the ImageMagick(1) suite of tools." – humble coffee Nov 16 '09 at 4:06
1  
You are correct. For some reason I thought it was part of a different library. Either way the code I posted above is the correct way to automate batch conversion within a directory. – Marcin Nov 16 '09 at 4:17
1  
You can use bash expansion to improve that command like: for f in *.png; do convert "$f" "${f/%png/jpg}"; done – evilsoup Jan 28 at 2:57

The actual "png2jpg" command you are looking for is in reality split into two commands called pngtopnm and cjpeg, and they are part of the netpbm and libjpeg-progs packages, respectively.

png2pnm foo.png | cjpeg > foo.jpeg
share|improve this answer

For batch processing:

for img in *.png; do
  convert "$img" "$img.jpg"
done

You will end up with file names like image1.png.jpg though.

This will work in bash, and maybe bourne. I don't know about other shells, but the only difference would likely be the loop syntax.

share|improve this answer

my quick solution for i in $(ls | grep .png); do convert $i $(echo $i.jpg | sed s/.png//g); done

share|improve this answer
1  
This has got to be one of the ugliest, most convoluted command-lines I've ever seen – evilsoup Jan 28 at 2:56

I have a couple more solutions.

The simplest solution is like most already posted. A simple bash for loop.

for i in *.png ; do convert "$i" "${i%.*}.jpg" ; done

For some reason I tend to avoid loops in bash so here is a more unixy xargs approach, using bash for the name-mangling.

ls -1 *.png | xargs -n 1 bash -c 'echo "$0" "${0%.*}.jpg"'

The one I use. It uses GNU Parallel to run multiple jobs at once, giving you a performance boost. It is installed by default on many systems and is almost definitely in your repo (it is a good program to have around).

parallel convert '{}' '{.}.jpg' ::: *.png

The number of jobs defaults to the number of processes you have. I found better CPU usage using 3 jobs on my dual-core system.

parallel -j 3 convert '{}' '{.}.jpg' ::: *.png

And if you want some stats (an ETA, jobs completed, average time per job...)

parallel --eta convert '{}' '{.}.jpg' ::: *.png

The final command that I use looks like this for refrence. I use ls rather than parallel's syntax for who-knows-what reason.

ls -1 *.png | parallel -j 3 --eta convert '{}' '{.}.jpg'
share|improve this answer
1  
+1 for correct bash string expansion in the for, if I could give you another upvote for mentioning parallel, I would. There's one typo, however - you need a done at the end of that for loop. Also, for the parallel stuff, you could avoid using that ls and pipe with a construct like: parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png (see here) – evilsoup Jan 28 at 3:04
Fixed typo. That is a cool syntax that I didn't know of. I don't know which one I like better for probably the same reason I prefer not to use loops in bash. I put it the solution because it is probably the more "proper" way but I'll probably stick with the ls method for myself because it makes more sense to me. – Kevin Cox Jan 28 at 14:04
...although it should be noted that that syntax only works on GNU parallel. The parallel that's packaged in some linux distros (like Debian & Ubuntu) is actually a different version with a slightly different syntax (use -- rather than :::) - and even then, it frustratingly lacks some of the features of GNU parallel. – evilsoup Jan 28 at 14:17
(though those on distros that don't package GNU parallel can install it from source quite easily, using the instructions here) – evilsoup Jan 28 at 14:24
I think I should change it back then so that it works with as many versions as possible. – Kevin Cox Jan 28 at 18:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.