Description
With the recent addition of transform.hsl()
(#2398) we now have 5 ways to interact with pixels from a surface, that are:
Surface.get_at()
/Surface.set_at()
Surface.blit()
with different blend flags- using surfarrays and numpy
transform.hsl()
Surface.fill()
While these options cover most needs, there's still room for improvement. Specifically, there's no built-in, easy, and fast way to replace all occurrences of one color with another on a surface:
- Using get_at/set_at is incredibly slow.
- Tinting a surface with a color using .blit() isn't the desired effect.
- Creating a mask and then blitting with alpha can work, but it's a multi-stage process that hinders performance, especially if you need to replace multiple colors.
- transform.hsl shifts all pixels, potentially changing some that we don't want
- Surface.fill covers the entire surface or a sub-rect, so it's not really what we want again
These methods either compromise performance, ease of use or miss the point completely. Therefore, I propose adding a new method/function that can replace a set of colors with another set of corresponding colors:
Surface.replace_colors(sequence: Sequence[Tuple[ColorValue, ColorValue]])
pygame.transform.replace_colors(sequence: Sequence[Tuple[ColorValue, ColorValue]], dest: Optional[Surface] = None)
So you could have something like this:
# would replace all red pixels with green and black with white
surf.replace_colors([((255, 0, 0), (0, 255, 0)), ((0, 0, 0), (255, 255, 255))]
Which could be a really cool addition to quickly change the look of your sprites and an easy way.
My internal tests show that a custom C implementation of this feature would be:
- 500 times faster than a naive get_at/set_at strategy
- 20 times faster than a surfarray strategy without SIMD, and 100 times faster with an AVX2 implementation
- 2500 times faster than a naive get_at/set_at strategy if using AVX2
There have also been discussions about the need for these operations, indicating a genuine demand for such a feature:
https://discord.com/channels/772505616680878080/1245854714504024104