9
9
10
10
import numpy as np
11
11
from numpy .typing import NDArray
12
- from typing_extensions import Final
12
+ from typing_extensions import Final , Literal
13
13
14
14
import tcod .sdl .video
15
15
from tcod .loader import ffi , lib
@@ -484,15 +484,33 @@ def set_vsync(self, enable: bool) -> None:
484
484
def read_pixels (
485
485
self ,
486
486
* ,
487
- rect : Optional [Tuple [int , int , int , int ]] = None ,
488
- format : Optional [int ] = None ,
489
- out : Optional [NDArray [Any ]] = None ,
490
- ) -> NDArray [Any ]:
491
- """
492
- .. versionadded:: 13.5
487
+ rect : tuple [int , int , int , int ] | None = None ,
488
+ format : int | Literal ["RGB" , "RGBA" ] = "RGBA" ,
489
+ out : NDArray [np .uint8 ] | None = None ,
490
+ ) -> NDArray [np .uint8 ]:
491
+ """Fetch the pixel contents of the current rendering target to an array.
492
+
493
+ By default returns an RGBA pixel array of the full target in the shape: ``(height, width, rgba)``.
494
+ The target can be changed with :any:`set_render_target`
495
+
496
+ Args:
497
+ rect: The ``(left, top, width, height)`` region of the target to fetch, or None for the entire target.
498
+ format: The pixel format. Defaults to ``"RGBA"``.
499
+ out: The output array.
500
+ Can be None or must be an ``np.uint8`` array of shape: ``(height, width, channels)``.
501
+ Must be C contiguous along the ``(width, channels)`` axes.
502
+
503
+ This operation is slow due to coping from VRAM to RAM.
504
+ When reading the main rendering target this should be called after rendering and before :any:`present`.
505
+ See https://wiki.libsdl.org/SDL2/SDL_RenderReadPixels
506
+
507
+ Returns:
508
+ The output uint8 array of shape: ``(height, width, channels)`` with the fetched pixels.
509
+
510
+ .. versionadded:: Unreleased
493
511
"""
494
- if format is None :
495
- format = lib . SDL_PIXELFORMAT_RGBA32
512
+ FORMATS : Final = { "RGB" : lib . SDL_PIXELFORMAT_RGB24 , "RGBA" : lib . SDL_PIXELFORMAT_RGBA32 }
513
+ sdl_format = FORMATS . get ( format ) if isinstance ( format , str ) else format
496
514
if rect is None :
497
515
texture_p = lib .SDL_GetRenderTarget (self .p )
498
516
if texture_p :
@@ -502,15 +520,31 @@ def read_pixels(
502
520
rect = (0 , 0 , * self .output_size )
503
521
width , height = rect [2 :4 ]
504
522
if out is None :
505
- if format == lib .SDL_PIXELFORMAT_RGBA32 :
523
+ if sdl_format == lib .SDL_PIXELFORMAT_RGBA32 :
506
524
out = np .empty ((height , width , 4 ), dtype = np .uint8 )
507
- elif format == lib .SDL_PIXELFORMAT_RGB24 :
525
+ elif sdl_format == lib .SDL_PIXELFORMAT_RGB24 :
508
526
out = np .empty ((height , width , 3 ), dtype = np .uint8 )
509
527
else :
510
- raise TypeError ("Pixel format not supported yet." )
511
- assert out .shape [:2 ] == (height , width )
512
- assert out [0 ].flags .c_contiguous
513
- _check (lib .SDL_RenderReadPixels (self .p , format , ffi .cast ("void*" , out .ctypes .data ), out .strides [0 ]))
528
+ msg = f"Pixel format { format !r} not supported by tcod."
529
+ raise TypeError (msg )
530
+ if out .dtype != np .uint8 :
531
+ msg = "`out` must be a uint8 array."
532
+ raise TypeError (msg )
533
+ expected_shape = (height , width , {lib .SDL_PIXELFORMAT_RGB24 : 3 , lib .SDL_PIXELFORMAT_RGBA32 : 4 }[sdl_format ])
534
+ if out .shape != expected_shape :
535
+ msg = f"Expected `out` to be an array of shape { expected_shape } , got { out .shape } instead."
536
+ raise TypeError (msg )
537
+ if not out [0 ].flags .c_contiguous :
538
+ msg = "`out` array must be C contiguous."
539
+ _check (
540
+ lib .SDL_RenderReadPixels (
541
+ self .p ,
542
+ (rect ,),
543
+ sdl_format ,
544
+ ffi .cast ("void*" , out .ctypes .data ),
545
+ out .strides [0 ],
546
+ )
547
+ )
514
548
return out
515
549
516
550
def clear (self ) -> None :
@@ -522,6 +556,7 @@ def clear(self) -> None:
522
556
523
557
def fill_rect (self , rect : Tuple [float , float , float , float ]) -> None :
524
558
"""Fill a rectangle with :any:`draw_color`.
559
+
525
560
.. versionadded:: 13.5
526
561
"""
527
562
_check (lib .SDL_RenderFillRectF (self .p , (rect ,)))
0 commit comments