w00d
w00d

Reputation: 5596

PIL jpeg, how to preserve the pixel color

I have some experiments with JPEG, the doc said "100 completely disables the JPEG quantization stage."

However, I still got some pixel modification during saving. Here is my code:

import Image
red = [20,30,40,50,60,70];
img = Image.new("RGB", [1, len(red)], (255,255,255))
pix = img.load()

for x in range(0,len(red)):
    pix[0,x] = (red[x],255,255)

img.save('test.jpg',quality=100)

img = Image.open('test.jpg')
pix = img.load()

for x in range(0,len(red)):
    print pix[0,x][0],

I got unexpected output: 22 25 42 45 62 65 What should I do to preserve the pixel value ? Please note that I also tried with PHP using imagejpeg and It gives me the correct value when quality=100.

I can use png to preserve, but I want to know the reason behind this and if there is any option to avoid

Upvotes: 7

Views: 5408

Answers (3)

Gringo Suave
Gringo Suave

Reputation: 31940

Believe I've figured out how to keep the current color subsampling and other quality details:

from PIL import Image, JpegImagePlugin as JIP

img = Image.open(filename)
img.save(
    filename + '2.jpg',                 # copy
    format='JPEG',
    exif=img.info.get('exif'),          # keep EXIF info
    optimize=True,
    subsampling=JIP.get_sampling(img),  # keep color res
    qtables=img.quantization,           # keep quality
    # quality=-1,                       # keep
)

Per https://www.exiv2.org/tags.html I've found that the YCbCrSubSampling tag is not kept in EXIF in JPEG files:

In JPEG compressed data a JPEG marker is used instead of this tag.

This must be why there is another function in a seemingly out of the way place to to grab it.

See: https://stackoverflow.com/a/56675440/450917

How to keep XMP as well:

Resize image with Python and keep EXIF and XMP metadata

Upvotes: 3

Mark Ransom
Mark Ransom

Reputation: 308520

JPEG consists of many different steps, many of which introduce some loss. By using a sample image containing only red, you've probably run across the worst offender - downsampling or chroma subsampling. Half of the color information is thrown away because the eye is more sensitive to brightness changes than color changes.

Some JPEG encoders can be configured to turn off subsampling, including PIL and Pillow by setting subsampling=0. In any case it won't give you a completely lossless file since there are still other steps that introduce a loss.

Upvotes: 4

askewchan
askewchan

Reputation: 46578

JPEG will always carry risk of lossyness, see Is Jpeg lossless when quality is set to 100?.

Your best bet is to use another format, especially if your experiments are for science :) Even if you're forced to start with JPEG (which seems unlikely) you should immediately convert to a lossless format for any kind of analysis and modification.

If you really want to try lossless JPEG work with python you can try jpegtran, "the lossless jpeg image transformation software from the Independent Jpeg Group", but as @Mark notes, this won't get you very far.

By the way, quantization is used in lossy or lossless compression alike, so my guess is that

...100 completely disables the JPEG quantization stage.[1]

simply means that it's not compressed at all.

Upvotes: 4

Related Questions