From e0b7d30fd437292c88141fb08d60681870b86c6e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 8 May 2026 17:22:58 +0300 Subject: Squashed 'subprojects/pixpat/' content from commit d444626 git-subtree-dir: subprojects/pixpat git-subtree-split: d444626e6ba988ec6d487800721e447f94b1eaf5 --- pixpat-python/tests/test_numpy.py | 110 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 pixpat-python/tests/test_numpy.py (limited to 'pixpat-python/tests/test_numpy.py') diff --git a/pixpat-python/tests/test_numpy.py b/pixpat-python/tests/test_numpy.py new file mode 100644 index 0000000..6dbd7bb --- /dev/null +++ b/pixpat-python/tests/test_numpy.py @@ -0,0 +1,110 @@ +"""Empirical check that pixpat works correctly with numpy. + +pixpat does not depend on numpy. This file proves that ndarrays work +as ``Buffer`` planes through the buffer protocol, in the shapes a +caller would typically use. Skipped when numpy is missing. +""" + +import pixpat +import pytest + +np = pytest.importorskip('numpy') + + +def test_xrgb8888_into_uint8_3d_ndarray(): + w, h = 64, 32 + arr = np.zeros((h, w, 4), dtype=np.uint8) + pixpat.draw_pattern(pixpat.Buffer([arr], 'XRGB8888', w, h, [arr.strides[0]]), 'smpte') + assert arr.any() + + +def test_abgr16161616_into_uint16_3d_ndarray(): + w, h = 64, 32 + arr = np.zeros((h, w, 4), dtype=np.uint16) + pixpat.draw_pattern(pixpat.Buffer([arr], 'ABGR16161616', w, h, [arr.strides[0]]), 'smpte') + assert arr.any() + assert arr.dtype == np.uint16 + + +def test_nv12_into_two_ndarrays(): + w, h = 64, 32 + y = np.zeros((h, w), dtype=np.uint8) + uv = np.zeros((h // 2, w), dtype=np.uint8) # interleaved U,V at half-height + pixpat.draw_pattern( + pixpat.Buffer( + planes=[y, uv], + fmt='NV12', + width=w, + height=h, + strides=[y.strides[0], uv.strides[0]], + ), + 'smpte', + ) + assert y.any() + assert uv.any() + + +def test_convert_with_readonly_ndarray_src(): + """A numpy view with writeable=False must work as the convert source.""" + w, h = 64, 32 + src = np.zeros((h, w, 4), dtype=np.uint8) + pixpat.draw_pattern(pixpat.Buffer([src], 'XRGB8888', w, h, [src.strides[0]]), 'smpte') + src.flags.writeable = False + + dst = np.zeros((h, w, 4), dtype=np.uint16) + pixpat.convert( + pixpat.Buffer([dst], 'ABGR16161616', w, h, [dst.strides[0]]), + pixpat.Buffer([src], 'XRGB8888', w, h, [src.strides[0]]), + ) + assert dst.any() + + +def test_roundtrip_ndarrays_byte_for_byte(): + """End-to-end XRGB8888 -> ABGR16161616 -> XRGB8888 with ndarrays only.""" + w, h = 64, 32 + src = np.zeros((h, w, 4), dtype=np.uint8) + mid = np.zeros((h, w, 4), dtype=np.uint16) + dst = np.zeros((h, w, 4), dtype=np.uint8) + + pixpat.draw_pattern(pixpat.Buffer([src], 'XRGB8888', w, h, [src.strides[0]]), 'smpte') + pixpat.convert( + pixpat.Buffer([mid], 'ABGR16161616', w, h, [mid.strides[0]]), + pixpat.Buffer([src], 'XRGB8888', w, h, [src.strides[0]]), + ) + pixpat.convert( + pixpat.Buffer([dst], 'XRGB8888', w, h, [dst.strides[0]]), + pixpat.Buffer([mid], 'ABGR16161616', w, h, [mid.strides[0]]), + ) + assert np.array_equal(src, dst) + + +def test_writable_view_via_view_method(): + """`arr.view()` shares memory and is writable by default — drawing into + it must update the original.""" + w, h = 64, 32 + arr = np.zeros((h, w, 4), dtype=np.uint8) + view = arr.view() + pixpat.draw_pattern(pixpat.Buffer([view], 'XRGB8888', w, h, [view.strides[0]]), 'smpte') + assert arr.any() # the original sees the writes + + +def test_noncontiguous_source_smoke(): + """Discovery test: what happens if the caller hands us a non-C-contiguous + array? pixpat reads ``stride`` bytes per row, so any row-contiguous + layout where ``arr.strides[0]`` is the row stride should work; a + transposed array (where rows aren't even contiguous) is misuse. + + This test passes a *valid* row-contiguous slice — the top half of a + bigger image, taken via slicing — and expects success. It exists to + document the contract: 'rows must be contiguous in memory; pass + arr.strides[0] as the stride'. + """ + big = np.zeros((64, 64, 4), dtype=np.uint8) + top_half = big[:32] # shape (32, 64, 4); rows still C-contiguous + assert top_half.strides[0] == 64 * 4 + pixpat.draw_pattern( + pixpat.Buffer([top_half], 'XRGB8888', 64, 32, [top_half.strides[0]]), + 'smpte', + ) + assert big[:32].any() + assert not big[32:].any() # the other half stayed untouched -- cgit v1.2.3