You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.2 KiB
153 lines
4.2 KiB
8 years ago
|
"""
|
||
|
This module is part of the 'blup' package and contains the definition of a
|
||
|
basic Frame class.
|
||
|
|
||
|
"""
|
||
|
|
||
|
class FrameDimension(object):
|
||
|
""" This class serves as container for the dimensions of a frame. """
|
||
|
|
||
|
def __init__(self, width=18, height=8, depth=2, channels=1):
|
||
|
self.width = width
|
||
|
self.height = height
|
||
|
self.depth = depth
|
||
|
self.channels = channels
|
||
|
|
||
|
def size(self):
|
||
|
return (self.width, self.height)
|
||
|
|
||
|
def depth(self):
|
||
|
return self.depth
|
||
|
|
||
|
def channels(self):
|
||
|
return self.channels
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
if ( self.width == other.width and self.height == other.height and
|
||
|
self.depth == other.depth and self.channels == other.channels ):
|
||
|
return True
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
def __ne__(self, other):
|
||
|
return not self.__eq__(other)
|
||
|
|
||
|
def __str__(self):
|
||
|
return "(%d, %d, %d, %d)" % (self.width, self.height, self.depth,
|
||
|
self.channels)
|
||
|
|
||
|
class Frame(object):
|
||
|
""" This class describes a single frame. """
|
||
|
|
||
|
def __init__(self, dimension):
|
||
|
"""
|
||
|
Initialize the frame with the given dimensions. The 'depth' parameter
|
||
|
describes, how many different values a single pixel can have.
|
||
|
|
||
|
"""
|
||
|
self.__dimension = dimension
|
||
|
width = dimension.width
|
||
|
height = dimension.height
|
||
|
if dimension.channels == 1:
|
||
|
self.__pixels = [ [ 0 ] * width for i in range(height) ]
|
||
|
else:
|
||
|
self.__pixels = [ [ tuple([0]*dimension.channels) ] * width for i in range(height) ]
|
||
|
|
||
|
@property
|
||
|
def dimension(self):
|
||
|
return self.__dimension
|
||
|
|
||
|
@property
|
||
|
def size(self):
|
||
|
return (self.__dimension.width, self.__dimension.height)
|
||
|
@property
|
||
|
def depth(self):
|
||
|
return self.__dimension.depth
|
||
|
@property
|
||
|
def channels(self):
|
||
|
return self.__dimension.channels
|
||
|
|
||
|
@property
|
||
|
def pixels(self):
|
||
|
return self.__pixels
|
||
|
|
||
|
@pixels.setter
|
||
|
def pixels(self, pixels):
|
||
|
if len(pixels) != self.__dimension.height:
|
||
|
raise ValueError('not enough rows given')
|
||
|
widths = set(map(lambda r: len(r), pixels))
|
||
|
if len(widths) != 1:
|
||
|
raise ValueError('rows are not of the same length')
|
||
|
if widths.pop() != self.__dimension.width:
|
||
|
raise ValueError('rows are too short')
|
||
|
|
||
|
# TODO check depth
|
||
|
# TODO check number of channels
|
||
|
|
||
|
self.__pixels = pixels
|
||
|
|
||
|
def transform(self, depth):
|
||
|
""" Transform the frame to a frame with a different depth. """
|
||
|
oldmaxval = self.__dimension.depth - 1
|
||
|
newmaxval = depth - 1
|
||
|
factor = (newmaxval*1.0) / (oldmaxval*1.0)
|
||
|
newdim = FrameDimension(self.__dimension.width,
|
||
|
self.__dimension.height,
|
||
|
depth,
|
||
|
self.__dimension.channels)
|
||
|
newframe = Frame(newdim)
|
||
|
|
||
|
transformfkt = lambda p: int(round(p * factor))
|
||
|
for y in range(self.__dimension.height):
|
||
|
if self.__dimension.channels == 1:
|
||
|
newframe.__pixels[y] = map(transformfkt, self.__pixels[y])
|
||
|
else:
|
||
|
for x in range(self.__dimension.width):
|
||
|
newframe.__pixels[y][x] = tuple(map(transformfkt, p))
|
||
|
|
||
|
return newframe
|
||
|
|
||
|
def getPixel(self, x, y):
|
||
|
""" Return the pixel value at (x, y). """
|
||
|
return self.__pixels[y][x]
|
||
|
|
||
|
def setPixel(self, x, y, value):
|
||
|
""" Set the pixel value at (x, y). """
|
||
|
if self.__dimension.channels == 1:
|
||
|
if value < 0 or value >= self.__dimension.depth:
|
||
|
raise ValueError('pixel value not in depth range')
|
||
|
else:
|
||
|
if len(value) != self.__dimension.channels:
|
||
|
raise ValueError('channel count does not match')
|
||
|
for v in value:
|
||
|
if v < 0 or v >= self.__dimension.depth:
|
||
|
raise ValueError('pixel value not in depth range')
|
||
|
self.__pixels[y][x] = value
|
||
|
|
||
|
|
||
|
def getPixelsAsBytes(self):
|
||
|
""" Return the frame as a byte string. """
|
||
|
if self.__dimension.channels != 1:
|
||
|
raise Exception('cannot convert a multi-channel frame')
|
||
|
|
||
|
bytes = ''
|
||
|
for y in range(self.__dimension.width):
|
||
|
for x in range(self.__dimension.height):
|
||
|
bytes += chr(self.__pixels[x][y])
|
||
|
return bytes
|
||
|
|
||
|
def invert(self):
|
||
|
""" Ivert the frame. """
|
||
|
for y in range(self.__dimension.height):
|
||
|
for x in range(self.__dimension.width):
|
||
|
if self.__dimension.channels == 1:
|
||
|
self.__pixels[x][y] = ((self.__dimension.depth - 1) -
|
||
|
self.__pixels[x][y])
|
||
|
else:
|
||
|
self.__pixels[y][x] = tuple(map(
|
||
|
lambda x: ((self.depth - 1) - x),
|
||
|
self.__pixels[y][x]))
|
||
|
|
||
|
|
||
|
|