PIL(pillow)のインデックスカラーのあれこれ

PIL(pillow)のインデックスカラーのあれこれ

サンプルのJpegデータを読み込む

from PIL import Image, ImageDraw, ImageFont
imo = Image.open('jpeg/IMG_2952x.jpg')
print("mode = ",imo.mode)
print("size = ",imo.size)
mode =  RGB
size =  (640, 480)

jpeg画像フルカラーからパレットカラー(256色)に減色

im256 = imo.quantize() #減色 index color変換
print("mode = ",im256.mode)
print("size = ",im256.size)
im256.palette.save('palette.dat')
im256
mode =  P
size =  (640, 480)

Markdown記述だが、4スペースCODE識別の時は、後方のイメージが変換できなかったが ```記述に変更したら、画像が読み込めるようになった。単純にBUGかな?


f:id:chiyoh:20190503004617p:plain


もちろん、256色モードがあるTIFFとGIFに変換もできる

im256.save('im256.tif')
im256.save('im256.gif')

TIFFデータに変換したデータを読み込み、各データを見ていく PILライブラリのカラーパレットとTIFFのTAGに入っているパレットformatが違うので注意

from PIL import Image, ImageDraw, ImageFont
im256_tiff = Image.open('im256.tif')
im256_tiff
print("mode = ",im256_tiff.mode) # P
print("size = ",im256_tiff.size) # P
print("getbands = ",im256_tiff.getbands()) # ('P',)
print("getpixel(0,0) = ",im256_tiff.getpixel((0,0))) # 2 index 値
#print("getpalette = ",im256_tiff.getpalette()) # 2 index 値
palette = im256_tiff.getpalette()
i=0
print("colorpalette[0]= (",palette[i*3+0],palette[i*3+1],palette[i*3+2],")")
i=2
print("colorpalette[2]= (",palette[i*3+0],palette[i*3+1],palette[i*3+2],")")
i=32
print("colorpalette[32]= (",palette[i*3+0],palette[i*3+1],palette[i*3+2],")")
i=255
print("colorpalette[255]= (",palette[i*3+0],palette[i*3+1],palette[i*3+2],")")


print("TAG data:")
print("ImageWidth = " , im256_tiff.tag_v2[256]) # 8
print("ImageLength = " , im256_tiff.tag_v2[257]) # 8
print("BitsPerSample = " , im256_tiff.tag_v2[258]) # 8
# color map は、2 ** BitsPerSampleなので 256、RGB=3なので3*256データ
# データ長はshortで16bit 0~65535、(0,0,0)~(65535,65535,65535)
# しかし現在のRGBカラーは~(255,255,255)までで256で割らないと同じ値にならない
# また、R0~R256,G0~G255,B0~B255の順に並んでいるのでgetpellteとは違うフォーマット
print(type(im256_tiff.tag_v2[320][0]),len(im256_tiff.tag_v2[320])) # int
tag_palette = im256_tiff.tag_v2[320]
i=0
print("colorpalette[0]= (",tag_palette[0+i]/256,tag_palette[256+i]/256,tag_palette[512+i]/256,")")
i=32
print("colorpalette[32]= (",tag_palette[0+i]/256,tag_palette[256+i]/256,tag_palette[512+i]/256,")")
i=255
print("colorpalette[255]= (",tag_palette[0+i]/256,tag_palette[256+i]/256,tag_palette[512+i]/256,")")
mode =  P
size =  (640, 480)
getbands =  ('P',)
getpixel(0,0) =  2
colorpalette[0]= ( 253 253 253 )
colorpalette[2]= ( 249 249 250 )
colorpalette[32]= ( 228 230 228 )
colorpalette[255]= ( 4 4 7 )
TAG data:
ImageWidth =  640
ImageLength =  480
BitsPerSample =  (8,)
<class 'int'> 768
colorpalette[0]= ( 253.0 253.0 253.0 )
colorpalette[32]= ( 228.0 230.0 228.0 )
colorpalette[255]= ( 4.0 4.0 7.0 )

実際のパレットマップはこんな感じ

# -*- coding: utf-8 -*-
from PIL import Image, ImageDraw, ImageFont

def draw_pcolor_map(pcm):

    row,col,c_dx,c_dy,s_dx,y_osf = 32,8,16,16,16*8,24

    im = Image.new("RGB", (col*(c_dx+s_dx), c_dy*row+y_osf),color=(255,255,255))
    font_ttf = "C:/Windows/Fonts/msgothic.ttc" #MS ゴシック 他のOSの場合は適当にfont ファイルに変える
    draw = ImageDraw.Draw(im)

    draw.font = ImageFont.truetype(font_ttf, 24) # font size
    draw.text([0,0], "Index color map",(0,0,0))

    draw.font = ImageFont.truetype(font_ttf, 14) # font size

    for x in range(0,col):
        for num in range(0,row):
            # color box
            ix = row*x+num
            pcolor = (pcm[ix*3],pcm[ix*3+1],pcm[ix*3+2])
            draw.rectangle([(x*(c_dx+s_dx)+1,num*c_dy+1+y_osf),
                            (x*(c_dx+s_dx)+c_dx-1,(num+1)*c_dy-1-1+y_osf)],
                           outline=(0,0,0),
                           fill=pcolor)
            # number
            str_color = '{0:>3}:({1:>3},{2:>3},{3:>3})'.format(ix,pcolor[0],pcolor[1],pcolor[2]) 
            #print(str_color) # debug
            draw.text([x*(c_dx+s_dx)+c_dx+4,num*c_dy+y_osf], str_color,(0,0,0))

    return im

if __name__ == '__main__' :
    imo = Image.open('jpeg/IMG_2952x.jpg')
    im256 = imo.quantize() #減色 index color変換
    pcm = im256.getpalette()
    im = draw_pcolor_map(pcm)
    im.show()
pcm = im256.getpalette()
im = draw_pcolor_map(pcm)
im

f:id:chiyoh:20190503004624p:plain