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