Skip to content

Commit a55cc62

Browse files
committed
Fix snapshot tool crashes and black images for XY image items
- Fix SystemError when taking snapshots of XYImageItem/MaskedXYImageItem by converting src_rect from list to tuple before passing to C extension - Add export_roi method to XYImageItem to properly handle coordinate transformations using _scale_xy instead of _scale_rect - Fixes snapshot rendering producing black images for non-uniform coordinates
1 parent 77c210a commit a55cc62

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
* Added `IExportROIImageItemType` to `XYImageItem.types()` so that `get_items_in_rectangle()` can properly identify XY image items
99
* Updated `__implements__` tuples for consistency across `XYImageItem`, `MaskedXYImageItem`, and `MaskedImageItem`
1010
* The tool now correctly displays statistics for images with non-uniform coordinates
11+
* Fixed snapshot tool failing with `SystemError` on `XYImageItem` and `MaskedXYImageItem`:
12+
* Fixed `assemble_imageitems` passing list instead of tuple to C extension function `_scale_rect`
13+
* Added missing `export_roi` method to `XYImageItem` to properly handle non-uniform coordinate transformations
14+
* Snapshots of XY images now render correctly instead of producing black images
1115

1216
## Version 2.8.0 ##
1317

plotpy/items/image/misc.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,6 @@ def assemble_imageitems(
474474
475475
Returns:
476476
Pixel data
477-
478-
.. warning::
479-
480-
Does not support `XYImageItem` objects
481477
"""
482478
# align width to 'align' bytes
483479
if align is not None:
@@ -511,6 +507,8 @@ def assemble_imageitems(
511507
src_rect[1] += 0.5 * pixel_height
512508
src_rect[2] -= 0.5 * pixel_width
513509
src_rect[3] -= 0.5 * pixel_height
510+
# Convert to tuple for compatibility with C extension
511+
src_rect = tuple(src_rect)
514512

515513
for it in sorted(items, key=lambda obj: obj.z()):
516514
if it.isVisible() and src_qrect.intersects(it.boundingRect()):
@@ -737,11 +735,6 @@ def get_image_from_plot(
737735
738736
Returns:
739737
Image pixel data
740-
741-
.. warning::
742-
743-
Support only the image items implementing the `IExportROIImageItemType`
744-
interface, i.e. this does *not* support `XYImageItem` objects
745738
"""
746739
if destw is None:
747740
destw = p1.x() - p0.x() + 1

plotpy/items/image/standard.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,10 @@ def export_roi(
433433
else:
434434
a, b = 1.0, 0.0
435435
interp = self.interpolate if apply_interpolation else (INTERP_NEAREST,)
436+
rescaled_src = self._rescale_src_rect(src_rect)
436437
_scale_rect(
437438
self.data,
438-
self._rescale_src_rect(src_rect),
439+
rescaled_src,
439440
dst_image,
440441
dst_rect,
441442
(a, b, None),
@@ -689,6 +690,38 @@ def draw_image(
689690
qrect = QC.QRectF(QC.QPointF(dest[0], dest[1]), QC.QPointF(dest[2], dest[3]))
690691
painter.drawImage(qrect, self._image, qrect)
691692

693+
def export_roi(
694+
self,
695+
src_rect: tuple[float, float, float, float],
696+
dst_rect: tuple[float, float, float, float],
697+
dst_image: np.ndarray,
698+
apply_lut: bool = False,
699+
apply_interpolation: bool = False,
700+
original_resolution: bool = False,
701+
force_interp_mode: str | None = None,
702+
force_interp_size: int | None = None,
703+
) -> None:
704+
"""Export a rectangular area of the image to another image
705+
706+
Args:
707+
src_rect: Source rectangle in plot coordinates
708+
dst_rect: Destination rectangle in pixel coordinates
709+
dst_image: Destination image array
710+
apply_lut: Apply LUT (Default value = False)
711+
apply_interpolation: Apply interpolation (Default value = False)
712+
original_resolution: Original resolution (Default value = False)
713+
force_interp_mode: Force interpolation mode (Default value = None)
714+
force_interp_size: Force interpolation size (Default value = None)
715+
"""
716+
if apply_lut:
717+
lut = self.lut
718+
else:
719+
a, b = 1.0, 0.0
720+
lut = (a, b, None, np.zeros((1,), np.uint32))
721+
interp = self.interpolate if apply_interpolation else (INTERP_NEAREST,)
722+
xytr = self.x, self.y, src_rect
723+
_scale_xy(self.data, xytr, dst_image, dst_rect, lut, interp)
724+
692725
def get_pixel_coordinates(self, xplot: float, yplot: float) -> tuple[float, float]:
693726
"""Get pixel coordinates from plot coordinates
694727

0 commit comments

Comments
 (0)