Convert image to specific palette using PIL without dithering

后端 未结 2 1491
难免孤独
难免孤独 2020-12-10 06:06

I am trying to convert an RGB image in PNG format to use a specific indexed palette using the Pillow library (Python Image Library, PIL). But I want to convert using the \"r

相关标签:
2条回答
  • 2020-12-10 06:23

    I took all these and made it faster, added notes for you to understand & converted to pillow instead of pil. Basically.

    import sys
    import PIL
    from PIL import Image
    
    def quantizetopalette(silf, palette, dither=False):
        """Convert an RGB or L mode image to use a given P image's palette."""
    
        silf.load()
    
        # use palette from reference image made below
        palette.load()
        im = silf.im.convert("P", 0, palette.im)
        # the 0 above means turn OFF dithering making solid colors
        return silf._new(im)
    
    if __name__ == "__main__":
        import sys, os
    
    for imgfn in sys.argv[1:]:
        palettedata = [ 0, 0, 0, 255, 0, 0, 255, 255, 0, 0, 255, 0, 255, 255, 255,85,255,85, 255,85,85, 255,255,85] 
    
    #   palettedata = [ 0, 0, 0, 0,170,0, 170,0,0, 170,85,0,] # pallet 0 dark
    #   palettedata = [ 0, 0, 0, 85,255,85, 255,85,85, 255,255,85]  # pallet 0 light
    
    #   palettedata = [ 0, 0, 0, 85,255,255, 255,85,255, 255,255,255,]  #pallete 1 light
    #   palettedata = [ 0, 0, 0, 0,170,170, 170,0,170, 170,170,170,] #pallete 1 dark
    #   palettedata = [ 0,0,170, 0,170,170, 170,0,170, 170,170,170,] #pallete 1 dark sp
    
    #   palettedata = [ 0, 0, 0, 0,170,170, 170,0,0, 170,170,170,] # pallet 3 dark
    #   palettedata = [ 0, 0, 0, 85,255,255, 255,85,85, 255,255,255,] # pallet 3 light
    
    #  grey  85,85,85) blue (85,85,255) green (85,255,85) cyan (85,255,255) lightred 255,85,85 magenta (255,85,255)  yellow (255,255,85) 
    # black 0, 0, 0,  blue (0,0,170) darkred 170,0,0 green (0,170,0)  cyan (0,170,170)magenta (170,0,170) brown(170,85,0) light grey (170,170,170) 
    #  
    # below is the meat we make an image and assign it a palette
    # after which it's used to quantize the input image, then that is saved 
        palimage = Image.new('P', (16, 16))
        palimage.putpalette(palettedata *32)
        oldimage = Image.open(sys.argv[1])
        oldimage = oldimage.convert("RGB")
        newimage = quantizetopalette(oldimage, palimage, dither=False)
        dirname, filename= os.path.split(imgfn)
        name, ext= os.path.splitext(filename)
        newpathname= os.path.join(dirname, "cga-%s.png" % name)
        newimage.save(newpathname)
    
    #   palimage.putpalette(palettedata *64)  64 times 4 colors on the 256 index 4 times, == 256 colors, we made a 256 color pallet.
    
    0 讨论(0)
  • 2020-12-10 06:47

    The parts of PIL implemented in C are in the PIL._imaging module, also available as Image.core after you from PIL import Image. Current versions of Pillow give every PIL.Image.Image instance a member named im which is an instance of ImagingCore, a class defined within PIL._imaging. You can list its methods with help(oldimage.im), but the methods themselves are undocumented from within Python.

    The convert method of ImagingCore objects is implemented in _imaging.c. It takes one to three arguments and creates a new ImagingCore object (called Imaging_Type within _imaging.c).

    • mode (required): mode string (e.g. "P")
    • dither (optional, default 0): PIL passes 0 or 1
    • paletteimage (optional): An ImagingCore with a palette

    The problem I was facing is that quantize() in dist-packages/PIL/Image.py forces the dither argument to 1. So I pulled a copy of the quantize() method out and changed that. This may not work in future versions of Pillow, but if not, they're likely to implement the "extended quantizer interface in a later version" that a comment in quantize() promises.

    #!/usr/bin/env python3
    from PIL import Image
    
    def quantizetopalette(silf, palette, dither=False):
        """Convert an RGB or L mode image to use a given P image's palette."""
    
        silf.load()
    
        # use palette from reference image
        palette.load()
        if palette.mode != "P":
            raise ValueError("bad mode for palette image")
        if silf.mode != "RGB" and silf.mode != "L":
            raise ValueError(
                "only RGB or L mode images can be quantized to a palette"
                )
        im = silf.im.convert("P", 1 if dither else 0, palette.im)
        # the 0 above means turn OFF dithering
    
        # Later versions of Pillow (4.x) rename _makeself to _new
        try:
            return silf._new(im)
        except AttributeError:
            return silf._makeself(im)
    
    palettedata = [0, 0, 0, 102, 102, 102, 176, 176, 176, 255, 255, 255]
    palimage = Image.new('P', (16, 16))
    palimage.putpalette(palettedata * 64)
    oldimage = Image.open("School_scrollable1.png")
    newimage = quantizetopalette(oldimage, palimage, dither=False)
    newimage.show()
    
    0 讨论(0)
提交回复
热议问题