Traktor/myenv/Lib/site-packages/pygame/tests/pixelarray_test.py

1668 lines
61 KiB
Python
Raw Normal View History

2024-05-26 05:12:46 +02:00
import gc
import operator
import platform
import sys
import unittest
import weakref
from functools import reduce
from pygame.tests.test_utils import SurfaceSubclass
try:
from pygame.tests.test_utils import arrinter
except NameError:
pass
import pygame
IS_PYPY = "PyPy" == platform.python_implementation()
class TestMixin:
def assert_surfaces_equal(self, s1, s2, msg=None):
"""Checks if two surfaces are equal in size and color."""
w, h = s1.get_size()
self.assertTupleEqual((w, h), s2.get_size(), msg)
msg = "" if msg is None else f"{msg}, "
msg += f"size: ({w}, {h})"
for x in range(w):
for y in range(h):
self.assertEqual(
s1.get_at((x, y)),
s2.get_at((x, y)),
f"{msg}, position: ({x}, {y})",
)
def assert_surface_filled(self, surface, expected_color, msg=None):
"""Checks if the surface is filled with the given color."""
width, height = surface.get_size()
surface.lock() # Lock for possible speed up.
for pos in ((x, y) for y in range(height) for x in range(width)):
self.assertEqual(surface.get_at(pos), expected_color, msg)
surface.unlock()
@unittest.skipIf(IS_PYPY, "pypy having issues")
class PixelArrayTypeTest(unittest.TestCase, TestMixin):
def test_compare(self):
# __doc__ (as of 2008-06-25) for pygame.pixelarray.PixelArray.compare:
# PixelArray.compare (array, distance=0, weights=(0.299, 0.587, 0.114)): Return PixelArray
# Compares the PixelArray with another one.
w = 10
h = 20
size = w, h
sf = pygame.Surface(size, 0, 32)
ar = pygame.PixelArray(sf)
sf2 = pygame.Surface(size, 0, 32)
self.assertRaises(TypeError, ar.compare, sf2)
ar2 = pygame.PixelArray(sf2)
ar3 = ar.compare(ar2)
self.assertTrue(isinstance(ar3, pygame.PixelArray))
self.assertEqual(ar3.shape, size)
sf2.fill(pygame.Color("white"))
self.assert_surfaces_equal(sf2, ar3.surface)
del ar3
r = pygame.Rect(2, 5, 6, 13)
sf.fill(pygame.Color("blue"), r)
sf2.fill(pygame.Color("red"))
sf2.fill(pygame.Color("blue"), r)
ar3 = ar.compare(ar2)
sf.fill(pygame.Color("white"), r)
self.assert_surfaces_equal(sf, ar3.surface)
# FINISH ME!
# Test other bit depths, slices, and distance != 0.
def test_compare__same_colors_within_distance(self):
"""Ensures compare works correctly with same colored surfaces."""
size = (3, 5)
pixelarray_result_color = pygame.Color("white")
surface_color = (127, 127, 127, 255)
for depth in (8, 16, 24, 32):
expected_pixelarray_surface = pygame.Surface(size, depth=depth)
expected_pixelarray_surface.fill(pixelarray_result_color)
# Copy the surface to ensure same dimensions/formatting.
surf_a = expected_pixelarray_surface.copy()
surf_a.fill(surface_color)
# For non-32 bit depths, the actual color can be different from what
# was filled.
expected_surface_color = surf_a.get_at((0, 0))
pixelarray_a = pygame.PixelArray(surf_a)
pixelarray_b = pygame.PixelArray(surf_a.copy())
for distance in (0.0, 0.01, 0.1, 1.0):
pixelarray_result = pixelarray_a.compare(
pixelarray_b, distance=distance
)
# Ensure the resulting pixelarray is correct and that the original
# surfaces were not changed.
self.assert_surfaces_equal(
pixelarray_result.surface,
expected_pixelarray_surface,
(depth, distance),
)
self.assert_surface_filled(
pixelarray_a.surface, expected_surface_color, (depth, distance)
)
self.assert_surface_filled(
pixelarray_b.surface, expected_surface_color, (depth, distance)
)
pixelarray_a.close()
pixelarray_b.close()
pixelarray_result.close()
def test_compare__different_colors_within_distance(self):
"""Ensures compare works correctly with different colored surfaces
and the color difference is within the given distance.
"""
size = (3, 5)
pixelarray_result_color = pygame.Color("white")
surface_a_color = (127, 127, 127, 255)
surface_b_color = (128, 127, 127, 255)
for depth in (8, 16, 24, 32):
expected_pixelarray_surface = pygame.Surface(size, depth=depth)
expected_pixelarray_surface.fill(pixelarray_result_color)
# Copy the surface to ensure same dimensions/formatting.
surf_a = expected_pixelarray_surface.copy()
surf_a.fill(surface_a_color)
# For non-32 bit depths, the actual color can be different from what
# was filled.
expected_surface_a_color = surf_a.get_at((0, 0))
pixelarray_a = pygame.PixelArray(surf_a)
surf_b = expected_pixelarray_surface.copy()
surf_b.fill(surface_b_color)
# For non-32 bit depths, the actual color can be different from what
# was filled.
expected_surface_b_color = surf_b.get_at((0, 0))
pixelarray_b = pygame.PixelArray(surf_b)
for distance in (0.2, 0.3, 0.5, 1.0):
pixelarray_result = pixelarray_a.compare(
pixelarray_b, distance=distance
)
# Ensure the resulting pixelarray is correct and that the original
# surfaces were not changed.
self.assert_surfaces_equal(
pixelarray_result.surface,
expected_pixelarray_surface,
(depth, distance),
)
self.assert_surface_filled(
pixelarray_a.surface, expected_surface_a_color, (depth, distance)
)
self.assert_surface_filled(
pixelarray_b.surface, expected_surface_b_color, (depth, distance)
)
pixelarray_a.close()
pixelarray_b.close()
pixelarray_result.close()
def test_compare__different_colors_not_within_distance(self):
"""Ensures compare works correctly with different colored surfaces
and the color difference is not within the given distance.
"""
size = (3, 5)
pixelarray_result_color = pygame.Color("black")
surface_a_color = (127, 127, 127, 255)
surface_b_color = (128, 127, 127, 255)
for depth in (8, 16, 24, 32):
expected_pixelarray_surface = pygame.Surface(size, depth=depth)
expected_pixelarray_surface.fill(pixelarray_result_color)
# Copy the surface to ensure same dimensions/formatting.
surf_a = expected_pixelarray_surface.copy()
surf_a.fill(surface_a_color)
# For non-32 bit depths, the actual color can be different from what
# was filled.
expected_surface_a_color = surf_a.get_at((0, 0))
pixelarray_a = pygame.PixelArray(surf_a)
surf_b = expected_pixelarray_surface.copy()
surf_b.fill(surface_b_color)
# For non-32 bit depths, the actual color can be different from what
# was filled.
expected_surface_b_color = surf_b.get_at((0, 0))
pixelarray_b = pygame.PixelArray(surf_b)
for distance in (0.0, 0.00001, 0.0001, 0.001):
pixelarray_result = pixelarray_a.compare(
pixelarray_b, distance=distance
)
# Ensure the resulting pixelarray is correct and that the original
# surfaces were not changed.
self.assert_surfaces_equal(
pixelarray_result.surface,
expected_pixelarray_surface,
(depth, distance),
)
self.assert_surface_filled(
pixelarray_a.surface, expected_surface_a_color, (depth, distance)
)
self.assert_surface_filled(
pixelarray_b.surface, expected_surface_b_color, (depth, distance)
)
pixelarray_a.close()
pixelarray_b.close()
pixelarray_result.close()
def test_close(self):
"""does not crash when it is deleted."""
s = pygame.Surface((10, 10))
a = pygame.PixelArray(s)
a.close()
del a
def test_close_raises(self):
"""when you try to do an operation after it is closed."""
s = pygame.Surface((10, 10))
a = pygame.PixelArray(s)
a.close()
def access_after():
a[:]
self.assertRaises(ValueError, access_after)
def assign_all_after():
a[:] = 1
self.assertRaises(ValueError, assign_all_after)
def make_surface_after():
a.make_surface()
self.assertRaises(ValueError, make_surface_after)
def iter_after():
for x in a:
pass
self.assertRaises(ValueError, iter_after)
def close_after():
a.close()
self.assertRaises(ValueError, close_after)
def surface_after():
a.surface
self.assertRaises(ValueError, surface_after)
def itemsize_after():
a.itemsize
self.assertRaises(ValueError, itemsize_after)
def transpose_after():
a.transpose()
self.assertRaises(ValueError, transpose_after)
def test_context_manager(self):
"""closes properly."""
s = pygame.Surface((10, 10))
with pygame.PixelArray(s) as a:
a[:]
# Test pixel array write... will also catch refcount issues and
# segfault
with pygame.PixelArray(s) as a:
a[:] = pygame.Color("deepskyblue")
def test_pixel_array(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
self.assertEqual(ar._pixels_address, sf._pixels_address)
if sf.mustlock():
self.assertTrue(sf.get_locked())
self.assertEqual(len(ar), 10)
del ar
if sf.mustlock():
self.assertFalse(sf.get_locked())
def test_as_class(self):
# Check general new-style class freatures.
sf = pygame.Surface((2, 3), 0, 32)
ar = pygame.PixelArray(sf)
self.assertRaises(AttributeError, getattr, ar, "nonnative")
ar.nonnative = "value"
self.assertEqual(ar.nonnative, "value")
r = weakref.ref(ar)
self.assertTrue(r() is ar)
del ar
gc.collect()
self.assertTrue(r() is None)
class C(pygame.PixelArray):
def __str__(self):
return "string (%i, %i)" % self.shape
ar = C(sf)
self.assertEqual(str(ar), "string (2, 3)")
r = weakref.ref(ar)
self.assertTrue(r() is ar)
del ar
gc.collect()
self.assertTrue(r() is None)
def test_pixelarray__subclassed_surface(self):
"""Ensure the PixelArray constructor accepts subclassed surfaces."""
surface = SurfaceSubclass((3, 5), 0, 32)
pixelarray = pygame.PixelArray(surface)
self.assertIsInstance(pixelarray, pygame.PixelArray)
# Sequence interfaces
def test_get_column(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((6, 8), 0, bpp)
sf.fill((0, 0, 255))
val = sf.map_rgb((0, 0, 255))
ar = pygame.PixelArray(sf)
ar2 = ar.__getitem__(1)
self.assertEqual(len(ar2), 8)
self.assertEqual(ar2.__getitem__(0), val)
self.assertEqual(ar2.__getitem__(1), val)
self.assertEqual(ar2.__getitem__(2), val)
ar2 = ar.__getitem__(-1)
self.assertEqual(len(ar2), 8)
self.assertEqual(ar2.__getitem__(0), val)
self.assertEqual(ar2.__getitem__(1), val)
self.assertEqual(ar2.__getitem__(2), val)
@unittest.skipIf(IS_PYPY, "pypy malloc abort")
def test_get_pixel(self):
w = 10
h = 20
size = w, h
bg_color = (0, 0, 255)
fg_color_y = (0, 0, 128)
fg_color_x = (0, 0, 11)
for bpp in (8, 16, 24, 32):
sf = pygame.Surface(size, 0, bpp)
mapped_bg_color = sf.map_rgb(bg_color)
mapped_fg_color_y = sf.map_rgb(fg_color_y)
mapped_fg_color_x = sf.map_rgb(fg_color_x)
self.assertNotEqual(
mapped_fg_color_y,
mapped_bg_color,
"Unusable test colors for bpp %i" % (bpp,),
)
self.assertNotEqual(
mapped_fg_color_x,
mapped_bg_color,
"Unusable test colors for bpp %i" % (bpp,),
)
self.assertNotEqual(
mapped_fg_color_y,
mapped_fg_color_x,
"Unusable test colors for bpp %i" % (bpp,),
)
sf.fill(bg_color)
ar = pygame.PixelArray(sf)
ar_y = ar.__getitem__(1)
for y in range(h):
ar2 = ar_y.__getitem__(y)
self.assertEqual(
ar2,
mapped_bg_color,
"ar[1][%i] == %i, mapped_bg_color == %i"
% (y, ar2, mapped_bg_color),
)
sf.set_at((1, y), fg_color_y)
ar2 = ar_y.__getitem__(y)
self.assertEqual(
ar2,
mapped_fg_color_y,
"ar[1][%i] == %i, mapped_fg_color_y == %i"
% (y, ar2, mapped_fg_color_y),
)
sf.set_at((1, 1), bg_color)
for x in range(w):
ar2 = ar.__getitem__(x).__getitem__(1)
self.assertEqual(
ar2,
mapped_bg_color,
"ar[%i][1] = %i, mapped_bg_color = %i" % (x, ar2, mapped_bg_color),
)
sf.set_at((x, 1), fg_color_x)
ar2 = ar.__getitem__(x).__getitem__(1)
self.assertEqual(
ar2,
mapped_fg_color_x,
"ar[%i][1] = %i, mapped_fg_color_x = %i"
% (x, ar2, mapped_fg_color_x),
)
ar2 = ar.__getitem__(0).__getitem__(0)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(1).__getitem__(0)
self.assertEqual(ar2, mapped_fg_color_y, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(-4).__getitem__(1)
self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(-4).__getitem__(5)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(-4).__getitem__(0)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(-w + 1).__getitem__(0)
self.assertEqual(ar2, mapped_fg_color_y, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(-w).__getitem__(0)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(5).__getitem__(-4)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(5).__getitem__(-h + 1)
self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(5).__getitem__(-h)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(0).__getitem__(-h + 1)
self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,))
ar2 = ar.__getitem__(0).__getitem__(-h)
self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,))
def test_set_pixel(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
ar.__getitem__(0).__setitem__(0, (0, 255, 0))
self.assertEqual(ar[0][0], sf.map_rgb((0, 255, 0)))
ar.__getitem__(1).__setitem__(1, (128, 128, 128))
self.assertEqual(ar[1][1], sf.map_rgb((128, 128, 128)))
ar.__getitem__(-1).__setitem__(-1, (128, 128, 128))
self.assertEqual(ar[9][19], sf.map_rgb((128, 128, 128)))
ar.__getitem__(-2).__setitem__(-2, (128, 128, 128))
self.assertEqual(ar[8][-2], sf.map_rgb((128, 128, 128)))
def test_set_column(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((6, 8), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
sf2 = pygame.Surface((6, 8), 0, bpp)
sf2.fill((0, 255, 255))
ar2 = pygame.PixelArray(sf2)
# Test single value assignment
ar.__setitem__(2, (128, 128, 128))
self.assertEqual(ar[2][0], sf.map_rgb((128, 128, 128)))
self.assertEqual(ar[2][1], sf.map_rgb((128, 128, 128)))
ar.__setitem__(-1, (0, 255, 255))
self.assertEqual(ar[5][0], sf.map_rgb((0, 255, 255)))
self.assertEqual(ar[-1][1], sf.map_rgb((0, 255, 255)))
ar.__setitem__(-2, (255, 255, 0))
self.assertEqual(ar[4][0], sf.map_rgb((255, 255, 0)))
self.assertEqual(ar[-2][1], sf.map_rgb((255, 255, 0)))
# Test list assignment.
ar.__setitem__(0, [(255, 255, 255)] * 8)
self.assertEqual(ar[0][0], sf.map_rgb((255, 255, 255)))
self.assertEqual(ar[0][1], sf.map_rgb((255, 255, 255)))
# Test tuple assignment.
# Changed in Pygame 1.9.2 - Raises an exception.
self.assertRaises(
ValueError,
ar.__setitem__,
1,
(
(204, 0, 204),
(17, 17, 17),
(204, 0, 204),
(17, 17, 17),
(204, 0, 204),
(17, 17, 17),
(204, 0, 204),
(17, 17, 17),
),
)
# Test pixel array assignment.
ar.__setitem__(1, ar2.__getitem__(3))
self.assertEqual(ar[1][0], sf.map_rgb((0, 255, 255)))
self.assertEqual(ar[1][1], sf.map_rgb((0, 255, 255)))
def test_get_slice(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
self.assertEqual(len(ar[0:2]), 2)
self.assertEqual(len(ar[3:7][3]), 20)
self.assertEqual(ar[0:0], None)
self.assertEqual(ar[5:5], None)
self.assertEqual(ar[9:9], None)
# Has to resolve to ar[7:8]
self.assertEqual(len(ar[-3:-2]), 1) # 2D
self.assertEqual(len(ar[-3:-2][0]), 20) # 1D
# Try assignments.
# 2D assignment.
ar[2:5] = (255, 255, 255)
# 1D assignment
ar[3][3:7] = (10, 10, 10)
self.assertEqual(ar[3][5], sf.map_rgb((10, 10, 10)))
self.assertEqual(ar[3][6], sf.map_rgb((10, 10, 10)))
@unittest.skipIf(IS_PYPY, "skipping for PyPy (segfaults on mac pypy3 6.0.0)")
def test_contains(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
sf.fill((0, 0, 0))
sf.set_at((8, 8), (255, 255, 255))
ar = pygame.PixelArray(sf)
self.assertTrue((0, 0, 0) in ar)
self.assertTrue((255, 255, 255) in ar)
self.assertFalse((255, 255, 0) in ar)
self.assertFalse(0x0000FF in ar)
# Test sliced array
self.assertTrue((0, 0, 0) in ar[8])
self.assertTrue((255, 255, 255) in ar[8])
self.assertFalse((255, 255, 0) in ar[8])
self.assertFalse(0x0000FF in ar[8])
def test_get_surface(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
self.assertTrue(ar.surface is sf)
def test_get_surface__subclassed_surface(self):
"""Ensure the surface attribute can handle subclassed surfaces."""
expected_surface = SurfaceSubclass((5, 3), 0, 32)
pixelarray = pygame.PixelArray(expected_surface)
surface = pixelarray.surface
self.assertIs(surface, expected_surface)
self.assertIsInstance(surface, pygame.Surface)
self.assertIsInstance(surface, SurfaceSubclass)
def test_set_slice(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((6, 8), 0, bpp)
sf.fill((0, 0, 0))
ar = pygame.PixelArray(sf)
# Test single value assignment
val = sf.map_rgb((128, 128, 128))
ar[0:2] = val
self.assertEqual(ar[0][0], val)
self.assertEqual(ar[0][1], val)
self.assertEqual(ar[1][0], val)
self.assertEqual(ar[1][1], val)
val = sf.map_rgb((0, 255, 255))
ar[-3:-1] = val
self.assertEqual(ar[3][0], val)
self.assertEqual(ar[-2][1], val)
val = sf.map_rgb((255, 255, 255))
ar[-3:] = (255, 255, 255)
self.assertEqual(ar[4][0], val)
self.assertEqual(ar[-1][1], val)
# Test array size mismatch.
# Changed in ver. 1.9.2
# (was "Test list assignment, this is a vertical assignment.")
val = sf.map_rgb((0, 255, 0))
self.assertRaises(ValueError, ar.__setitem__, slice(2, 4), [val] * 8)
# And the horizontal assignment.
val = sf.map_rgb((255, 0, 0))
val2 = sf.map_rgb((128, 0, 255))
ar[0:2] = [val, val2]
self.assertEqual(ar[0][0], val)
self.assertEqual(ar[1][0], val2)
self.assertEqual(ar[0][1], val)
self.assertEqual(ar[1][1], val2)
self.assertEqual(ar[0][4], val)
self.assertEqual(ar[1][4], val2)
self.assertEqual(ar[0][5], val)
self.assertEqual(ar[1][5], val2)
# Test pixelarray assignment.
ar[:] = (0, 0, 0)
sf2 = pygame.Surface((6, 8), 0, bpp)
sf2.fill((255, 0, 255))
val = sf.map_rgb((255, 0, 255))
ar2 = pygame.PixelArray(sf2)
ar[:] = ar2[:]
self.assertEqual(ar[0][0], val)
self.assertEqual(ar[5][7], val)
# Ensure p1 ... pn are freed for array[...] = [p1, ..., pn]
# Bug fix: reference counting.
if hasattr(sys, "getrefcount"):
class Int(int):
"""Unique int instances"""
pass
sf = pygame.Surface((5, 2), 0, 32)
ar = pygame.PixelArray(sf)
pixel_list = [Int(i) for i in range(ar.shape[0])]
refcnts_before = [sys.getrefcount(i) for i in pixel_list]
ar[...] = pixel_list
refcnts_after = [sys.getrefcount(i) for i in pixel_list]
gc.collect()
self.assertEqual(refcnts_after, refcnts_before)
def test_subscript(self):
# By default we do not need to work with any special __***__
# methods as map subscripts are the first looked up by the
# object system.
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((6, 8), 0, bpp)
sf.set_at((1, 3), (0, 255, 0))
sf.set_at((0, 0), (0, 255, 0))
sf.set_at((4, 4), (0, 255, 0))
val = sf.map_rgb((0, 255, 0))
ar = pygame.PixelArray(sf)
# Test single value requests.
self.assertEqual(ar[1, 3], val)
self.assertEqual(ar[0, 0], val)
self.assertEqual(ar[4, 4], val)
self.assertEqual(ar[1][3], val)
self.assertEqual(ar[0][0], val)
self.assertEqual(ar[4][4], val)
# Test ellipse working.
self.assertEqual(len(ar[..., ...]), 6)
self.assertEqual(len(ar[1, ...]), 8)
self.assertEqual(len(ar[..., 3]), 6)
# Test simple slicing
self.assertEqual(len(ar[:, :]), 6)
self.assertEqual(
len(ar[:,]),
6,
)
self.assertEqual(len(ar[1, :]), 8)
self.assertEqual(len(ar[:, 2]), 6)
# Empty slices
self.assertEqual(
ar[4:4,],
None,
)
self.assertEqual(ar[4:4, ...], None)
self.assertEqual(ar[4:4, 2:2], None)
self.assertEqual(ar[4:4, 1:4], None)
self.assertEqual(
ar[4:4:2,],
None,
)
self.assertEqual(
ar[4:4:-2,],
None,
)
self.assertEqual(ar[4:4:1, ...], None)
self.assertEqual(ar[4:4:-1, ...], None)
self.assertEqual(ar[4:4:1, 2:2], None)
self.assertEqual(ar[4:4:-1, 1:4], None)
self.assertEqual(ar[..., 4:4], None)
self.assertEqual(ar[1:4, 4:4], None)
self.assertEqual(ar[..., 4:4:1], None)
self.assertEqual(ar[..., 4:4:-1], None)
self.assertEqual(ar[2:2, 4:4:1], None)
self.assertEqual(ar[1:4, 4:4:-1], None)
# Test advanced slicing
ar[0] = 0
ar[1] = 1
ar[2] = 2
ar[3] = 3
ar[4] = 4
ar[5] = 5
# We should receive something like [0,2,4]
self.assertEqual(ar[::2, 1][0], 0)
self.assertEqual(ar[::2, 1][1], 2)
self.assertEqual(ar[::2, 1][2], 4)
# We should receive something like [2,2,2]
self.assertEqual(ar[2, ::2][0], 2)
self.assertEqual(ar[2, ::2][1], 2)
self.assertEqual(ar[2, ::2][2], 2)
# Should create a 3x3 array of [0,2,4]
ar2 = ar[::2, ::2]
self.assertEqual(len(ar2), 3)
self.assertEqual(ar2[0][0], 0)
self.assertEqual(ar2[0][1], 0)
self.assertEqual(ar2[0][2], 0)
self.assertEqual(ar2[2][0], 4)
self.assertEqual(ar2[2][1], 4)
self.assertEqual(ar2[2][2], 4)
self.assertEqual(ar2[1][0], 2)
self.assertEqual(ar2[2][0], 4)
self.assertEqual(ar2[1][1], 2)
# Should create a reversed 3x8 array over X of [1,2,3] -> [3,2,1]
ar2 = ar[3:0:-1]
self.assertEqual(len(ar2), 3)
self.assertEqual(ar2[0][0], 3)
self.assertEqual(ar2[0][1], 3)
self.assertEqual(ar2[0][2], 3)
self.assertEqual(ar2[0][7], 3)
self.assertEqual(ar2[2][0], 1)
self.assertEqual(ar2[2][1], 1)
self.assertEqual(ar2[2][2], 1)
self.assertEqual(ar2[2][7], 1)
self.assertEqual(ar2[1][0], 2)
self.assertEqual(ar2[1][1], 2)
# Should completely reverse the array over X -> [5,4,3,2,1,0]
ar2 = ar[::-1]
self.assertEqual(len(ar2), 6)
self.assertEqual(ar2[0][0], 5)
self.assertEqual(ar2[0][1], 5)
self.assertEqual(ar2[0][3], 5)
self.assertEqual(ar2[0][-1], 5)
self.assertEqual(ar2[1][0], 4)
self.assertEqual(ar2[1][1], 4)
self.assertEqual(ar2[1][3], 4)
self.assertEqual(ar2[1][-1], 4)
self.assertEqual(ar2[-1][-1], 0)
self.assertEqual(ar2[-2][-2], 1)
self.assertEqual(ar2[-3][-1], 2)
# Test advanced slicing
ar[:] = 0
ar2 = ar[:, 1]
ar2[:] = [99] * len(ar2)
self.assertEqual(ar2[0], 99)
self.assertEqual(ar2[-1], 99)
self.assertEqual(ar2[-2], 99)
self.assertEqual(ar2[2], 99)
self.assertEqual(ar[0, 1], 99)
self.assertEqual(ar[1, 1], 99)
self.assertEqual(ar[2, 1], 99)
self.assertEqual(ar[-1, 1], 99)
self.assertEqual(ar[-2, 1], 99)
# Cases where a 2d array should have a dimension of length 1.
ar2 = ar[1:2, :]
self.assertEqual(ar2.shape, (1, ar.shape[1]))
ar2 = ar[:, 1:2]
self.assertEqual(ar2.shape, (ar.shape[0], 1))
sf2 = pygame.Surface((1, 5), 0, 32)
ar2 = pygame.PixelArray(sf2)
self.assertEqual(ar2.shape, sf2.get_size())
sf2 = pygame.Surface((7, 1), 0, 32)
ar2 = pygame.PixelArray(sf2)
self.assertEqual(ar2.shape, sf2.get_size())
# Array has a single ellipsis subscript: the identity operator
ar2 = ar[...]
self.assertTrue(ar2 is ar)
# Ensure x and y are freed for p = array[x, y]
# Bug fix: reference counting
if hasattr(sys, "getrefcount"):
class Int(int):
"""Unique int instances"""
pass
sf = pygame.Surface((2, 2), 0, 32)
ar = pygame.PixelArray(sf)
x, y = Int(0), Int(1)
rx_before, ry_before = sys.getrefcount(x), sys.getrefcount(y)
p = ar[x, y]
rx_after, ry_after = sys.getrefcount(x), sys.getrefcount(y)
self.assertEqual(rx_after, rx_before)
self.assertEqual(ry_after, ry_before)
def test_ass_subscript(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((6, 8), 0, bpp)
sf.fill((255, 255, 255))
ar = pygame.PixelArray(sf)
# Test ellipse working
ar[..., ...] = (0, 0, 0)
self.assertEqual(ar[0, 0], 0)
self.assertEqual(ar[1, 0], 0)
self.assertEqual(ar[-1, -1], 0)
ar[...,] = (0, 0, 255)
self.assertEqual(ar[0, 0], sf.map_rgb((0, 0, 255)))
self.assertEqual(ar[1, 0], sf.map_rgb((0, 0, 255)))
self.assertEqual(ar[-1, -1], sf.map_rgb((0, 0, 255)))
ar[:, ...] = (255, 0, 0)
self.assertEqual(ar[0, 0], sf.map_rgb((255, 0, 0)))
self.assertEqual(ar[1, 0], sf.map_rgb((255, 0, 0)))
self.assertEqual(ar[-1, -1], sf.map_rgb((255, 0, 0)))
ar[...] = (0, 255, 0)
self.assertEqual(ar[0, 0], sf.map_rgb((0, 255, 0)))
self.assertEqual(ar[1, 0], sf.map_rgb((0, 255, 0)))
self.assertEqual(ar[-1, -1], sf.map_rgb((0, 255, 0)))
# Ensure x and y are freed for array[x, y] = p
# Bug fix: reference counting
if hasattr(sys, "getrefcount"):
class Int(int):
"""Unique int instances"""
pass
sf = pygame.Surface((2, 2), 0, 32)
ar = pygame.PixelArray(sf)
x, y = Int(0), Int(1)
rx_before, ry_before = sys.getrefcount(x), sys.getrefcount(y)
ar[x, y] = 0
rx_after, ry_after = sys.getrefcount(x), sys.getrefcount(y)
self.assertEqual(rx_after, rx_before)
self.assertEqual(ry_after, ry_before)
def test_pixels_field(self):
for bpp in [1, 2, 3, 4]:
sf = pygame.Surface((11, 7), 0, bpp * 8)
ar = pygame.PixelArray(sf)
ar2 = ar[1:, :]
self.assertEqual(ar2._pixels_address - ar._pixels_address, ar.itemsize)
ar2 = ar[:, 1:]
self.assertEqual(ar2._pixels_address - ar._pixels_address, ar.strides[1])
ar2 = ar[::-1, :]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
(ar.shape[0] - 1) * ar.itemsize,
)
ar2 = ar[::-2, :]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
(ar.shape[0] - 1) * ar.itemsize,
)
ar2 = ar[:, ::-1]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
(ar.shape[1] - 1) * ar.strides[1],
)
ar3 = ar2[::-1, :]
self.assertEqual(
ar3._pixels_address - ar._pixels_address,
(ar.shape[0] - 1) * ar.strides[0] + (ar.shape[1] - 1) * ar.strides[1],
)
ar2 = ar[:, ::-2]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
(ar.shape[1] - 1) * ar.strides[1],
)
ar2 = ar[2::, 3::]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
ar.strides[0] * 2 + ar.strides[1] * 3,
)
ar2 = ar[2::2, 3::4]
self.assertEqual(
ar2._pixels_address - ar._pixels_address,
ar.strides[0] * 2 + ar.strides[1] * 3,
)
ar2 = ar[9:2:-1, :]
self.assertEqual(
ar2._pixels_address - ar._pixels_address, ar.strides[0] * 9
)
ar2 = ar[:, 5:2:-1]
self.assertEqual(
ar2._pixels_address - ar._pixels_address, ar.strides[1] * 5
)
##? ar2 = ar[:,9:2:-1]
def test_make_surface(self):
bg_color = pygame.Color(255, 255, 255)
fg_color = pygame.Color(128, 100, 0)
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 20), 0, bpp)
bg_color_adj = sf.unmap_rgb(sf.map_rgb(bg_color))
fg_color_adj = sf.unmap_rgb(sf.map_rgb(fg_color))
sf.fill(bg_color_adj)
sf.fill(fg_color_adj, (2, 5, 4, 11))
ar = pygame.PixelArray(sf)
newsf = ar[::2, ::2].make_surface()
rect = newsf.get_rect()
self.assertEqual(rect.width, 5)
self.assertEqual(rect.height, 10)
for p in [
(0, 2),
(0, 3),
(1, 2),
(2, 2),
(3, 2),
(3, 3),
(0, 7),
(0, 8),
(1, 8),
(2, 8),
(3, 8),
(3, 7),
]:
self.assertEqual(newsf.get_at(p), bg_color_adj)
for p in [(1, 3), (2, 3), (1, 5), (2, 5), (1, 7), (2, 7)]:
self.assertEqual(newsf.get_at(p), fg_color_adj)
# Bug when array width is not a multiple of the slice step.
w = 17
lst = list(range(w))
w_slice = len(lst[::2])
h = 3
sf = pygame.Surface((w, h), 0, 32)
ar = pygame.PixelArray(sf)
ar2 = ar[::2, :]
sf2 = ar2.make_surface()
w2, h2 = sf2.get_size()
self.assertEqual(w2, w_slice)
self.assertEqual(h2, h)
# Bug when array height is not a multiple of the slice step.
# This can hang the Python interpreter.
h = 17
lst = list(range(h))
h_slice = len(lst[::2])
w = 3
sf = pygame.Surface((w, h), 0, 32)
ar = pygame.PixelArray(sf)
ar2 = ar[:, ::2]
sf2 = ar2.make_surface() # Hangs here.
w2, h2 = sf2.get_size()
self.assertEqual(w2, w)
self.assertEqual(h2, h_slice)
def test_make_surface__subclassed_surface(self):
"""Ensure make_surface can handle subclassed surfaces."""
expected_size = (3, 5)
expected_flags = 0
expected_depth = 32
original_surface = SurfaceSubclass(
expected_size, expected_flags, expected_depth
)
pixelarray = pygame.PixelArray(original_surface)
surface = pixelarray.make_surface()
self.assertIsNot(surface, original_surface)
self.assertIsInstance(surface, pygame.Surface)
self.assertNotIsInstance(surface, SurfaceSubclass)
self.assertEqual(surface.get_size(), expected_size)
self.assertEqual(surface.get_flags(), expected_flags)
self.assertEqual(surface.get_bitsize(), expected_depth)
def test_iter(self):
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((5, 10), 0, bpp)
ar = pygame.PixelArray(sf)
iterations = 0
for col in ar:
self.assertEqual(len(col), 10)
iterations += 1
self.assertEqual(iterations, 5)
def test_replace(self):
# print("replace start")
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 10), 0, bpp)
sf.fill((255, 0, 0))
rval = sf.map_rgb((0, 0, 255))
oval = sf.map_rgb((255, 0, 0))
ar = pygame.PixelArray(sf)
ar[::2].replace((255, 0, 0), (0, 0, 255))
self.assertEqual(ar[0][0], rval)
self.assertEqual(ar[1][0], oval)
self.assertEqual(ar[2][3], rval)
self.assertEqual(ar[3][6], oval)
self.assertEqual(ar[8][9], rval)
self.assertEqual(ar[9][9], oval)
ar[::2].replace((0, 0, 255), (255, 0, 0), weights=(10, 20, 50))
self.assertEqual(ar[0][0], oval)
self.assertEqual(ar[2][3], oval)
self.assertEqual(ar[3][6], oval)
self.assertEqual(ar[8][9], oval)
self.assertEqual(ar[9][9], oval)
# print("replace end")
def test_extract(self):
# print("extract start")
for bpp in (8, 16, 24, 32):
sf = pygame.Surface((10, 10), 0, bpp)
sf.fill((0, 0, 255))
sf.fill((255, 0, 0), (2, 2, 6, 6))
white = sf.map_rgb((255, 255, 255))
black = sf.map_rgb((0, 0, 0))
ar = pygame.PixelArray(sf)
newar = ar.extract((255, 0, 0))
self.assertEqual(newar[0][0], black)
self.assertEqual(newar[1][0], black)
self.assertEqual(newar[2][3], white)
self.assertEqual(newar[3][6], white)
self.assertEqual(newar[8][9], black)
self.assertEqual(newar[9][9], black)
newar = ar.extract((255, 0, 0), weights=(10, 0.1, 50))
self.assertEqual(newar[0][0], black)
self.assertEqual(newar[1][0], black)
self.assertEqual(newar[2][3], white)
self.assertEqual(newar[3][6], white)
self.assertEqual(newar[8][9], black)
self.assertEqual(newar[9][9], black)
# print("extract end")
def test_2dslice_assignment(self):
w = 2 * 5 * 8
h = 3 * 5 * 9
sf = pygame.Surface((w, h), 0, 32)
ar = pygame.PixelArray(sf)
size = (w, h)
strides = (1, w)
offset = 0
self._test_assignment(sf, ar, size, strides, offset)
xslice = slice(None, None, 2)
yslice = slice(None, None, 3)
ar, size, strides, offset = self._array_slice(
ar, size, (xslice, yslice), strides, offset
)
self._test_assignment(sf, ar, size, strides, offset)
xslice = slice(5, None, 5)
yslice = slice(5, None, 5)
ar, size, strides, offset = self._array_slice(
ar, size, (xslice, yslice), strides, offset
)
self._test_assignment(sf, ar, size, strides, offset)
def _test_assignment(self, sf, ar, ar_size, ar_strides, ar_offset):
self.assertEqual(ar.shape, ar_size)
ar_w, ar_h = ar_size
ar_xstride, ar_ystride = ar_strides
sf_w, sf_h = sf.get_size()
black = pygame.Color("black")
color = pygame.Color(0, 0, 12)
pxcolor = sf.map_rgb(color)
sf.fill(black)
for ar_x, ar_y in [
(0, 0),
(0, ar_h - 4),
(ar_w - 3, 0),
(0, ar_h - 1),
(ar_w - 1, 0),
(ar_w - 1, ar_h - 1),
]:
sf_offset = ar_offset + ar_x * ar_xstride + ar_y * ar_ystride
sf_y = sf_offset // sf_w
sf_x = sf_offset - sf_y * sf_w
sf_posn = (sf_x, sf_y)
sf_pix = sf.get_at(sf_posn)
self.assertEqual(
sf_pix,
black,
"at pixarr posn (%i, %i) (surf posn (%i, %i)): "
"%s != %s" % (ar_x, ar_y, sf_x, sf_y, sf_pix, black),
)
ar[ar_x, ar_y] = pxcolor
sf_pix = sf.get_at(sf_posn)
self.assertEqual(
sf_pix,
color,
"at pixarr posn (%i, %i) (surf posn (%i, %i)): "
"%s != %s" % (ar_x, ar_y, sf_x, sf_y, sf_pix, color),
)
def _array_slice(self, ar, size, slices, strides, offset):
ar = ar[slices]
xslice, yslice = slices
w, h = size
xstart, xstop, xstep = xslice.indices(w)
ystart, ystop, ystep = yslice.indices(h)
w = (xstop - xstart + xstep - 1) // xstep
h = (ystop - ystart + ystep - 1) // ystep
xstride, ystride = strides
offset += xstart * xstride + ystart * ystride
xstride *= xstep
ystride *= ystep
return ar, (w, h), (xstride, ystride), offset
def test_array_properties(self):
# itemsize, ndim, shape, and strides.
for bpp in [1, 2, 3, 4]:
sf = pygame.Surface((2, 2), 0, bpp * 8)
ar = pygame.PixelArray(sf)
self.assertEqual(ar.itemsize, bpp)
for shape in [(4, 16), (5, 13)]:
w, h = shape
sf = pygame.Surface(shape, 0, 32)
bpp = sf.get_bytesize()
pitch = sf.get_pitch()
ar = pygame.PixelArray(sf)
self.assertEqual(ar.ndim, 2)
self.assertEqual(ar.shape, shape)
self.assertEqual(ar.strides, (bpp, pitch))
ar2 = ar[::2, :]
w2 = len(([0] * w)[::2])
self.assertEqual(ar2.ndim, 2)
self.assertEqual(ar2.shape, (w2, h))
self.assertEqual(ar2.strides, (2 * bpp, pitch))
ar2 = ar[:, ::2]
h2 = len(([0] * h)[::2])
self.assertEqual(ar2.ndim, 2)
self.assertEqual(ar2.shape, (w, h2))
self.assertEqual(ar2.strides, (bpp, 2 * pitch))
ar2 = ar[1]
self.assertEqual(ar2.ndim, 1)
self.assertEqual(ar2.shape, (h,))
self.assertEqual(ar2.strides, (pitch,))
ar2 = ar[:, 1]
self.assertEqual(ar2.ndim, 1)
self.assertEqual(ar2.shape, (w,))
self.assertEqual(ar2.strides, (bpp,))
def test_self_assign(self):
# This differs from NumPy arrays.
w = 10
max_x = w - 1
h = 20
max_y = h - 1
for bpp in [1, 2, 3, 4]:
sf = pygame.Surface((w, h), 0, bpp * 8)
ar = pygame.PixelArray(sf)
for i in range(w * h):
ar[i % w, i // w] = i
ar[:, :] = ar[::-1, :]
for i in range(w * h):
self.assertEqual(ar[max_x - i % w, i // w], i)
ar = pygame.PixelArray(sf)
for i in range(w * h):
ar[i % w, i // w] = i
ar[:, :] = ar[:, ::-1]
for i in range(w * h):
self.assertEqual(ar[i % w, max_y - i // w], i)
ar = pygame.PixelArray(sf)
for i in range(w * h):
ar[i % w, i // w] = i
ar[:, :] = ar[::-1, ::-1]
for i in range(w * h):
self.assertEqual(ar[max_x - i % w, max_y - i // w], i)
def test_color_value(self):
# Confirm that a PixelArray slice assignment distinguishes between
# pygame.Color and tuple objects as single (r, g, b[, a]) colors
# and other sequences as sequences of colors to be treated as
# slices.
sf = pygame.Surface((5, 5), 0, 32)
ar = pygame.PixelArray(sf)
index = slice(None, None, 1)
ar.__setitem__(index, (1, 2, 3))
self.assertEqual(ar[0, 0], sf.map_rgb((1, 2, 3)))
ar.__setitem__(index, pygame.Color(10, 11, 12))
self.assertEqual(ar[0, 0], sf.map_rgb((10, 11, 12)))
self.assertRaises(ValueError, ar.__setitem__, index, (1, 2, 3, 4, 5))
self.assertRaises(ValueError, ar.__setitem__, (index, index), (1, 2, 3, 4, 5))
self.assertRaises(ValueError, ar.__setitem__, index, [1, 2, 3])
self.assertRaises(ValueError, ar.__setitem__, (index, index), [1, 2, 3])
sf = pygame.Surface((3, 3), 0, 32)
ar = pygame.PixelArray(sf)
ar[:] = (20, 30, 40)
self.assertEqual(ar[0, 0], sf.map_rgb((20, 30, 40)))
ar[:] = [20, 30, 40]
self.assertEqual(ar[0, 0], 20)
self.assertEqual(ar[1, 0], 30)
self.assertEqual(ar[2, 0], 40)
def test_transpose(self):
# PixelArray.transpose(): swap axis on a 2D array, add a length
# 1 x axis to a 1D array.
sf = pygame.Surface((3, 7), 0, 32)
ar = pygame.PixelArray(sf)
w, h = ar.shape
dx, dy = ar.strides
for i in range(w * h):
x = i % w
y = i // w
ar[x, y] = i
ar_t = ar.transpose()
self.assertEqual(ar_t.shape, (h, w))
self.assertEqual(ar_t.strides, (dy, dx))
for i in range(w * h):
x = i % w
y = i // w
self.assertEqual(ar_t[y, x], ar[x, y])
ar1D = ar[0]
ar2D = ar1D.transpose()
self.assertEqual(ar2D.shape, (1, h))
for y in range(h):
self.assertEqual(ar1D[y], ar2D[0, y])
ar1D = ar[:, 0]
ar2D = ar1D.transpose()
self.assertEqual(ar2D.shape, (1, w))
for x in range(2):
self.assertEqual(ar1D[x], ar2D[0, x])
def test_length_1_dimension_broadcast(self):
w = 5
sf = pygame.Surface((w, w), 0, 32)
ar = pygame.PixelArray(sf)
# y-axis broadcast.
sf_x = pygame.Surface((w, 1), 0, 32)
ar_x = pygame.PixelArray(sf_x)
for i in range(w):
ar_x[i, 0] = (w + 1) * 10
ar[...] = ar_x
for y in range(w):
for x in range(w):
self.assertEqual(ar[x, y], ar_x[x, 0])
# x-axis broadcast.
ar[...] = 0
sf_y = pygame.Surface((1, w), 0, 32)
ar_y = pygame.PixelArray(sf_y)
for i in range(w):
ar_y[0, i] = (w + 1) * 10
ar[...] = ar_y
for x in range(w):
for y in range(w):
self.assertEqual(ar[x, y], ar_y[0, y])
# (1, 1) array broadcast.
ar[...] = 0
sf_1px = pygame.Surface((1, 1), 0, 32)
ar_1px = pygame.PixelArray(sf_1px)
ar_1px[0, 0] = 42 # Well it had to show up somewhere.
ar[...] = ar_1px
for y in range(w):
for x in range(w):
self.assertEqual(ar[x, y], 42)
def test_assign_size_mismatch(self):
sf = pygame.Surface((7, 11), 0, 32)
ar = pygame.PixelArray(sf)
self.assertRaises(ValueError, ar.__setitem__, Ellipsis, ar[:, 0:2])
self.assertRaises(ValueError, ar.__setitem__, Ellipsis, ar[0:2, :])
def test_repr(self):
# Python 3.x bug: the tp_repr slot function returned NULL instead
# of a Unicode string, triggering an exception.
sf = pygame.Surface((3, 1), pygame.SRCALPHA, 16)
ar = pygame.PixelArray(sf)
ar[...] = 42
pixel = sf.get_at_mapped((0, 0))
self.assertEqual(repr(ar), type(ar).__name__ + "([\n [42, 42, 42]]\n)")
@unittest.skipIf(IS_PYPY, "pypy having issues")
class PixelArrayArrayInterfaceTest(unittest.TestCase, TestMixin):
@unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)")
def test_basic(self):
# Check unchanging fields.
sf = pygame.Surface((2, 2), 0, 32)
ar = pygame.PixelArray(sf)
ai = arrinter.ArrayInterface(ar)
self.assertEqual(ai.two, 2)
self.assertEqual(ai.typekind, "u")
self.assertEqual(ai.nd, 2)
self.assertEqual(ai.data, ar._pixels_address)
@unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)")
def test_shape(self):
for shape in [[4, 16], [5, 13]]:
w, h = shape
sf = pygame.Surface(shape, 0, 32)
ar = pygame.PixelArray(sf)
ai = arrinter.ArrayInterface(ar)
ai_shape = [ai.shape[i] for i in range(ai.nd)]
self.assertEqual(ai_shape, shape)
ar2 = ar[::2, :]
ai2 = arrinter.ArrayInterface(ar2)
w2 = len(([0] * w)[::2])
ai_shape = [ai2.shape[i] for i in range(ai2.nd)]
self.assertEqual(ai_shape, [w2, h])
ar2 = ar[:, ::2]
ai2 = arrinter.ArrayInterface(ar2)
h2 = len(([0] * h)[::2])
ai_shape = [ai2.shape[i] for i in range(ai2.nd)]
self.assertEqual(ai_shape, [w, h2])
@unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)")
def test_itemsize(self):
for bytes_per_pixel in range(1, 5):
bits_per_pixel = 8 * bytes_per_pixel
sf = pygame.Surface((2, 2), 0, bits_per_pixel)
ar = pygame.PixelArray(sf)
ai = arrinter.ArrayInterface(ar)
self.assertEqual(ai.itemsize, bytes_per_pixel)
@unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)")
def test_flags(self):
aim = arrinter
common_flags = aim.PAI_NOTSWAPPED | aim.PAI_WRITEABLE | aim.PAI_ALIGNED
s = pygame.Surface((10, 2), 0, 32)
ar = pygame.PixelArray(s)
ai = aim.ArrayInterface(ar)
self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN)
ar2 = ar[::2, :]
ai = aim.ArrayInterface(ar2)
self.assertEqual(ai.flags, common_flags)
s = pygame.Surface((8, 2), 0, 24)
ar = pygame.PixelArray(s)
ai = aim.ArrayInterface(ar)
self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN)
s = pygame.Surface((7, 2), 0, 24)
ar = pygame.PixelArray(s)
ai = aim.ArrayInterface(ar)
self.assertEqual(ai.flags, common_flags)
def test_slicing(self):
# This will implicitly test data and strides fields.
#
# Need an 8 bit test surfaces because pixelcopy.make_surface
# returns an 8 bit surface for a 2d array.
factors = [7, 3, 11]
w = reduce(operator.mul, factors, 1)
h = 13
sf = pygame.Surface((w, h), 0, 8)
color = sf.map_rgb((1, 17, 128))
ar = pygame.PixelArray(sf)
for f in factors[:-1]:
w = w // f
sf.fill((0, 0, 0))
ar = ar[f : f + w, :]
ar[0][0] = color
ar[-1][-2] = color
ar[0][-3] = color
sf2 = ar.make_surface()
sf3 = pygame.pixelcopy.make_surface(ar)
self.assert_surfaces_equal(sf3, sf2)
h = reduce(operator.mul, factors, 1)
w = 13
sf = pygame.Surface((w, h), 0, 8)
color = sf.map_rgb((1, 17, 128))
ar = pygame.PixelArray(sf)
for f in factors[:-1]:
h = h // f
sf.fill((0, 0, 0))
ar = ar[:, f : f + h]
ar[0][0] = color
ar[-1][-2] = color
ar[0][-3] = color
sf2 = ar.make_surface()
sf3 = pygame.pixelcopy.make_surface(ar)
self.assert_surfaces_equal(sf3, sf2)
w = 20
h = 10
sf = pygame.Surface((w, h), 0, 8)
color = sf.map_rgb((1, 17, 128))
ar = pygame.PixelArray(sf)
for slices in [
(slice(w), slice(h)),
(slice(0, w, 2), slice(h)),
(slice(0, w, 3), slice(h)),
(slice(w), slice(0, h, 2)),
(slice(w), slice(0, h, 3)),
(slice(0, w, 2), slice(0, h, 2)),
(slice(0, w, 3), slice(0, h, 3)),
]:
sf.fill((0, 0, 0))
ar2 = ar[slices]
ar2[0][0] = color
ar2[-1][-2] = color
ar2[0][-3] = color
sf2 = ar2.make_surface()
sf3 = pygame.pixelcopy.make_surface(ar2)
self.assert_surfaces_equal(sf3, sf2)
@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented")
@unittest.skipIf(IS_PYPY, "pypy having issues")
class PixelArrayNewBufferTest(unittest.TestCase, TestMixin):
if pygame.HAVE_NEWBUF:
from pygame.tests.test_utils import buftools
bitsize_to_format = {8: "B", 16: "=H", 24: "3x", 32: "=I"}
def test_newbuf_2D(self):
buftools = self.buftools
Importer = buftools.Importer
for bit_size in [8, 16, 24, 32]:
s = pygame.Surface((10, 2), 0, bit_size)
ar = pygame.PixelArray(s)
format = self.bitsize_to_format[bit_size]
itemsize = ar.itemsize
shape = ar.shape
w, h = shape
strides = ar.strides
length = w * h * itemsize
imp = Importer(ar, buftools.PyBUF_FULL)
self.assertTrue(imp.obj, ar)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 2)
self.assertEqual(imp.itemsize, itemsize)
self.assertEqual(imp.format, format)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertTrue(imp.suboffsets is None)
self.assertEqual(imp.buf, s._pixels_address)
s = pygame.Surface((8, 16), 0, 32)
ar = pygame.PixelArray(s)
format = self.bitsize_to_format[s.get_bitsize()]
itemsize = ar.itemsize
shape = ar.shape
w, h = shape
strides = ar.strides
length = w * h * itemsize
imp = Importer(ar, buftools.PyBUF_SIMPLE)
self.assertTrue(imp.obj, ar)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 0)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertTrue(imp.shape is None)
self.assertTrue(imp.strides is None)
self.assertTrue(imp.suboffsets is None)
self.assertEqual(imp.buf, s._pixels_address)
imp = Importer(ar, buftools.PyBUF_FORMAT)
self.assertEqual(imp.ndim, 0)
self.assertEqual(imp.format, format)
imp = Importer(ar, buftools.PyBUF_WRITABLE)
self.assertEqual(imp.ndim, 0)
self.assertTrue(imp.format is None)
imp = Importer(ar, buftools.PyBUF_F_CONTIGUOUS)
self.assertEqual(imp.ndim, 2)
self.assertTrue(imp.format is None)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
imp = Importer(ar, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertEqual(imp.ndim, 2)
self.assertTrue(imp.format is None)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND)
ar_sliced = ar[:, ::2]
format = self.bitsize_to_format[s.get_bitsize()]
itemsize = ar_sliced.itemsize
shape = ar_sliced.shape
w, h = shape
strides = ar_sliced.strides
length = w * h * itemsize
imp = Importer(ar_sliced, buftools.PyBUF_STRIDED)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 2)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertEqual(imp.buf, s._pixels_address)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(
BufferError, Importer, ar_sliced, buftools.PyBUF_ANY_CONTIGUOUS
)
ar_sliced = ar[::2, :]
format = self.bitsize_to_format[s.get_bitsize()]
itemsize = ar_sliced.itemsize
shape = ar_sliced.shape
w, h = shape
strides = ar_sliced.strides
length = w * h * itemsize
imp = Importer(ar_sliced, buftools.PyBUF_STRIDED)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 2)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertEqual(imp.buf, s._pixels_address)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(
BufferError, Importer, ar_sliced, buftools.PyBUF_ANY_CONTIGUOUS
)
s2 = s.subsurface((2, 3, 5, 7))
ar = pygame.PixelArray(s2)
format = self.bitsize_to_format[s.get_bitsize()]
itemsize = ar.itemsize
shape = ar.shape
w, h = shape
strides = ar.strides
length = w * h * itemsize
imp = Importer(ar, buftools.PyBUF_STRIDES)
self.assertTrue(imp.obj, ar)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 2)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertTrue(imp.suboffsets is None)
self.assertEqual(imp.buf, s2._pixels_address)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_FORMAT)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_WRITABLE)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ANY_CONTIGUOUS)
def test_newbuf_1D(self):
buftools = self.buftools
Importer = buftools.Importer
s = pygame.Surface((2, 16), 0, 32)
ar_2D = pygame.PixelArray(s)
x = 0
ar = ar_2D[x]
format = self.bitsize_to_format[s.get_bitsize()]
itemsize = ar.itemsize
shape = ar.shape
h = shape[0]
strides = ar.strides
length = h * itemsize
buf = s._pixels_address + x * itemsize
imp = Importer(ar, buftools.PyBUF_STRIDES)
self.assertTrue(imp.obj, ar)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 1)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertTrue(imp.suboffsets is None)
self.assertEqual(imp.buf, buf)
imp = Importer(ar, buftools.PyBUF_FULL)
self.assertEqual(imp.ndim, 1)
self.assertEqual(imp.format, format)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_FORMAT)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_WRITABLE)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ANY_CONTIGUOUS)
y = 10
ar = ar_2D[:, y]
shape = ar.shape
w = shape[0]
strides = ar.strides
length = w * itemsize
buf = s._pixels_address + y * s.get_pitch()
imp = Importer(ar, buftools.PyBUF_FULL)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 1)
self.assertEqual(imp.itemsize, itemsize)
self.assertEqual(imp.format, format)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertEqual(imp.strides, strides)
self.assertEqual(imp.buf, buf)
self.assertTrue(imp.suboffsets is None)
imp = Importer(ar, buftools.PyBUF_SIMPLE)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 0)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertTrue(imp.shape is None)
self.assertTrue(imp.strides is None)
imp = Importer(ar, buftools.PyBUF_ND)
self.assertEqual(imp.len, length)
self.assertEqual(imp.ndim, 1)
self.assertEqual(imp.itemsize, itemsize)
self.assertTrue(imp.format is None)
self.assertFalse(imp.readonly)
self.assertEqual(imp.shape, shape)
self.assertTrue(imp.strides is None)
imp = Importer(ar, buftools.PyBUF_C_CONTIGUOUS)
self.assertEqual(imp.ndim, 1)
imp = Importer(ar, buftools.PyBUF_F_CONTIGUOUS)
self.assertEqual(imp.ndim, 1)
imp = Importer(ar, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertEqual(imp.ndim, 1)
if __name__ == "__main__":
unittest.main()