From dc5db75e93b6b0a14c8e1d4fbcc6f885ad7cac79 Mon Sep 17 00:00:00 2001 From: geisserml Date: Sun, 27 Oct 2024 00:20:59 +0200 Subject: [PATCH] `PdfBitmap.to_numpy()` Use 2d shape for single-channel bitmap --- docs/devel/changelog_staging.md | 1 + src/pypdfium2/_helpers/bitmap.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/devel/changelog_staging.md b/docs/devel/changelog_staging.md index c2c164438..5309188d5 100644 --- a/docs/devel/changelog_staging.md +++ b/docs/devel/changelog_staging.md @@ -9,6 +9,7 @@ - Rendering / Bitmap * Removed `PdfDocument.render()` (see deprecation rationale in v4.25 changelog). Instead, use `PdfPage.render()` with a loop or process pool. * Removed `PdfBitmap.get_info()` and `PdfBitmapInfo`, which existed only on behalf of data transfer with `PdfDocument.render()`. + * `PdfBitmap.to_numpy()`: If the bitmap is single-channel (grayscale), use a 2d shape to avoid needlessly wrapping each pixel value in a list. * `PdfBitmap.from_pil()`: Removed `recopy` param. * Removed pdfium color scheme param from rendering, as it's not really useful: one can only set colors for certain object types, which are then forced on all instances of that type. This may flatten different colors into one, leading to a loss of visual information. To achieve a "dark theme" for light PDFs, we suggest to instead post-process rendered images with selective lightness inversion, as is now implemented in pypdfium2's rendering CLI. - Pageobjects diff --git a/src/pypdfium2/_helpers/bitmap.py b/src/pypdfium2/_helpers/bitmap.py index 10e5389e1..c047791f8 100644 --- a/src/pypdfium2/_helpers/bitmap.py +++ b/src/pypdfium2/_helpers/bitmap.py @@ -197,7 +197,8 @@ def to_numpy(self): The array contains as many rows as the bitmap is high. Each row contains as many pixels as the bitmap is wide. - The length of each pixel corresponds to the number of channels. + If there is more than one channel, each pixel will be an array of values per channel (shape depth 3). + If there is only one channel, the pixels are the values of that channel directly (shape depth 2). The resulting array is supposed to share memory with the original bitmap buffer, so changes to the buffer should be reflected in the array, and vice versa. @@ -210,11 +211,11 @@ def to_numpy(self): array = numpy.ndarray( # layout: row major - shape = (self.height, self.width, self.n_channels), + shape = (self.height, self.width, self.n_channels) if self.n_channels > 1 else (self.height, self.width), dtype = ctypes.c_ubyte, buffer = self.buffer, - # number of bytes per item for each nesting level (outer->inner, i. e. row, pixel, value) - strides = (self.stride, self.n_channels, 1), + # number of bytes per item for each nesting level (outer->inner: row, pixel, value - or row, value for a single-channel bitmap) + strides = (self.stride, self.n_channels, 1) if self.n_channels > 1 else (self.stride, 1), ) return array