On 17/12/12 10:41, Brian Will wrote:
For pedagogical purposes, I'm trying to set up a simple drawing canvas on which to draw and display a single image with control of the individual pixels. Efficiency is no concern. To this end, I have a MutableImage class with getPixel and setPixel methods. Everything seems to work fine, except when blitting the generated image, pixels from columns on the left side for some reason also get displayed in columns about 2/3 to the right, e.g. in a 500 pixel wide image, the content of columns 0-100 gets erroneously drawn also in columns ~300-400 (overwriting whatever should be in those columns). My hack around this is to save my generated image to file, then load it again with pyglet.image.load. When I then blit my generated image newly loaded from the file, it displays properly. So if my data is getting saved properly, does this mean there's a bug in blitting images after set_data?

p.s. I also get strange behavior in the saved .png. The generated image displays correctly in my window, but the saved file doesn't match, almost like a whole color channel is missing. Seems like /something/ is screwy with the channels.

Here's my code:

import pyglet
class MutableImage(object):
    FORMAT = 'RGB'
    def __init__(self, image):
        self.image = image
self.imageData = image.get_data(MutableImage.FORMAT, image.width * len(MutableImage.FORMAT))
        self.dataList = list(self.imageData)
    def getPixel(self, x, y):
        '''Returns tuple of (r, g, b)'''
        pixelIdx = x + (y * self.image.width)
        byteIdx = pixelIdx * len(MutableImage.FORMAT)
        return (
ord(self.dataList[byteIdx]),
ord(self.dataList[byteIdx + 1]),
ord(self.dataList[byteIdx + 2])
        )
    def setPixel(self, x, y, color):
        ''' color is tuple of (R, G, B) as integers 0-255 '''
        # ignore requests to draw out of bounds
        if self.inBounds(x, y):
            pixelIdx = x + (y * self.image.width)
            byteIdx = pixelIdx * len(MutableImage.FORMAT)
            r, g, b = color
self.dataList[byteIdx] = chr(r)
self.dataList[byteIdx + 1] = chr(g)
self.dataList[byteIdx + 2] = chr(b)
    def getImage(self):
        ''' return the current state of data '''
        data = ''.join(self.dataList)
self.image.set_data(MutableImage.FORMAT, self.image.width * len(MutableImage.FORMAT), data) # without hack of saving as file then loading as file, a fraction of left side # gets redrawn on right side for no apparent reason when we blit the image
self.image.save('hack-around.png')
        return pyglet.image.load('hack-around.png')
    def inBounds(self, x, y):
        if x < self.image.width and y < self.image.height:
            return True
        return False
    def clamp(self, x, y):
        if x >= self.image.width:
            x = self.image.width - 1
        if y >= self.image.height:
            y = self.image.height - 1
        return (x, y)
    def paintRectangle(self, lowerLeftCorner, upperRightCorner, color):
        ''' coords in (x, y) tuple  '''
        x1, y1 = lowerLeftCorner
        x2, y2 = upperRightCorner
        x1, y1 = self.clamp(x1, y1)
        x2, y2 = self.clamp(x2, y2)
        for x in range(x1, x2 + 1):
            for y in range(y1, y2 + 1):
self.setPixel(x, y, color)
    def copyRegion(self, src, dest, width, height):
        ''' src and dest (x, y) tuples of lower left corner of regions '''
        pass
    def paintImage(self, dest, srcImage):
''' dest specifies lower left corner where to draw the srcImage '''
mutableSrcImage = MutableImage(srcImage)
        destX, destY = dest
        for x in range(srcImage.width):
            for y in range(srcImage.height):
                color = mutableSrcImage.getPixel(x, y)
self.setPixel(x + destX, y + destY, color)

def displayWindow(image):
window = pyglet.window.Window(image.width, image.height, caption='image render')
    @window.event
    def on_draw():
        image.blit(0, 0)
    pyglet.app.run()



mi = MutableImage(pyglet.image.create(500, 900))
mi.paintRectangle((100, 0), (500, 900), (0, 255, 0))

for x in range(50, 500):
    mi.setPixel(x, 850, (255, 0, 0))
for x in range(50, 500):
    mi.setPixel(x, 450, (255, 0, 0))
for x in range(50, 500):
    mi.setPixel(x, 250, (255, 0, 0))
mi.paintRectangle((0, 0), (100, 100), (0, 255, 255))
mi.paintRectangle((450, 850), (500, 900), (0, 255, 255))

displayWindow(mi.getImage())

Ah ok, I solved it. As the documentation states "*Note:* You can make no assumptions about the return type; usually it will be ImageData or CompressedImageData, but patterns are free to return any subclass of AbstractImage." Therefore you must interrogate the returned image for it's format and pitch ie. on my system:
>>> print image.pitch, image.format
... 2000 RGBA

--
You received this message because you are subscribed to the Google Groups 
"pyglet-users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pyglet-users?hl=en.

Reply via email to