An image on the canvas, loaded from a file path. SVG files are rendered via QSvgRenderer at full vector quality. PDF files are rasterised via QPdfDocument. All other formats are loaded directly as a QPixmap. display_width / display_height are in scene units. The image is
| 16 | |
| 17 | |
| 18 | class ImageItem(QGraphicsItem): |
| 19 | """ |
| 20 | An image on the canvas, loaded from a file path. |
| 21 | |
| 22 | SVG files are rendered via QSvgRenderer at full vector quality. |
| 23 | PDF files are rasterised via QPdfDocument. |
| 24 | All other formats are loaded directly as a QPixmap. |
| 25 | |
| 26 | display_width / display_height are in scene units. The image is |
| 27 | reloaded from disk each time from_data() restores the scene, so the |
| 28 | canvas stays in sync with the source file. |
| 29 | |
| 30 | Double-click opens a dialog to change the file or resize. |
| 31 | """ |
| 32 | |
| 33 | def __init__(self, file_path: str, display_width: int, display_height: int, |
| 34 | pos: QPointF = QPointF(0, 0)): |
| 35 | super().__init__() |
| 36 | self.file_path: str = file_path |
| 37 | self.display_width: int = display_width |
| 38 | self.display_height: int = display_height |
| 39 | self.setPos(pos) |
| 40 | self.setFlag(QGraphicsItem.ItemIsSelectable) |
| 41 | self.setFlag(QGraphicsItem.ItemIsMovable) |
| 42 | self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) |
| 43 | self._renderer = None # QSvgRenderer for SVG files |
| 44 | self._pixmap: QPixmap | None = None # QPixmap for raster / PDF |
| 45 | _live_image_items.add(self) |
| 46 | self._load() |
| 47 | |
| 48 | def rescale(self, ratio: float) -> None: |
| 49 | self.prepareGeometryChange() |
| 50 | self.display_width = max(1, round(self.display_width * ratio)) |
| 51 | self.display_height = max(1, round(self.display_height * ratio)) |
| 52 | if self._pixmap is not None: |
| 53 | self._load() # reload raster/PDF pixmap at new size |
| 54 | self.update() |
| 55 | |
| 56 | # ── loading ─────────────────────────────────────────────────────────────── |
| 57 | |
| 58 | def _load(self) -> None: |
| 59 | ext = Path(self.file_path).suffix.lower() |
| 60 | w, h = max(1, self.display_width), max(1, self.display_height) |
| 61 | |
| 62 | if ext == ".svg": |
| 63 | from PySide6.QtSvg import QSvgRenderer |
| 64 | renderer = QSvgRenderer(self.file_path) |
| 65 | if renderer.isValid(): |
| 66 | self._renderer = renderer |
| 67 | self._pixmap = None |
| 68 | return |
| 69 | self._renderer = None |
| 70 | self._pixmap = self._placeholder(w, h) |
| 71 | elif ext == ".pdf": |
| 72 | self._renderer = None |
| 73 | self._pixmap = self._load_pdf(w, h) |
| 74 | else: |
| 75 | px = QPixmap(self.file_path) |
no outgoing calls
no test coverage detected