185 lines
5.1 KiB
Python
185 lines
5.1 KiB
Python
|
#
|
||
|
# 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 Image, ImageColor
|
||
|
|
||
|
##
|
||
|
# Colour palette wrapper for palette mapped images.
|
||
|
|
||
|
class ImagePalette:
|
||
|
"Colour palette for palette mapped images"
|
||
|
|
||
|
def __init__(self, mode = "RGB", palette = None):
|
||
|
self.mode = mode
|
||
|
self.rawmode = None # if set, palette contains raw data
|
||
|
self.palette = palette or range(256)*len(self.mode)
|
||
|
self.colors = {}
|
||
|
self.dirty = None
|
||
|
if len(self.mode)*256 != len(self.palette):
|
||
|
raise ValueError, "wrong palette size"
|
||
|
|
||
|
def getdata(self):
|
||
|
# experimental: get palette contents in format suitable
|
||
|
# for the low-level im.putpalette primitive
|
||
|
if self.rawmode:
|
||
|
return self.rawmode, self.palette
|
||
|
return self.mode + ";L", self.tostring()
|
||
|
|
||
|
def tostring(self):
|
||
|
# experimental: convert palette to string
|
||
|
if self.rawmode:
|
||
|
raise ValueError("palette contains raw palette data")
|
||
|
if Image.isStringType(self.palette):
|
||
|
return self.palette
|
||
|
return array.array("B", self.palette).tostring()
|
||
|
|
||
|
def getcolor(self, color):
|
||
|
# experimental: given an rgb tuple, allocate palette entry
|
||
|
if self.rawmode:
|
||
|
raise ValueError("palette contains raw palette data")
|
||
|
if Image.isTupleType(color):
|
||
|
try:
|
||
|
return self.colors[color]
|
||
|
except KeyError:
|
||
|
# allocate new color slot
|
||
|
if Image.isStringType(self.palette):
|
||
|
self.palette = map(int, self.palette)
|
||
|
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):
|
||
|
# (experimental) save palette to text file
|
||
|
if self.rawmode:
|
||
|
raise ValueError("palette contains raw palette data")
|
||
|
if type(fp) == type(""):
|
||
|
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.palette), 256):
|
||
|
fp.write(" %d" % self.palette[j])
|
||
|
fp.write("\n")
|
||
|
fp.close()
|
||
|
|
||
|
# --------------------------------------------------------------------
|
||
|
# Internal
|
||
|
|
||
|
def raw(rawmode, data):
|
||
|
palette = ImagePalette()
|
||
|
palette.rawmode = rawmode
|
||
|
palette.palette = data
|
||
|
palette.dirty = 1
|
||
|
return palette
|
||
|
|
||
|
# --------------------------------------------------------------------
|
||
|
# Factories
|
||
|
|
||
|
def _make_linear_lut(black, white):
|
||
|
lut = []
|
||
|
if black == 0:
|
||
|
for i in range(256):
|
||
|
lut.append(white*i/255)
|
||
|
else:
|
||
|
raise NotImplementedError # FIXME
|
||
|
return lut
|
||
|
|
||
|
def _make_gamma_lut(exp, mode="RGB"):
|
||
|
lut = []
|
||
|
for i in range(256):
|
||
|
lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
|
||
|
return lut
|
||
|
|
||
|
def new(mode, data):
|
||
|
return Image.core.new_palette(mode, data)
|
||
|
|
||
|
def negative(mode="RGB"):
|
||
|
palette = range(256)
|
||
|
palette.reverse()
|
||
|
return ImagePalette(mode, palette * len(mode))
|
||
|
|
||
|
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)
|
||
|
|
||
|
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)
|
||
|
return ImagePalette("RGB", r + g + b)
|
||
|
|
||
|
def wedge(mode="RGB"):
|
||
|
return ImagePalette(mode, range(256) * len(mode))
|
||
|
|
||
|
def load(filename):
|
||
|
|
||
|
# FIXME: supports GIMP gradients only
|
||
|
|
||
|
fp = open(filename, "rb")
|
||
|
|
||
|
lut = None
|
||
|
|
||
|
if not lut:
|
||
|
try:
|
||
|
import GimpPaletteFile
|
||
|
fp.seek(0)
|
||
|
p = GimpPaletteFile.GimpPaletteFile(fp)
|
||
|
lut = p.getpalette()
|
||
|
except (SyntaxError, ValueError):
|
||
|
pass
|
||
|
|
||
|
if not lut:
|
||
|
try:
|
||
|
import GimpGradientFile
|
||
|
fp.seek(0)
|
||
|
p = GimpGradientFile.GimpGradientFile(fp)
|
||
|
lut = p.getpalette()
|
||
|
except (SyntaxError, ValueError):
|
||
|
pass
|
||
|
|
||
|
if not lut:
|
||
|
try:
|
||
|
import PaletteFile
|
||
|
fp.seek(0)
|
||
|
p = PaletteFile.PaletteFile(fp)
|
||
|
lut = p.getpalette()
|
||
|
except (SyntaxError, ValueError):
|
||
|
pass
|
||
|
|
||
|
if not lut:
|
||
|
raise IOError, "cannot load palette"
|
||
|
|
||
|
return lut # data, rawmode
|
||
|
|
||
|
|
||
|
# add some psuedocolour palettes as well
|