def __init__ (self, width, height, xofs=0, yofs=0): self.width = width self.height = height self.xoffset = xofs self.yoffset = yofs self.data = ImageSurface (width, height)
def __init__(self, width, height, xofs=0, yofs=0): self.width = width self.height = height self.xoffset = xofs self.yoffset = yofs self.data = ImageSurface(width, height)
class Image: """An image class that stores its' data in an unsigned byte RGBA buffer.""" def __init__ (self, width, height, xofs=0, yofs=0): self.width = width self.height = height self.xoffset = xofs self.yoffset = yofs self.data = ImageSurface (width, height) def GetPixel (self, x, y): """Retrieves the color of a pixel at the given position.""" return UnpackColor (self.data.getPixel (x, y)) def SetPixel (self, x, y, color=None): """Sets the color of a pixel at the given position.""" if x < 0 or x >= self.dimensions[0]: raise ValueError ("x is out of the image boundary ({} <> {})".format (x, self.dimensions[0])) if y < 0 or y >= self.dimensions[1]: raise ValueError ("y is out of the image boundary ({} <> {})".format (y, self.dimensions[1])) w = self.dimensions[0] if color is None: color = (0, 0, 0, 0) if type (color) is PaletteIndex: color = (color.red, color.green, color.blue, 255) self.data.setPixel (x, y, PackColor (*color)) ### Image Readers ### @classmethod def LoadDoomGraphic (cls, bytebuffer, palette): """Loads a top-down column-based paletted doom graphic, given the graphic's binary data and a palette. Returns an Image usable with the OpenGL context.""" pos = 0 width, height, xofs, yofs = struct.unpack_from ("<HHHH", bytebuffer, pos) pos += struct.calcsize ("<HHHH") image = cls (width, height, xofs, yofs) colheaders = [] # The headers for each column for colheader in range (width): colheaders.append (struct.unpack_from ("<I", bytebuffer, pos)[0]) pos += struct.calcsize ("<I") # Okay, so in the standard graphic format, if the last row # started in the same column is above or at the height last # drawn, they'd usually be drawn above or on top of the column # we just drew (which would be a waste of space since we're just # drawing on top of pixels we've *just* drawn). # Instead, what we do is *add* the last offset to our current # one, so we're always drawing in new space instead. This gives # us twice the column height to work with, allowing graphic # columns to start from up to the 512th row instead of the # 256th. This means transparent images that are > 256 in height # won't corrupt. for column in range (width): lastrowstart = -1 rowstart = 0 byteofs = colheaders[column] while True: rowstart = struct.unpack_from ("<B", bytebuffer, byteofs)[0] byteofs += 1 if rowstart == 255: # No more pieces to draw, go to next column break if rowstart <= lastrowstart: rowstart += lastrowstart columnlength = struct.unpack_from ("<B", bytebuffer, byteofs)[0] byteofs += 2 for rowpos in range (columnlength): palindex = struct.unpack_from ("<B", bytebuffer, byteofs)[0] byteofs += 1 palcolor = palette.colors[palindex] image.SetPixel (column, rowpos + rowstart, palcolor) byteofs += 1 lastrowstart = rowstart return image @classmethod def LoadPNG (cls, bytebuffer): """Loads a Portable Network Graphic.""" decompressor = zlib.decompressobj () if bytebuffer[0:8] != b'\x89PNG\r\n\x1a\n': raise ValueError ("The PNG header is corrupted") # TODO pass
class Image: """An image class that stores its' data in an unsigned byte RGBA buffer.""" def __init__(self, width, height, xofs=0, yofs=0): self.width = width self.height = height self.xoffset = xofs self.yoffset = yofs self.data = ImageSurface(width, height) def GetPixel(self, x, y): """Retrieves the color of a pixel at the given position.""" return UnpackColor(self.data.getPixel(x, y)) def SetPixel(self, x, y, color=None): """Sets the color of a pixel at the given position.""" if x < 0 or x >= self.dimensions[0]: raise ValueError( "x is out of the image boundary ({} <> {})".format( x, self.dimensions[0])) if y < 0 or y >= self.dimensions[1]: raise ValueError( "y is out of the image boundary ({} <> {})".format( y, self.dimensions[1])) w = self.dimensions[0] if color is None: color = (0, 0, 0, 0) if type(color) is PaletteIndex: color = (color.red, color.green, color.blue, 255) self.data.setPixel(x, y, PackColor(*color)) ### Image Readers ### @classmethod def LoadDoomGraphic(cls, bytebuffer, palette): """Loads a top-down column-based paletted doom graphic, given the graphic's binary data and a palette. Returns an Image usable with the OpenGL context.""" pos = 0 width, height, xofs, yofs = struct.unpack_from("<HHHH", bytebuffer, pos) pos += struct.calcsize("<HHHH") image = cls(width, height, xofs, yofs) colheaders = [] # The headers for each column for colheader in range(width): colheaders.append(struct.unpack_from("<I", bytebuffer, pos)[0]) pos += struct.calcsize("<I") # Okay, so in the standard graphic format, if the last row # started in the same column is above or at the height last # drawn, they'd usually be drawn above or on top of the column # we just drew (which would be a waste of space since we're just # drawing on top of pixels we've *just* drawn). # Instead, what we do is *add* the last offset to our current # one, so we're always drawing in new space instead. This gives # us twice the column height to work with, allowing graphic # columns to start from up to the 512th row instead of the # 256th. This means transparent images that are > 256 in height # won't corrupt. for column in range(width): lastrowstart = -1 rowstart = 0 byteofs = colheaders[column] while True: rowstart = struct.unpack_from("<B", bytebuffer, byteofs)[0] byteofs += 1 if rowstart == 255: # No more pieces to draw, go to next column break if rowstart <= lastrowstart: rowstart += lastrowstart columnlength = struct.unpack_from("<B", bytebuffer, byteofs)[0] byteofs += 2 for rowpos in range(columnlength): palindex = struct.unpack_from("<B", bytebuffer, byteofs)[0] byteofs += 1 palcolor = palette.colors[palindex] image.SetPixel(column, rowpos + rowstart, palcolor) byteofs += 1 lastrowstart = rowstart return image @classmethod def LoadPNG(cls, bytebuffer): """Loads a Portable Network Graphic.""" decompressor = zlib.decompressobj() if bytebuffer[0:8] != b'\x89PNG\r\n\x1a\n': raise ValueError("The PNG header is corrupted") # TODO pass