Search code examples
pythonpython-imaging-librarypng

Pillow does not preseve PNG info like gamma?


I don't have an example image at this time, but essentially, if i encountered a situation where images loaded and then saved, without modification, changes brightness. I read a issue where this could be because the image uses CMYK mode, but the images open in RGB mode. (I am using PNG images, which again are frames extracted from a video using ffmpeg) After opening and then saving an image, it goes from 1.6 MB to 1.2 MB in size. Quick sample code:

from PIL import Image  # Version 7.1.2

img = Image.open('.\\temp\\original.png')
print(img2.mode) # RGB
img.save('.\\temp\\test.png') # This is darker than original

I found out the original carries this info, using the img.info attribute:

{'aspect': (1, 1), 'chromaticity': (0.3127, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06), 'gamma': 0.50994}

The saved images do not. Amazed Pillow doesn't actually save this info with new images, and i'm looking for a way to get around it. Another SO suggestion has not worked:

from PIL import Image

img = Image.open('1.png')
png_info = img.info
img.save('2.png', **png_info)

Per documentation, .save() doesn't seem to support adding this info, and i am looking for a way around it, ideally something that still let me convert images to RGB Pytorch tensors just as easily. (And back again.)

Update: Link to example image where this issue occurs: Opening and saving this will make it darker.

https://mega.nz/file/0AYwAQRJ#MrhtkDKN-EGj25eld2SrZO0GPrMDQlaz7rtVaQ-GtXs


Solution

  • I don't know why PIL/Pillow is failing/declining to preserve/save your gamma info, but you can maybe work around it with pngcheck and pngcrush.

    You can get the gAMA chunk with:

    pngcheck -v sonic.png | grep gAMA
    chunk gAMA at offset 0x00066, length 4: 0.50994
    

    And you can set it, to say 0.9, after PIL has lost it with:

    pngcrush -replace_gamma 0.9 INPUT.PNG OUTPUT.PNG