Ah, PixelArray. Of course! I'm actually using a PixelArray elsewhere in my code to extract the integer values of the surface which is fed to a dot matrix display. (My project is for a pinball machine.) My surface blits are used to create an on screen representation in a display window of the physical dot matrix display which is where I use the palette to set the colors. (The actual physical dot matrix display only has 16 shades of pixel brightness which is why I'm using an 8-bit surface.)
Anyway I don't know why I didn't think of using a PixelArray here, but yeah, that makes total sense. Awesome. Thanks so much for the feedback and ideas! Brian On Wed, Dec 3, 2014 at 4:25 PM, Lenard Lindstrom <le...@telus.net> wrote: > Hi Brian, > > On 14-12-02 09:56 AM, Brian Madden wrote: > >> Hi. I'm working with 8-bit surfaces in Python 2.7 with Pygame 1.9.2pre. >> Everything I've read says that if I blit an 8-bit surface to another 8-bit >> surface, Pygame will ignore both palettes and only copy each pixel's 8-bit >> integer value from the source surface to the destination surface. >> >> A Pygame Surface lets the programmer work with SDL surfaces without the > concern of how the pixel data is actually represented in memory. A Pygame > Surface pixel is the decoded--unmapped--(R, G, B, A) representation of the > color encoded--mapped--into the pixel's actual integer value. Since a > Pygame Surface is a color representation its pixel data, it is natural that > Surface methods do high level color transformations rather than direct > integer value manipulation. So, Surface.blit() actually blits unmapped > pixel colors, with the result mapped back into the destination surface > binary format (Of course, shortcuts are taken when possible.) > > My experience so far is that this is *not* what happens. Rather, I'm >> seeing that that when blitting, Pygame will use the source surface's >> palette to get the 24-bit entry for each pixel, then look for that 24-bit >> value in the destination surface's palette, and then write the 8-bit >> integer value from the destination surface's palette as the pixel value in >> the destination surface. If there are no matching 24-bit palette entries >> for the palettes for both surfaces, then the resulting pixel's integer >> value in the destination surface is 0. >> > For two 8-bit surfaces without surface alpha or a color key the > Surface.blit() method has SDL do the blit. > > >> I'm just curious as to whether this is this a bug, or is my understanding >> of how Pygame works with 8-bit surfaces not correct? (In my case I have >> multiple surfaces each with their own palettes, and if I blit a pixel value >> of "1" then I want it to be "1" on my destination surface regardless of >> what any of the palettes are! :) >> >> Yes, the Pygame.blit() method description lacks detail. It assumes the > reader has some understanding of the SDL library. But this is no longer a > reasonable expectation. The pygame.Surface documentation needs updating. > > > It is possible to do a direct integer copy with pygame.PixelArray. Here is > a basic example: > > def pxcopy(source, target, dest=None): > """Copy raw surface pixels from source to target > > Argument dest is the (x, y) coordinates within the target surface > where the source surface will be copied. The default is (0, 0). > This simple example fails if the source rect does not fit entirely > within the target boundary.""" > > if dest is None: > dest = (0, 0) > x, y = dest > s = PixelArray(source) > w, h = s.shape > t = PixelArray(target) > t[x:x+w, y:y+h] = s > > >>> import pygame > >>> pygame.display.init() # Need this to enable Surface.set_palette() > >>> from pygame import Surface, PixelArray > >>> palette = [(i, i, i) for i in range(256)] > >>> target = Surface((100, 100), 0, 8) > >>> target.set_palette(palette) > >>> target.set_palette(palette) > >>> target.fill((30, 30, 30)) > <rect(0, 0, 100, 100)> > >>> target.get_at((10, 15)) > (30, 30, 30, 255) > >>> target.get_at_mapped((10, 15)) > 30 > >>> source = Surface((20, 30), 0, 8) > >>> source.fill((255, 0, 0)) > <rect(0, 0, 20, 30)> > >>> source.get_at((0, 0)) > (255, 0, 0, 255) > >>> source.get_at_mapped((0, 0)) > 96 > >>> pxcopy(source, target, (10, 15)) > >>> target.get_at_mapped((10, 15)) > 96 > >>> target.get_at((10, 15)) > (96, 96, 96, 255) > >>> target.get_at((0, 0)) > (30, 30, 30, 255) > >>> > > > Lenard Lindstrom > > -- *Brian Madden* Mission Pinball (blog <http://missionpinball.com> | twitter <https://twitter.com/missionpinball> | MPF software framework <http://missionpinball.com/framework> | sample games <https://missionpinball.com/blog/category/big-shot-em-conversion/>)