From 5e8e03ee917e2770fd9c697ba4053ced4197ff9d Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Sun, 7 Jan 2024 17:01:21 +1100 Subject: [PATCH] Change Image to DrawingArea, allow to place a box around the text of interest --- ocr_fixed.glade | 9 +--- ocr_fixed.py | 133 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/ocr_fixed.glade b/ocr_fixed.glade index 6d33cf0..4c8a737 100644 --- a/ocr_fixed.glade +++ b/ocr_fixed.glade @@ -245,16 +245,9 @@ True in - + True False - - - True - False - a-008.png - - diff --git a/ocr_fixed.py b/ocr_fixed.py index ead4d80..64bfb5a 100755 --- a/ocr_fixed.py +++ b/ocr_fixed.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 -from gi import require_version -require_version("Gtk", "3.0") +import cairo +import math +from gi import require_version +require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkPixbuf, GObject -import sys -import os -import math + +LINE_WIDTH = 2 +NODE_RADIUS = 5 +DRAG_RADIUS = 7 class App: def __init__(self): @@ -15,34 +18,136 @@ class App: self.application_window = self.builder.get_object('application_window') self.button1 = self.builder.get_object('button1') self.button2 = self.builder.get_object('button2') - self.image = self.builder.get_object('image') + self.viewport = self.builder.get_object('viewport') self.application_window.connect('destroy', Gtk.main_quit) + # see https://stackoverflow.com/questions/24844489/how-to-use-gdk-device-get-position + # this requires GTK+ 3.20+ + self.pointer = Gdk.Display.get_default().get_default_seat().get_pointer() + self.button1.connect('button_press_event', self.on_button1_press) self.button1.connect('button_release_event', self.on_button1_release) self.button2.connect('button_press_event', self.on_button2_press) self.button2.connect('button_release_event', self.on_button2_release) + # see https://gitlab.gnome.org/GNOME/pygobject/-/blob/master/examples/demo/demos/drawingarea.py + # has to be done before the DrawingArea is realized, don't use Glade + self.drawing_area = Gtk.DrawingArea() + self.drawing_area.set_property('visible', True) + self.drawing_area.set_property('can-focus', True) + self.drawing_area.set_events( + self.drawing_area.get_events() | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.POINTER_MOTION_HINT_MASK + ) + self.viewport.add(self.drawing_area) + + self.set_image('a-008.png') + self.drawing_area.connect('draw', self.on_draw) + self.drawing_area.connect('button_press_event', self.on_button_press) + self.drawing_area.connect('button_release_event', self.on_button_release) + self.drawing_area.connect('motion_notify_event', self.on_motion_notify) + + self.nodes = [] + self.node = -1 + def on_button1_press(self, button, event): - self.button1.set_active(True) - self.button2.set_active(False) - self.image.set_from_file('a-008.png') + if event.button == 1: + self.button1.set_active(True) + self.button2.set_active(False) + self.set_image('a-008.png') return True def on_button1_release(self, button, event): return True - + def on_button2_press(self, button, event): - self.button1.set_active(False) - self.button2.set_active(True) - self.image.set_from_file('a-009.png') + if event.button == 1: + self.button1.set_active(False) + self.button2.set_active(True) + self.set_image('a-009.png') return True def on_button2_release(self, button, event): return True + def set_image(self, file_png): + self.surface = cairo.ImageSurface.create_from_png(file_png) + self.drawing_area.set_size_request( + self.surface.get_width(), + self.surface.get_height() + ) + self.drawing_area.queue_draw_area( + 0, + 0, + self.surface.get_width(), + self.surface.get_height() + ) + + def on_draw(self, area, context): + context.set_source_surface(self.surface, 0., 0.) + context.paint() + + if len(self.nodes): + context.set_source_rgb(1., 0., 0.) + for nx, ny in self.nodes: + context.arc(nx, ny, NODE_RADIUS, -math.pi, math.pi) + context.fill() + + context.set_line_width(LINE_WIDTH) + nx, ny = self.nodes[-1] + context.move_to(nx, ny) + for nx, ny in self.nodes: + context.line_to(nx, ny) + context.stroke() + + return True + + def on_button_press(self, button, event): + if event.button == 1: + (window, x, y, state) = event.window.get_device_position(self.pointer) + for i in range(len(self.nodes)): + nx, ny = self.nodes[i] + if (x - nx) ** 2 + (y - ny) ** 2 < DRAG_RADIUS ** 2: + self.node = i + self.nodes[i] = (x, y) + break + else: + self.node = len(self.nodes) + self.nodes.append((x, y)) + self.drawing_area.queue_draw_area( + 0, + 0, + self.surface.get_width(), + self.surface.get_height() + ) + return True + + def on_button_release(self, button, event): + if event.button == 1: + self.node = -1 + return True + + def on_motion_notify(self, drawing_area, event): + # see https://gitlab.gnome.org/GNOME/pygobject/-/blob/master/examples/demo/demos/drawingarea.py + # Gdk.Window.get_device_pointer() is deprecated, use get_device_position() + (window, x, y, state) = event.window.get_device_position(self.pointer) + + if state & Gdk.ModifierType.BUTTON1_MASK: + if self.node >= 0: + self.nodes[self.node] = (x, y) + self.drawing_area.queue_draw_area( + 0, + 0, + self.surface.get_width(), + self.surface.get_height() + ) + return True + app = App() app.application_window.set_position(Gtk.WindowPosition.CENTER) -app.application_window.present() +app.application_window.present() Gtk.main() -- 2.34.1