Pillow/PIL/ImagePalette.py

248 lines
6.5 KiB
Python
Raw Normal View History

2010-07-31 06:52:47 +04:00
#
# The Python Imaging Library.
# $Id$
#
# image palette object
#
# History:
# 1996-03-11 fl Rewritten.
# 1997-01-03 fl Up and running.
# 1997-08-23 fl Added load hack
# 2001-04-16 fl Fixed randint shadow bug in random()
#
# Copyright (c) 1997-2001 by Secret Labs AB
# Copyright (c) 1996-1997 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#
import array
import warnings
from PIL import ImageColor
2010-07-31 06:52:47 +04:00
2015-05-26 17:07:21 +03:00
class ImagePalette(object):
"Color palette for palette mapped images"
2010-07-31 06:52:47 +04:00
2014-07-15 19:38:10 +04:00
def __init__(self, mode="RGB", palette=None, size=0):
2010-07-31 06:52:47 +04:00
self.mode = mode
2014-07-15 19:38:10 +04:00
self.rawmode = None # if set, palette contains raw data
self.palette = palette or list(range(256))*len(self.mode)
2010-07-31 06:52:47 +04:00
self.colors = {}
self.dirty = None
2014-07-15 19:38:10 +04:00
if ((size == 0 and len(self.mode)*256 != len(self.palette)) or
(size != 0 and size != len(self.palette))):
raise ValueError("wrong palette size")
2010-07-31 06:52:47 +04:00
def copy(self):
new = ImagePalette()
new.mode = self.mode
new.rawmode = self.rawmode
if self.palette is not None:
new.palette = self.palette[:]
new.colors = self.colors.copy()
new.dirty = self.dirty
return new
2010-07-31 06:52:47 +04:00
def getdata(self):
"""
Get palette contents in format suitable # for the low-level
``im.putpalette`` primitive.
.. warning:: This method is experimental.
"""
2010-07-31 06:52:47 +04:00
if self.rawmode:
return self.rawmode, self.palette
return self.mode + ";L", self.tobytes()
2010-07-31 06:52:47 +04:00
def tobytes(self):
"""Convert palette to bytes.
.. warning:: This method is experimental.
"""
2010-07-31 06:52:47 +04:00
if self.rawmode:
raise ValueError("palette contains raw palette data")
if isinstance(self.palette, bytes):
2010-07-31 06:52:47 +04:00
return self.palette
arr = array.array("B", self.palette)
if hasattr(arr, 'tobytes'):
2014-07-15 19:38:10 +04:00
# py3k has a tobytes, tostring is deprecated.
return arr.tobytes()
return arr.tostring()
2010-07-31 06:52:47 +04:00
# Declare tostring as an alias for tobytes
tostring = tobytes
2010-07-31 06:52:47 +04:00
def getcolor(self, color):
"""Given an rgb tuple, allocate palette entry.
.. warning:: This method is experimental.
"""
2010-07-31 06:52:47 +04:00
if self.rawmode:
raise ValueError("palette contains raw palette data")
if isinstance(color, tuple):
2010-07-31 06:52:47 +04:00
try:
return self.colors[color]
except KeyError:
# allocate new color slot
if isinstance(self.palette, bytes):
self.palette = [int(x) for x in self.palette]
2010-07-31 06:52:47 +04:00
index = len(self.colors)
if index >= 256:
raise ValueError("cannot allocate more than 256 colors")
self.colors[color] = index
self.palette[index] = color[0]
self.palette[index+256] = color[1]
self.palette[index+512] = color[2]
self.dirty = 1
return index
else:
raise ValueError("unknown color specifier: %r" % color)
def save(self, fp):
"""Save palette to text file.
.. warning:: This method is experimental.
"""
2010-07-31 06:52:47 +04:00
if self.rawmode:
raise ValueError("palette contains raw palette data")
if isinstance(fp, str):
2010-07-31 06:52:47 +04:00
fp = open(fp, "w")
fp.write("# Palette\n")
fp.write("# Mode: %s\n" % self.mode)
for i in range(256):
fp.write("%d" % i)
for j in range(i*len(self.mode), (i+1)*len(self.mode)):
try:
fp.write(" %d" % self.palette[j])
except IndexError:
fp.write(" 0")
2010-07-31 06:52:47 +04:00
fp.write("\n")
fp.close()
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
# --------------------------------------------------------------------
# Internal
def raw(rawmode, data):
palette = ImagePalette()
palette.rawmode = rawmode
palette.palette = data
palette.dirty = 1
return palette
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
# --------------------------------------------------------------------
# Factories
def _make_linear_lut(black, white):
warnings.warn(
'_make_linear_lut() is deprecated. '
'Please call make_linear_lut() instead.',
DeprecationWarning,
stacklevel=2
)
return make_linear_lut(black, white)
def _make_gamma_lut(exp):
warnings.warn(
'_make_gamma_lut() is deprecated. '
'Please call make_gamma_lut() instead.',
DeprecationWarning,
stacklevel=2
)
return make_gamma_lut(exp)
def make_linear_lut(black, white):
2010-07-31 06:52:47 +04:00
lut = []
if black == 0:
for i in range(256):
lut.append(white*i//255)
2010-07-31 06:52:47 +04:00
else:
2014-07-15 19:38:10 +04:00
raise NotImplementedError # FIXME
2010-07-31 06:52:47 +04:00
return lut
2014-07-15 19:38:10 +04:00
2014-07-19 02:45:57 +04:00
def make_gamma_lut(exp):
2010-07-31 06:52:47 +04:00
lut = []
for i in range(256):
lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
return lut
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
def negative(mode="RGB"):
palette = list(range(256))
2010-07-31 06:52:47 +04:00
palette.reverse()
return ImagePalette(mode, palette * len(mode))
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
def random(mode="RGB"):
from random import randint
palette = []
for i in range(256*len(mode)):
palette.append(randint(0, 255))
return ImagePalette(mode, palette)
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
def sepia(white="#fff0c0"):
r, g, b = ImageColor.getrgb(white)
r = make_linear_lut(0, r)
g = make_linear_lut(0, g)
b = make_linear_lut(0, b)
2010-07-31 06:52:47 +04:00
return ImagePalette("RGB", r + g + b)
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
def wedge(mode="RGB"):
return ImagePalette(mode, list(range(256)) * len(mode))
2010-07-31 06:52:47 +04:00
2014-07-15 19:38:10 +04:00
2010-07-31 06:52:47 +04:00
def load(filename):
# FIXME: supports GIMP gradients only
fp = open(filename, "rb")
lut = None
if not lut:
try:
2013-03-07 20:20:28 +04:00
from PIL import GimpPaletteFile
2010-07-31 06:52:47 +04:00
fp.seek(0)
p = GimpPaletteFile.GimpPaletteFile(fp)
lut = p.getpalette()
except (SyntaxError, ValueError):
2014-07-15 19:38:10 +04:00
# import traceback
# traceback.print_exc()
2010-07-31 06:52:47 +04:00
pass
if not lut:
try:
2013-03-07 20:20:28 +04:00
from PIL import GimpGradientFile
2010-07-31 06:52:47 +04:00
fp.seek(0)
p = GimpGradientFile.GimpGradientFile(fp)
lut = p.getpalette()
except (SyntaxError, ValueError):
2014-07-15 19:38:10 +04:00
# import traceback
# traceback.print_exc()
2010-07-31 06:52:47 +04:00
pass
if not lut:
try:
2013-03-07 20:20:28 +04:00
from PIL import PaletteFile
2010-07-31 06:52:47 +04:00
fp.seek(0)
p = PaletteFile.PaletteFile(fp)
lut = p.getpalette()
except (SyntaxError, ValueError):
#import traceback
#traceback.print_exc()
2010-07-31 06:52:47 +04:00
pass
if not lut:
raise IOError("cannot load palette")
2010-07-31 06:52:47 +04:00
2014-07-15 19:38:10 +04:00
return lut # data, rawmode