Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.stsci.edu/spst/UnixTransition/doc/ImageH.py
Дата изменения: Fri Feb 28 14:46:08 2014
Дата индексирования: Sat Mar 1 12:22:47 2014
Кодировка:

Поисковые слова: annular solar eclipse
#
# The Python Imaging Library.
# $Id: ImageH.py,v 1.3 1998/05/28 20:14:52 friedric Exp friedric $
#
# the Image class wrapper
#
# history:
# 95-09-09 fl Created
# 96-03-11 fl PIL release 0.0
# 96-04-30 fl PIL release 0.1b1
# 96-05-27 fl PIL release 0.1b2
# 96-10-04 fl PIL release 0.2a1
# 96-11-04 fl PIL release 0.2b1
# 96-12-08 fl PIL release 0.2b2
# 96-12-16 fl PIL release 0.2b3
# 97-01-14 fl PIL release 0.2b4
# 97-06-02 fl PIL release 0.3a1
# 97-08-27 fl PIL release 0.3a2
# 98-02-02 fl PIL release 0.3a3
# 98-03-09 fl PIL release 0.3b1
#
# Copyright (c) Secret Labs AB 1997-98.
# Copyright (c) Fredrik Lundh 1995-97.
#
# See the README file for information on usage and redistribution.
#

VERSION = "0.3a3"

class _imaging_not_installed:
def __getattr__(self, id):
raise ImportError, "The _imaging C module is not installed"

try:
# If the _imaging C module is not present, you can only use the
# "open" function to identify files. Most other operations will
# fail. Note that other modules should not refer to _imaging
# directly; import Image and use the core variable instead.
import PIL._imaging as _imaging
core = _imaging
del _imaging
except ImportError:
core = _imaging_not_installed()

import ImagePaletteH
import os, string

# type stuff
from types import IntType, StringType, TupleType, ListType, FloatType, LongType
isStringType = lambda t: type(t) == StringType
isTupleType = lambda t: type(t) == TupleType
isImageType = lambda t: hasattr(t, "im")
#from operator import isNumberType, isSequenceType # not in JPython 1.0.3
def isNumberType(t):
type(t) in (IntType, FloatType, LongType)

def isSequenceType(t):
type(t) in (TupleType, ListType, StringType)

#
# Debug level

DEBUG = 0

#
# Constants (defined in _imagingmodule.c)

# transpose
FLIP_LEFT_RIGHT = 0
FLIP_TOP_BOTTOM = 1
ROTATE_90 = 2
ROTATE_180 = 3
ROTATE_270 = 4

# transforms
AFFINE = 0
EXTENT = 1
PERSPECTIVE = 2 # Not yet implemented

# resampling
NEAREST = 0
ANTIALIAS = 1

# categories
NORMAL = 0
SEQUENCE = 1
CONTAINER = 2

#
# Registries

ID = []
OPEN = {}
MIME = {}
SAVE = {}
EXTENSION = {}

#
# Helpers

_initialized = 0

def preinit():
"Load standard file format drivers."

global _initialized
if _initialized >= 1:
return

for m in ["BmpImagePlugin", "GifImagePluginH", "JpegImagePluginH",
"PpmImagePlugin", "TiffImagePlugin"]:
try:
__import__(m)
except ImportError:
pass # ignore missing driver for now

_initialized = 1

def init():
"Load all file format drivers."

global _initialized
if _initialized >= 2:
return

import os, sys

# only check directories (including current, if present in the path)
for path in filter(os.path.isdir, sys.path):
for file in os.listdir(path):
if file[-15:] == "ImagePluginH.py":
p, f = os.path.split(file)
f, e = os.path.splitext(f)
try:
sys.path.insert(0, path)
try:
__import__(f)
finally:
del sys.path[0]
except ImportError:
if DEBUG:
print "Image: failed to import",
print f, ":", sys.exc_value

if OPEN or SAVE:
_initialized = 2


# --------------------------------------------------------------------
# Codec factories (used by tostring/fromstring and ImageFile.load)

def _getdecoder(d, e, a, ac = ()):

# tweak arguments
if a == None:
a = ()
elif type(a) != TupleType:
a = (a,)

try:
# get decoder
decoder = getattr(core, d + "_decoder")
return apply(decoder, a + ac)
except AttributeError:
raise IOError, "decoder %s not available" % d

def _getencoder(mode, encoder_name, args, extra = ()):

# tweak arguments
if args == None:
args = ()
elif type(args) != TupleType:
args = (args,)

try:
# get encoder
encoder = getattr(core, encoder_name + "_encoder")
return apply(encoder, (mode,) + args + extra)
except AttributeError:
raise IOError, "encoder %s not available" % encoder_name


# --------------------------------------------------------------------
# Simple expression analyzer

class _E:
def __init__(self, data): self.data = data
def __coerce__(self, other): return self, _E(other)
def __add__(self, other): return _E((self.data, "__add__", other.data))
def __mul__(self, other): return _E((self.data, "__mul__", other.data))

def _getscaleoffset(expr):
stub = ["stub"]
data = expr(_E(stub)).data
try:
(a, b, c) = data # simplified syntax
if (a is stub and b == "__mul__" and isNumberType(c)):
return c, 0.0
if (a is stub and b == "__add__" and isNumberType(c)):
return 1.0, c
except TypeError: pass
try:
((a, b, c), d, e) = data # full syntax
if (a is stub and b == "__mul__" and isNumberType(c) and
d == "__add__" and isNumberType(e)):
return c, e
except TypeError: pass
raise ValueError, "illegal expression"


# --------------------------------------------------------------------
# Implementation wrapper

import os

class Image:

format = None
format_description = None

def __init__(self):
self.im = None
self.mode = ""
self.size = (0,0)
self.palette = None
self.info = {}
self.category = NORMAL

def __setattr__(self, id, value):
if id == "palette":
pass # print "set", id, value
self.__dict__[id] = value

def _makeself(self, im):
new = Image()
new.im = im
new.mode = im.mode
new.size = im.size
new.palette = self.palette
new.info = self.info
return new

def _dump(self, file = None):
import tempfile
if not file:
file = tempfile.mktemp()
self.load()
self.im.save_ppm(file)
return file

def tostring(self, encoder_name = "raw", *args):
"Return image as a binary string"

# may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]):
args = args[0]

# compatibility mode
if encoder_name == "raw" and args == ():
mode = self.mode
if mode == "RGB":
mode = "RGBX"
args = (mode, 0, -1)
else:
mode = self.mode

self.load()

# unpack data
e = _getencoder(mode, encoder_name, args)
e.setimage(self.im)

data = []
while 1:
l, s, d = e.encode(65536)
data.append(d)
if s:
break
if s < 0:
raise RuntimeError, "encoder error %d in tostring" % s

return string.join(data, "")

def tobitmap(self, name = "image"):
"Return image as an XBM bitmap"

self.load()
if self.mode != "1":
raise ValueError, "not a bitmap"
data = self.tostring("xbm")
return string.join(["#define %s_width %d\n" % (name, self.size[0]),
"#define %s_height %d\n"% (name, self.size[1]),
"static char %s_bits[] = {\n" % name, data, "};"], "")

def fromstring(self, data, decoder = "raw", *args):
"Load data to image from binary string"

# may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]):
args = args[0]

# compatibility mode
if decoder == "raw" and args == ():
mode = self.mode
if mode == "RGB":
mode = "RGBX"
args = (mode, 0, -1)

# unpack data
d = _getdecoder(decoder, None, args)
d.setimage(self.im)
s = d.decode(data)

if s != (-1, 0):
raise ValueError, "cannot decode image data"

def load(self):
if self.im and self.palette and self.palette.rawmode:
self.im.putpalette(self.palette.rawmode, self.palette.data)
self.palette.mode = "RGB"
self.palette.rawmode = None
if self.info.has_key("transparency"):
self.im.putpalettealpha(self.info["transparency"], 0)
self.palette.mode = "RGBA"

#
# function wrappers

def convert(self, mode = None, data = None):
"Convert to other pixel format"

if not mode:
if self.mode == "P":
mode = self.palette.mode
else:
return self.copy()
self.load()
if data:
if mode in ["L", "RGB"]:
im = self.im.convert_matrix(mode, data)
elif mode == "P":
im = self.im.convert(mode) # FIXME
else:
im = self.im.convert(mode)
return self._makeself(im)

def copy(self):
"Copy raster data"

self.load()
im = self.im.copy()
return self._makeself(im)

def crop(self, box = None):
"Crop region from image"

self.load()
if box == None:
return self.copy()

# delayed operation
return _ImageCrop(self, box)

def draft(self, mode, size):
"Configure image decoder"

pass

def filter(self, kernel):
"Apply environment filter to image"

self.load()
id = kernel.id
if len(self.mode) == 1:
return self._makeself(self.im.filter(id))
# fix to handle multiband images since _imaging doesn't
ims = []
for c in range(self.im.bands):
ims.append(self._makeself(self.im.getband(c).filter(id)))
return merge(self.mode, ims)

def getbbox(self):
"Get bounding box of actual data (non-zero pixels) in image"

self.load()
return self.im.getbbox()

def getdata(self, band = None):
"Get image data as sequence object."

self.load()
if band != None:
return self.im.getband(band)
return self.im # could be misused

def getpixel(self, (x, y)):
"Get pixel value"

self.load()
if 0 <= x < self.size[0] and 0 <= y <= self.size[1]:
return self.im[int(x + y * self.size[0])]
raise IndexError

def getprojection(self):
"Get projection to x and y axes"

self.load()
x, y = self.im.getprojection()
return map(ord, x), map(ord, y)

def histogram(self, mask = None):
"Take histogram of image"

self.load()
if mask:
mask.load()
return self.im.histogram(mask.im)
return self.im.histogram()

def offset(self, xoffset, yoffset = None):
"Offset image in horizontal and/or vertical direction"

if yoffset == None:
yoffset = xoffset
self.load()
return self._makeself(self.im.offset(xoffset, yoffset))

def paste(self, im, box = None, mask = None):
"Paste other image into region"

if box == None:
# all of image
box = (0, 0) + self.size

if not isImageType(im):
if len(box) == 2:
box = box + self.size
im = new(self.mode, (box[2]-box[0], box[3]-box[1]), im)

elif len(box) == 2:
# lower left corner given
box = box + (box[0]+im.size[0], box[1]+im.size[1])

im.load()
self.load()

# fix to handle conversion when pasting
if self.mode != im.mode:
im = im.convert(self.mode)

if mask:
mask.load()
self.im.paste(im.im, box, mask.im)
else:
self.im.paste(im.im, box)

def point(self, lut, mode = None):
"Map image through lookup table"

if self.mode == "F":
# floating point; lut must be a valid expression
scale, offset = _getscaleoffset(lut)
self.load()
im = self.im.point_transform(scale, offset);
else:
# integer image; use lut and mode
if not isSequenceType(lut):
# if it isn't a list, it should be a function
lut = map(lut, range(256)) * len(self.mode)
self.load()
im = self.im.point(lut, mode)

return self._makeself(im)

def putalpha(self, im):
"Set alpha layer"

if self.mode != "RGBA" or im.mode not in ["1", "L"]:
raise ValueError, "illegal image mode"

im.load()
self.load()

if im.mode == "1":
im = im.convert("L")

self.im.putband(im.im, 3)

def putdata(self, data, scale = 1.0, offset = 0.0):
"Put data from a sequence object into an image."

self.load() # hmm...
self.im.putdata(data, scale, offset)

def putpalette(self, data, rawmode = "RGB"):
"Put palette data into an image."

if self.mode not in ("L", "P"):
raise ValueError, "illegal image mode"
if type(data) != StringType:
data = string.join(map(chr, data), "")
self.mode = "P"
self.palette = ImagePaletteH.raw(rawmode, data)
self.palette.mode = "RGB"

def resize(self, size, resample = NEAREST):
"Resize image"

if resample not in [NEAREST, ANTIALIAS]:
raise ValueError, "unknown resampling method"

self.load()
if resample == NEAREST:
im = self.im.resize(size)
else:
im = self.im.resize_antialias(size)
return self._makeself(im)

def rotate(self, angle, resample = NEAREST):
"Rotate image. Angle given as degrees counter-clockwise."

if resample != NEAREST:
raise ValueError, "unknown resampling method"

self.load()
im = self.im.rotate(angle)
return self._makeself(im)

def save(self, fp, format = None, **params):
"Save image to file or stream"

if isStringType(fp):
import __builtin__
filename = fp
fp = __builtin__.open(fp, "wb")
close = 1
else:
filename = ""
close = 0

self.encoderinfo = params
self.encoderconfig = ()

self.load()

preinit()

ext = string.lower(os.path.splitext(filename)[1])

try:

if not format:
format = EXTENSION[ext]

SAVE[string.upper(format)](self, fp, filename)

except KeyError, v:

init()

if not format:
format = EXTENSION[ext]

SAVE[string.upper(format)](self, fp, filename)

if close:
fp.close()

def seek(self, frame):
"Seek to given frame in sequence file"

if frame != 0:
raise EOFError

def show(self, title = None):
"Display image (for debug purposes only)"

try:
import ImageTk
ImageTk._show(self, title)
# note: caller must enter mainloop
except:
_showxv(self, title)

def split(self):
"Split image into bands"

ims = []
self.load()
for i in range(self.im.bands):
ims.append(self._makeself(self.im.getband(i)))
return tuple(ims)

def tell(self):
"Return current frame number"

return 0

def thumbnail(self, size):
"Create thumbnail representation (modifies image in place)"

# preserve aspect ratio
x, y = self.size
if x > size[0]: y = y * size[0] / x; x = size[0]
if y > size[1]: x = x * size[1] / y; y = size[1]
size = x, y

if size == self.size:
return

self.draft(None, size)

im = self.resize(size)

self.im = im.im
self.mode = im.mode
self.size = size

def transform(self, size, method, data, resample = NEAREST):
"Transform image"

if method == EXTENT:
x0, y0, x1, y1 = data
xs = float(x1 - x0) / size[0]
ys = float(y1 - y0) / size[1]
data = (xs, 0, x0 + xs/2, 0, ys, y0 + ys/2)
elif method != AFFINE:
raise ValueError, "unknown transformation method"
if resample != NEAREST:
raise ValueError, "unknown resampling method"

self.load()
im = self.im.transform(size, data)
return self._makeself(im)

def transpose(self, method):
"Transpose image (flip or rotate in 90 degree steps)"

self.load()
im = self.im.transpose(method)
return self._makeself(im)


# --------------------------------------------------------------------
# Delayed operations

class _ImageCrop(Image):

def __init__(self, im, box):

Image.__init__(self)

self.mode = im.mode
self.size = box[2]-box[0], box[3]-box[1]

self.__crop = box

self.im = im.im

def load(self):

# delayed evaluation of crop operation

if self.__crop is None:
return

# FIXME: the C implementation of crop is broken, so we
# implement it by pasting into empty image instead.

# im = self.im.__crop(self.__crop)

im = core.new(self.mode, self.size)

im.paste(self.im, (-self.__crop[0], -self.__crop[1],
self.im.size[0]-self.__crop[0],
self.im.size[1]-self.__crop[1]))

if self.mode == "P":
im.putpalette("RGB", self.im.getpalette("RGB", "RGB"))

self.im = im

self.__crop = None


# --------------------------------------------------------------------
# Factories

#
# Debugging

def _wedge():
"Create greyscale wedge (for debugging only)"

return Image()._makeself(core.wedge("L"))

#
# Create/open images.

def new(mode, size, color = 0):
"Create a new image"

if color == None:
# don't initialize
return Image()._makeself(core.new(mode, size))

if isTupleType(color):
# convert colour tuple to integer value (0xAABBGGRR)
if len(color) == 3:
color = color[0] + (color[1]<<8) + (color[2]<<16)
elif len(color) == 4:
color = color[0] + (color[1]<<8) + (color[2]<<16) + (color[3]<<24)
else:
color = color[0]

return Image()._makeself(core.fill(mode, size, color))

def fromstring(mode, size, data, decoder = "raw", *args):
"Load image from string"

# may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]):
args = args[0]

if decoder == "raw" and args == ():
args = mode

im = new(mode, size)
im.fromstring(data, decoder, args)
return im

def open(fp, mode = "r"):
"Open an image file, without loading the raster data"

if mode != "r":
raise ValueError, "bad mode"

if isStringType(fp):
import __builtin__
filename = fp
fp = __builtin__.open(fp, "rb")
else:
filename = ""

prefix = fp.read(16)

preinit()

for i in ID:
try:
factory, accept = OPEN[i]
if not accept or accept(prefix):
fp.seek(0)
return factory(fp, filename)
except SyntaxError:
pass

init()

for i in ID:
try:
factory, accept = OPEN[i]
if not accept or accept(prefix):
fp.seek(0)
return factory(fp, filename)
except SyntaxError:
pass

raise IOError, "cannot identify image file"

#
# Image processing.

def blend(im1, im2, alpha):
"Interpolate between images."

if alpha == 0.0:
return im1
elif alpha == 1.0:
return im2
return Image()._makeself(core.blend(im1.im, im2.im, alpha))

def composite(image1, image2, mask):
"Create composite image by blending images using a transparency mask"

image = image2.copy()
image.paste(image1, None, mask)
return image

def eval(image, *args):
"Evaluate image expression"

return image.point(args[0])

def merge(mode, bands):
"Merge a set of single band images into a new multiband image."

if len(mode) != len(bands) or "*" in mode:
raise ValueError, "wrong number of bands"
for im in bands[1:]:
if len(im.mode) != 1 or im.size != bands[0].size:
raise ValueError, "wrong number of bands"
im = core.new(mode, bands[0].size)
for i in range(len(mode)):
bands[i].load()
im.putband(bands[i].im, i)
return Image()._makeself(im)


# --------------------------------------------------------------------
# Plugin registry

def register_open(id, factory, accept = None):
id = string.upper(id)
ID.append(id)
OPEN[id] = factory, accept

def register_mime(id, mimetype):
MIME[string.upper(id)] = mimetype

def register_save(id, driver):
SAVE[string.upper(id)] = driver

def register_extension(id, extension):
EXTENSION[string.lower(extension)] = string.upper(id)


# --------------------------------------------------------------------
# Unix display support

def _showxv(self, title = None):

if self.mode == "P":
file = self.convert("RGB")._dump()
else:
file = self._dump()

if title:
opt = "-name \"%s\"" % title
else:
opt = ""

os.system("(xv %s %s; rm -f %s)&" % (opt, file, file))