pythoncolor-spaceindexedcolor-profile

How to find Indexed Color mode PNGs in python


How do I get a list of all the Indexed Color mode PNGs that are present in a given folder that contains a lot of other files (which are all images, but they all have different Color Modes) using Python?

Previously tried code:

from PIL import Image
import os

path = 'logos/'

for x in os.listdir (path):
    if x.endswith(".png"):
        img = Image.open(path + x)
    cmode = str(img)
    P = 'mode=P' in cmode
    if P == True:
        print (x + " " + str(img))

Using this code, I got a list of images, some of which are Indexed Color mode, and the rest are RGB color mode (checking them through Photoshop) https://www.dropbox.com/s/vlvywqhcfrkk8kq/3978.png?dl=0 This is a link to an image that shows up as P through the script, but it is an RGB image in Photoshop. https://www.dropbox.com/s/x3qiuuhs3gv9bp9/6507.png?dl=0 This is a truly Indexed Color image, like the ones that I need to find.


Solution

  • You can use this:

    #!/usr/bin/env python3
    
    from PIL import Image
    from glob import glob
    
    # Start with empty list
    paletteImages = []
    
    # Iterate over all PNGs
    for f in glob("*.png"):
      # Open with PIL
      im = Image.open(f)
      # Append to list if palette image
      if 'P' in im.mode: paletteImages.append(f)
    
    print(paletteImages)
    

    More discussion on palette/indexed images here.

    Note that the above code will also find PaletteAlpha images, i.e. those with mode = 'PA', so change in to == if you don't want PaletteAlpha images.


    Or you can do it with ImageMagick in the Terminal more simply:

    identify -verbose  *png | egrep "Filename:|Type|png.IHDR.color_type"
    
    Filename: 3978.png
    Type: PaletteAlpha
    png:IHDR.color_type: 3 (Indexed)
    Filename: 6507.png
    Type: Palette
    png:IHDR.color_type: 3 (Indexed)
    

    Note that you can get exactly the same results from wand which is a ctypes binding to ImageMagick.


    Or you can use pngcheck:

    pngcheck *png   
                               
    OK: 3978.png (64x64, 8-bit palette+trns, non-interlaced, 33.1%).
    OK: 6507.png (64x64, 8-bit palette, non-interlaced, 56.3%).
    

    You could call this with a Python subprocess.run().


    Or you can use exiftool:

    exiftool *png | egrep "Color Type|File Name"   
    File Name                       : 3978.png
    Color Type                      : Palette
    File Name                       : 6507.png
    Color Type                      : Palette
    

    You can get the same results with the Python binding to exiftool. Example here.


    Or you can search for the PLTE, i.e. palette PNG chunk:

    grep PLTE *png     
    
    Binary file 3978.png matches
    Binary file 6507.png matches
    

    Or you can slurp the image with Python and search for string in the slurped file to get the same result:

    with open('3978.png', 'rb') as fd:
       data = fd.read()
       if b'PLTE' in data:
          print('PLTE was found')