reorganized gif optimize to work with palette parameter

This commit is contained in:
David Schmidt 2013-08-05 17:59:35 +02:00
parent b9ab3f5bf4
commit c9df9d0b23

View File

@ -343,70 +343,71 @@ def getheader(im, palette=None, info=None):
optimize = info and info.get("optimize", 0) optimize = info and info.get("optimize", 0)
# start of header # Header Block
# http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
header = [ header = [
b"GIF87a" + # magic b"GIF87a" + # signature + version
o16(im.size[0]) + # size o16(im.size[0]) + # canvas width
o16(im.size[1]) o16(im.size[1]) # canvas height
] ]
# if the user adds a palette, use it if im.mode == "P":
usedPaletteColors = None if palette and isinstance(palette, bytes):
sourcePalette = palette[:768]
if palette is not None and isinstance(palette, bytes):
paletteBytes = palette[:768]
else: else:
usedPaletteColors = [] sourcePalette = im.im.getpalette("RGB")[:768]
else: # L-mode
sourcePalette = bytearray([i//3 for i in range(768)])
usedPaletteColors = paletteBytes = None
if optimize: if optimize:
# minimize color palette if wanted usedPaletteColors = []
# check which colors are used
i = 0 i = 0
for count in im.histogram(): for count in im.histogram():
if count: if count:
usedPaletteColors.append(i) usedPaletteColors.append(i)
i += 1 i += 1
countUsedPaletteColors = len(usedPaletteColors) # create the new palette if not every color is used
if len(usedPaletteColors) < 256:
# create the global palette
if im.mode == "P":
# colour palette
if countUsedPaletteColors > 0 and countUsedPaletteColors < 256:
paletteBytes = b""; paletteBytes = b"";
if im.mode == "P":
# pick only the used colors from the palette # pick only the used colors from the palette
for i in usedPaletteColors: for i in usedPaletteColors:
paletteBytes += im.im.getpalette("RGB")[i*3:i*3+3] paletteBytes += sourcePalette[i*3:i*3+3]
else: else:
paletteBytes = im.im.getpalette("RGB")[:768]
else:
# greyscale
if countUsedPaletteColors > 0 and countUsedPaletteColors < 256:
paletteBytes = b"";
# add only the used grayscales to the palette # add only the used grayscales to the palette
for i in usedPaletteColors: for i in usedPaletteColors:
paletteBytes += o8(i)*3 paletteBytes += o8(i)*3
else :
paletteBytes = bytearray([i//3 for i in range(768)])
# TODO improve this, maybe add numpy support # TODO improve this, maybe add numpy support
# replace the palette color id of all pixel with the new id # replace the palette color id of all pixel with the new id
if countUsedPaletteColors > 0 and countUsedPaletteColors < 256:
imageBytes = bytearray(im.tobytes()) imageBytes = bytearray(im.tobytes())
for i in range(len(imageBytes)): for i in range(len(imageBytes)):
for newI in range(countUsedPaletteColors): for newI in range(len(usedPaletteColors)):
if imageBytes[i] == usedPaletteColors[newI]: if imageBytes[i] == usedPaletteColors[newI]:
imageBytes[i] = newI imageBytes[i] = newI
break break
im.frombytes(bytes(imageBytes)) im.frombytes(bytes(imageBytes))
if not paletteBytes:
paletteBytes = sourcePalette
# Logical Screen Descriptor
# calculate the palette size for the header # calculate the palette size for the header
import math import math
colorTableSize = int(math.ceil(math.log(len(paletteBytes)//3, 2)))-1 colorTableSize = int(math.ceil(math.log(len(paletteBytes)//3, 2)))-1
if colorTableSize < 0: colorTableSize = 0 if colorTableSize < 0: colorTableSize = 0
header.append(o8(colorTableSize + 128)) # size of global color table + global color table flag # size of global color table + global color table flag
header.append(o8(0) + o8(0)) # background + reserved/aspect header.append(o8(colorTableSize + 128))
# end of screen descriptor header # background + reserved/aspect
header.append(o8(0) + o8(0))
# end of Logical Screen Descriptor
# add the missing amount of bytes # add the missing amount of bytes
# the palette has to be 2<<n in size # the palette has to be 2<<n in size
@ -414,7 +415,7 @@ def getheader(im, palette=None, info=None):
if actualTargetSizeDiff > 0: if actualTargetSizeDiff > 0:
paletteBytes += o8(0) * 3 * actualTargetSizeDiff paletteBytes += o8(0) * 3 * actualTargetSizeDiff
# global color palette # Header + Logical Screen Descriptor + Global Color Table
header.append(paletteBytes) header.append(paletteBytes)
return header, usedPaletteColors return header, usedPaletteColors