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.
156 lines
4.3 KiB
156 lines
4.3 KiB
""" |
|
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') |
|
if x < 0 or x >= self.dimension.width: |
|
raise ValueError('invalid x coordinate') |
|
if y < 0 or y >= self.dimension.height: |
|
raise ValueError('invalid y coordinate') |
|
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])) |
|
|
|
|
|
|
|
|