Great! But I'm not entirely sure about the erroneous results I was seeing. I would think that erroneously assuming 3 bytes per pixel when there are really 4 would result in color distortion, not a repetition of pixels. Nor do I understand why saving/loading as a file fixed it, nor why the .png output is still borked (though .jpg comes out fine).
On Mon, Dec 17, 2012 at 1:01 PM, Adam Bark <[email protected]> wrote: > 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. > -- 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.
