Batch converting PNG to JPG in linux
Solution 1
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
Solution 2
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
Solution 3
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
Solution 4
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)
)
- mogrify processes images in place, meaning the original file is overwritten, with the exception of the
- 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.
- When a program terminates, it returns an exit status. A status of
- 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
Solution 5
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
Related videos on Youtube
nedned
Updated on September 17, 2022Comments
-
nedned over 1 year
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.
-
nedned over 14 yearsAccording to the man page for convert: "The convert program is a member of the ImageMagick(1) suite of tools."
-
nedned over 14 yearsAwesome, 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.
-
Marcin over 14 yearsYou 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.
-
Vishnu Pradeep over 12 yearspng images with transparent background does not convert properly to jpg.
-
hyperknot almost 12 yearsTo convert PNG's with transparent background, use the following command:
mogrify -format jpg -background black -flatten *.png
-
evilsoup over 11 yearsThis has got to be one of the ugliest, most convoluted command-lines I've ever seen
-
evilsoup over 11 yearsYou can use bash expansion to improve that command like:
for f in *.png; do convert "$f" "${f/%png/jpg}"; done
-
evilsoup over 11 years+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 thatls
and pipe with a construct like:parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png
(see here) -
Raza over 11 yearsFixed 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. -
evilsoup over 11 years...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 over 11 years(though those on distros that don't package GNU parallel can install it from source quite easily, using the instructions here)
-
Raza over 11 yearsI think I should change it back then so that it works with as many versions as possible.
-
neurino almost 11 yearsI wonder how can this overwrite original files if the filename changes... in fact jpg files keep untouched ;) Ah, +1
-
Raza over 10 years@neurino The file name isn't changed in the mogrify example. The files still have a
.png
extension but are jpeg images. Try usingfile img.png
(after running mogrify) and it will tell you that it is a jpeg image. -
neurino over 10 years@KevinCox on my linux box after
mogrify -format jpeg img.png
I have 2 files andfile img.*
reports one png, the original untouched, and a new jpeg one. Somogrify
does not overwrite original files in this case. -
Raza over 10 years@neurino Interesting. From the mogrify man page: "mogrify - resize an image, blur, crop, despeckle, dither, draw on, flip, join, re-sample, and much more. Mogrify overwrites the original image file, whereas, convert(1) writes to a different image file." So I don't know why that happens on your box.
-
Raza over 10 years@neurino This happens on my box as well. Now I'm really confused, it this a bug? Or an undocumented feature?
-
Max Howell over 10 years@evilsoup honestly, this is elegant for shell scripts. Claiming it is convoluted isn't fair.
-
evilsoup over 10 years@MaxHowell man. No. Here would be an elegant version of this:
for f in ./*.png; do convert "$f" "${f%.*}.jpg"; done
. That avoids the completely unnecessaryls
,grep
andsed
calls (andecho
, but IIRC that's a bash builtin and so will have no/very little performance impact), and gets rid of two pipes and two subshells, and involves less typing. It's even slightly more portable, since not all versions ofls
are safe to parse. -
Max Howell over 10 years@evilsoup I stand corrected! Good job.
-
janko-m over 9 yearsFrom
mogrify
documentation: "This tool is similiar toconvert
except that the original image file is overwritten (unless you change the file suffix with the -format option) with any changes you request." -
Joel Purra over 9 yearsThanks for a deep/recursive directory one-line solution which leaves the resulting
*.jpg
files next to the original*.png
files, shows how to reduce file size/quality and doesn't break because of any odd characters in directory or file name. -
don_crissti over 8 yearsProbably the best answer provided you get rid of the
while read
part (replace it or remove it all together)... -
Steven Jeffries over 8 years@don_crissti, what's wrong with while read?
-
don_crissti over 8 yearsIt's error prone (unless you're 100% sure you're dealing with sane file names) and slow (like in very, very, very slow).
-
tsenapathy about 8 yearsjust remember it's case sensitive. my camera name it as *.JPG and didn't realize this in first instance.
-
Flatron almost 8 yearsIf you need to compress your png's more use
mogrify -quality 75 -format jpg *.png
-
Nam G VU over 7 yearsMe too on Ubuntu Desktop 16 today - original files remain
-
Dan Dascalescu over 6 yearsWhat is the default JPG quality, and how can file timestamps be preserved?
-
Steven Jeffries over 6 years@DanDascalescu The methods above (except the last one) will preserve filenames, but replace their extension, so timestamped files should be okay (always make a copy and test first). According to ImageMagick, "The default is to use the estimated quality of your input image if it can be determined, otherwise 92" (imagemagick.org/script/command-line-options.php#quality) Quality can be specified with -quality <number> where <number> is 1 to 100.
-
Dan Dascalescu over 6 yearsThanks.
mogrify -format jpg foo.png
created foo.jpg with the current timestamp though. I wanted to copy the timestamp of foo.png into foo.jpg, and I don't see anything of that nature in the options. -
Ahi Tuna over 5 yearsIf you have a directory with more than 10,000 png images in it... the ls command will likely fail. So, this command works in those situations:
find . -type f -name '*.png' | parallel --eta convert '{}' '{.}.jpg'
-
naim5am about 4 yearsThanks. Last comment but saved my from going down a rabbit hole figuring out why ? >> mogrify: unable to open image 'jpg:': No such file or directory @ error/blob.c/OpenBlob/3496.
-
Mahesh Jamdade about 3 yearsis it possible to compress the image, jpg to jpg or jpeg to jpeg?
-
ubershmekel about 3 yearsShould work. Please try this and let me know. Just change the line's
.png
to.jpg
. -
Mahesh Jamdade about 3 yearsjust to confirm is it this command
ffmpeg -i input.jpg output.jpg
-
ubershmekel about 3 yearsThat command you mentioned should recompress a single jpg.
-
Nae almost 3 yearsI've learnt so much from this answer.
-
Raymond over 2 yearsBe careful in using any of above command as it will mess up the background. I tried few commands and none worked. Always have a backup of your folder. @KevinCox you should test commands before posting as I messed up my images.
-
Raza over 2 years@Raymond all of these commands are testing and work fine. You would have to share more information for any help. What is "the background" and how is it messed up? One first step would be to check that you don't have any aliases or other custom commands that may be running instead of the commands intended by the answer.
-
Raymond over 2 yearsIt's the transparency, you should include it in the command or mention it.
-
Raza over 2 yearsJPEG images don't support transparency so no method of converting will preserve that. By default
convert
uses a black background but you can change the color using-background '#FF0000' -alpha remove
. -
Admin almost 2 yearsHow is this better than accepted answer given 13 years ago?
-
Admin almost 2 yearsTo elaborate on @Toto's answer: doesn't mogrify (as mentioned in that accepted answer) do this for you? It's a nice effort though :)