Beispiel #1
0
 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)
Beispiel #2
0
 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)
Beispiel #3
0
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
Beispiel #4
0
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