diff --git a/myscan/app.py b/myscan/app.py index c27b9f9..fe4f1b5 100644 --- a/myscan/app.py +++ b/myscan/app.py @@ -30,12 +30,20 @@ from .ocr import Ocr, layout, paragraph_joins, reflow, text_direction IMAGE_FILTER = "Images (*.png *.jpg *.jpeg *.tif *.tiff *.bmp *.webp)" -def to_qimage(img): - """BGR or grayscale uint8 array -> QImage (a copy).""" +def to_qimage(img, page=False): + """BGR or grayscale uint8 array -> QImage (a copy). With `page`, exact-white pixels + (the uncovered corners of a stitched page) become transparent, so when the view + rotates the page to level it those corners show the window background through.""" img = np.ascontiguousarray(img) h, w = img.shape[:2] - fmt = QImage.Format_Grayscale8 if img.ndim == 2 else QImage.Format_BGR888 - return QImage(img.data, w, h, img.strides[0], fmt).copy() + if not page: + fmt = QImage.Format_Grayscale8 if img.ndim == 2 else QImage.Format_BGR888 + return QImage(img.data, w, h, img.strides[0], fmt).copy() + bgra = cv2.cvtColor(img, cv2.COLOR_GRAY2BGRA if img.ndim == 2 else cv2.COLOR_BGR2BGRA) + uncovered = (img == 255).all(axis=-1) if img.ndim == 3 else (img == 255) + bgra[uncovered, 3] = 0 + bgra = np.ascontiguousarray(bgra) + return QImage(bgra.data, w, h, bgra.strides[0], QImage.Format_ARGB32).copy() def imread(path): @@ -90,7 +98,7 @@ class Bridge(QObject): self.start_event, self.stop_event = threading.Event(), threading.Event() def publish(self, name, bgr): - (self.frame if name == "frame" else self.page).emit(to_qimage(bgr)) + (self.frame if name == "frame" else self.page).emit(to_qimage(bgr, page=(name == "page"))) def set_status(self, **kw): self.state = {**self.state, **kw} @@ -616,8 +624,6 @@ class MainWindow(QMainWindow): self.act_boxes = act("Boxes", lambda on: self.view.show_boxes(on), "Ctrl+B", "Show recognised lines on the page", True) self.act_boxes.setChecked(True) act("Fit", lambda: self.view.fit(), "Ctrl+0", "Fit the page to the window") - act("Zoom +", lambda: self.view.zoom(1.25), QKeySequence.ZoomIn) - act("Zoom −", lambda: self.view.zoom(0.8), QKeySequence.ZoomOut) for a in (self.act_save, self.act_copy): a.setEnabled(False) @@ -735,7 +741,7 @@ class MainWindow(QMainWindow): self.page_id += 1 self.view.set_lines([]) self.view.angle = 0.0 - self.view.set_image(to_qimage(img)) + self.view.set_image(to_qimage(img, page=True)) name = os.path.basename(path) if path else "page" self.page_title = f"Page — {name} ({img.shape[1]}×{img.shape[0]})" self.page_head.setText(self.page_title) @@ -802,7 +808,7 @@ class MainWindow(QMainWindow): return if flipped: # the boxes are on the page turned the right way up self.image = np.ascontiguousarray(self.image[::-1, ::-1]) - self.view.set_image(to_qimage(self.image)) + self.view.set_image(to_qimage(self.image, page=True)) self.lines = lines self.text, spans = layout(lines) self.view.set_lines(lines, self.text, spans)