Python Image Library fails with message decoder JPEG not available - PIL
libjpeg-dev is required to be able to process jpegs with pillow (or PIL), so you need to install it and then recompile pillow. It also seems that libjpeg8-dev is needed on Ubuntu 14.04
If you're still using PIL then you should really be using pillow these days though, so first pip uninstall PIL
before following these instructions to switch, or if you have a good reason for sticking with PIL then replace "pillow" with "PIL" in the below).
On Ubuntu:
# install libjpeg-dev with apt
sudo apt-get install libjpeg-dev
# if you're on Ubuntu 14.04, also install this
sudo apt-get install libjpeg8-dev
# reinstall pillow
pip install --no-cache-dir -I pillow
If that doesn't work, try one of the below, depending on whether you are on 64bit or 32bit Ubuntu.
For Ubuntu x64:
sudo ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib
sudo ln -s /usr/lib/x86_64-linux-gnu/libfreetype.so /usr/lib
sudo ln -s /usr/lib/x86_64-linux-gnu/libz.so /usr/lib
Or for Ubuntu 32bit:
sudo ln -s /usr/lib/i386-linux-gnu/libjpeg.so /usr/lib/
sudo ln -s /usr/lib/i386-linux-gnu/libfreetype.so.6 /usr/lib/
sudo ln -s /usr/lib/i386-linux-gnu/libz.so /usr/lib/
Then reinstall pillow:
pip install --no-cache-dir -I pillow
(Edits to include feedback from comments. Thanks Charles Offenbacher for pointing out this differs for 32bit, and t-mart for suggesting use of --no-cache-dir
).
OSError: decoder jpeg not available on Windows
A Short Explanation
This is because the Pillow package does not bring the required libraries. That’s something you need to take care of. Hence JPEG support (along with other file formats) is not available.
To verify this, have a look at the setup summary after installing Pillow. If you don't have that around, simplay reinstall the package and the summary will be shown.
$ sudo pip uninstall Pillow
$ sudo pip install Pillow
In the summary we see that I installed Pillow version 2.3.1 on Windows 8.1. Most importantly, we see that there is no support for JPEG and PNG (ZLIB) image files.
--------------------------------------------------------------------
PIL SETUP SUMMARY
--------------------------------------------------------------------
version Pillow 2.3.1
platform win32 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:24:06
[MSC v.1600 32 bit (Intel)]
--------------------------------------------------------------------
*** TKINTER support not available
(Tcl/Tk 8.6 libraries needed)
*** JPEG support not available
*** ZLIB (PNG/ZIP) support not available
*** LIBTIFF support not available
*** FREETYPE2 support not available
*** LITTLECMS2 support not available
*** WEBP support not available
*** WEBPMUX support not available
--------------------------------------------------------------------
To add a missing option, make sure you have the required
library, and set the corresponding ROOT variable in the
setup.py script.
To check the build, run the selftest.py script.
A definite Solution
On Linux, simply install package libjpeg-dev and reinstall the Pillow library.
But since we are working with Windows, we have to go a little deeper: We need to download the jpeg library sources to provide the header files and build the library file on our own. Also do some copy and paste.
You need to install Visual C++ 2010 Express. You need it anyway to build Pillow in the first place, or you end up with the error: Unable to find vcvarsall.bat.
Then download the jpeg library package from the Independent JPEG Group and extract it to a temporary location.
Copy the header files
In the jpeg package search for three files named
- jpeglib.h
- jmorecfg.h
- jconfig.h (edit: needs to be created, see comments)
and copy them into the include folder of your Python installation directory (probably "C:\Python34\include\")
Build the library file
To be able to finish the next steps, run vcvarsall.bat. This will add all the necessary directories to your PATH variable. By default, you find this file in "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
Now open a command line and find the directory where you extracted the jpeg library source earlier on. Execute the following two commands:
> nmake /f makefile.vc setup-v10
> msbuild jpeg.sln
The second command builds the required file and places them in the newly created subdirectory \Release\.
Clean up and rebuild Pillow with JPEG support
Awesome, now we only need to copy the freshly built Release\jpeg.lib into our Python-libs directory (probably "C:\Python34\libs\").
Note: "libs", not "Lib".
Once more, install the Pillow package and take care of the setup summery. JPEG support is now available.
--- JPEG support available
Decoder JPEG not available error when following Django photo app tutorial
There are several cases with PIL which lead to a similar experience.
If you have installed PIL out of a virtualenv using
pip install PIL
Then you should have installed the dev versions of libjpeg, libz before.
Assuming you're on a Ubuntu box, a
pip uninstall PIL
apt-get install libjpeg-dev zlib1g-dev libpng12-dev
pip install PIL
should suffice. You could also install Pillow instead of PIL, it works better with setuptools and can be installed in a virtualenv.
Weird interaction with Python PIL image.save quality parameter
Quick takeaways from the following explanations...
- The
quality
parameter forPIL.Image.save
isn't used when saving PNGs. - JPEG is generationally-lossy so as you keep re-saving images, they will likely degrade in quality because the algorithm will introduce more artifacting (among other things)
- PNG is lossless and the file size differences you're seeing are due to
PIL
stripping metadata when you re-save your image.
Let's look at your PNG file first. PNG is a lossless format - the image data you give it will not suffer generational loss if you were to open it and re-save it as PNG over and over again.
The quality
parameter isn't even recognized by the PNG plugin to PIL - if you look at the PngImagePlugin.py/PngStream._save
method it is never referenced in there.
What's happening with your specific sample image is that Pillow is dropping some metadata when you re-save it in your code.
On my test system, I have your PNG saved as sample.png
, and I did a simple load-and-save with the following code and save it as output.png
(inside ipython
)
In [1]: from PIL import Image
In [2]: img = Image.open("sample.png")
In [3]: img.save("output.png")
Now let's look at the differences between their metadata with ImageMagick:
#> diff <(magick identify -verbose output.png) <(magick identify -verbose sample.png)
7c7,9
< Units: Undefined
---
> Resolution: 94.48x94.48
> Print size: 10.8383x10.8383
> Units: PixelsPerCentimeter
74c76,78
< Orientation: Undefined
---
> Orientation: TopLeft
> Profiles:
> Profile-exif: 5218 bytes
76,77c80,81
< date:create: 2022-08-12T21:27:13+00:00
< date:modify: 2022-08-12T21:27:13+00:00
---
> date:create: 2022-08-12T21:23:42+00:00
> date:modify: 2022-08-12T21:23:31+00:00
78a83,85
> exif:ImageDescription: IMGP5493_seamless_2.jpg
> exif:ImageLength: 1024
> exif:ImageWidth: 1024
84a92
> png:pHYs: x_res=9448, y_res=9448, units=1
85a94,95
> png:text: 1 tEXt/zTXt/iTXt chunks were found
> png:text-encoded profiles: 1 were found
86a97
> unknown: nomacs - Image Lounge 3.14
90c101
< Filesize: 933730B
---
> Filesize: 939469B
93c104
< Pixels per second: 42.9936MP
---
> Pixels per second: 43.7861MP
You can see there are metadata differences - PIL didn't retain some of the information when re-saving the image, especially some exif
properties (you can see this PNG was actually converted from a JPG and the EXIF metadata was preserved in the conversion).
However, if you re-save the image with original image's info
data...
In [1]: from PIL import Image
In [2]: img = Image.open("sample.png")
In [3]: img.save("output-with-info.png", info=img.info)
You'll see that the two files are exactly the same again:
❯ sha256sum output.png output-with-info.png
37ad78a7b7000c9430f40d63aa2f0afd2b59ffeeb93285b12bbba9c7c3dec4a2 output.png
37ad78a7b7000c9430f40d63aa2f0afd2b59ffeeb93285b12bbba9c7c3dec4a2 output-with-info.png
Maybe Reducing PNG File Size
While lossless, the PNG format does allow for reducing the size of the image by specifying how aggressive the compression is (there are also more advanced things you could do like specifying a compression dictionary).
PIL exposes these options as optimize
and compress_level
under PNG options.
optimize
If present and true, instructs the PNG writer to make the
output file as small as possible. This includes extra
processing in order to find optimal encoder settings.
compress_level
ZLIB compression level, a number between 0 and 9: 1 gives
best speed, 9 gives best compression, 0 gives no
compression at all. Default is 6. When optimize option is
True compress_level has no effect (it is set to 9 regardless
of a value passed).
And seeing it in action...
from PIL import Image
img = Image.open("sample.png")
img.save("optimized.png", optimize=True)
The resulting image I get is about 60K smaller than the original.
❯ ls -lh optimized.png sample.png
-rw-r--r-- 1 wkl staff 843K Aug 12 18:10 optimized.png
-rw-r--r-- 1 wkl staff 918K Aug 12 17:23 sample.png
JPEG File
Now, JPEG is a generationally-lossy image format - as you save it over and over, you will keep losing quality - it doesn't matter if your subsequent generations save it at even higher qualities than the previous ones, you've lost data already from the previous saves.
Note that the likely reason why you saw file sizes balloon if you used quality=100
is because libjpeg
/libjpeg-turbo
(which are the underlying libraries used by PIL for JPEG) do not do certain things when the quality is set that high, I think it doesn't do quantization which is an important step in determining how many bits are needed to compress.
Related Topics
Nested Ssh Using Python Paramiko
How to Create Nested Dict in Python
Add Custom CSS Styling to Model Form Django
How to Get Access of Individual Trees of a Xgboost Model in Python /R
Does Ruby Support Conditional Regular Expressions
Why Can't Python Find Shared Objects That Are in Directories in Sys.Path
Pythonic Way of Checking If a Condition Holds for Any Element of a List
Handling Backreferences to Capturing Groups in Re.Sub Replacement Pattern
How to Send an Email with Python
What Makes Sets Faster Than Lists
Django: Deploying an Application on Heroku with SQLite3 as the Database
Sqlalchemy: Print the Actual Query
Best Way to Set Entry Background Color in Python Gtk3 and Set Back to Default
Size Legend for Plotly Bubble Map/Chart
How to Import a JSON from a File on Cloud Storage to Bigquery
Dead Simple Example of Using Multiprocessing Queue, Pool and Locking
What Is the Perfect Counterpart in Python for "While Not Eof"