Batch converting PNG to JPG in linux

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

which will keep the original as well as creating the converted image.

As for batch conversion, I think you need to use the Mogrify tool which is part of ImageMagick.

Keep in mind that this overwrites the old images.

The command is:

mogrify -format jpg *.png

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 'convert "$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).

ls -1 *.png | parallel convert '{}' '{.}.jpg'

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

ls -1 *.png | parallel -j 3 convert '{}' '{.}.jpg'

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

ls -1 *.png | parallel --eta convert '{}' '{.}.jpg'

There is also an alternative syntax if you are using GNU Parallel.

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

And a similar syntax for some other versions (including debian).

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

The convert command found on many Linux distributions is installed as part of the ImageMagick suite. Here's the bash code to run convert on all PNG files in a directory and avoid that double extension problem:

for img in *.png; do
    filename=${img%.*}
    convert "$filename.png" "$filename.jpg"
done

tl;dr

For those who just want the simplest commands:

Convert and keep original files:

mogrify -format jpg *.png

Convert and remove original files:

mogrify -format jpg *.png && rm *.png

Batch Converting Explained

Kinda late to the party, but just to clear up all of the confusion for someone who may not be very comfortable with cli, here's a super dumbed-down reference and explanation.

Example Directory

bar.png
foo.png
foobar.jpg

Simple Convert

Keeps all original png files as well as creates jpg files.

mogrify -format jpg *.png

Result

bar.png
bar.jpg
foo.png
foo.jpg
foobar.jpg

Explanation

  • mogrify is part of the ImageMagick suite of tools for image processing.
    • mogrify processes images in place, meaning the original file is overwritten, with the exception of the -format option. (From the site: This tool is similar to convert except that the original image file is overwritten (unless you change the file suffix with the -format option))
  • The - format option specifies that you will be changing the format, and the next argument needs to be the type (in this case, jpg).
  • Lastly, *.png is the input files (all files ending in .png).

Convert and Remove

Converts all png files to jpg, removes original.

mogrify -format jpg *.png && rm *.png

Result

bar.jpg
foo.jpg
foobar.jpg

Explanation

  • The first part is the exact same as above, it will create new jpg files.
  • The && is a boolean operator. In short:
    • When a program terminates, it returns an exit status. A status of 0 means no errors.
    • Since && performs short circuit evaluation, the right part will only be performed if there were no errors. This is useful because you may not want to delete all of the original files if there was an error converting them.
  • The rm command deletes files.

Fancy Stuff

Now here's some goodies for the people who are comfortable with the cli.

If you want some output while it's converting files:

for i in *.png; do mogrify -format jpg "$i" && rm "$i"; echo "$i converted to ${i%.*}.jpg"; done

Convert all png files in all subdirectories and give output for each one:

find . -iname '*.png' | while read i; do mogrify -format jpg "$i" && rm "$i"; echo "Converted $i to ${i%.*}.jpg"; done

Convert all png files in all subdirectories, put all of the resulting jpgs into the all directory, number them, remove original png files, and display output for each file as it takes place:

n=0; find . -iname '*.png' | while read i; do mogrify -format jpg "$i" && rm "$i"; fn="all/$((n++)).jpg"; mv "${i%.*}.jpg" "$fn"; echo "Moved $i to $fn"; done

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