Skip to content

Commit 8d87983

Browse files
committed
Try fix icon in image-mode
1 parent 711816b commit 8d87983

9 files changed

Lines changed: 204 additions & 30 deletions

File tree

src/bigocrpdf/__init__.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,44 @@ def main() -> int:
181181
return 1
182182

183183

184-
__all__ = ["main", "__version__", "__author__", "__license__", "setup_i18n"]
184+
def main_image() -> int:
185+
"""Entry point for the Image OCR application (standalone).
186+
187+
This uses a separate application_id for proper Wayland taskbar grouping.
188+
189+
Returns:
190+
The application exit code.
191+
"""
192+
# 1. Setup Python compatibility first
193+
_setup_python_compatibility()
194+
195+
# 2. Setup Locale
196+
setup_i18n()
197+
198+
# 3. Import the standalone image application
199+
from bigocrpdf.image_application import ImageOcrApp
200+
from bigocrpdf.utils.logger import logger
201+
202+
# 4. Check dependencies
203+
if not _check_gtk_dependencies():
204+
return 1
205+
206+
# Check OCR dependencies
207+
ocr_ok, ocr_error = _check_ocr_dependencies()
208+
if not ocr_ok:
209+
logger.error(f"OCR Dependency Error: {ocr_error}")
210+
print(f"\n*** OCR Dependency Error ***\n{ocr_error}\n", file=sys.stderr)
211+
212+
# 5. Run application with its own application_id
213+
try:
214+
app = ImageOcrApp()
215+
return app.run(sys.argv)
216+
except Exception as e:
217+
logger.error(f"Critical error starting Image OCR: {e}")
218+
return 1
219+
220+
221+
__all__ = ["main", "main_image", "__version__", "__author__", "__license__", "setup_i18n"]
185222

186223

187224
if __name__ == "__main__":

src/bigocrpdf/application.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,6 @@ def __init__(self) -> None:
4646
_("Print version information and exit"),
4747
None,
4848
)
49-
self.add_main_option(
50-
"image-mode",
51-
0,
52-
GLib.OptionFlags.NONE,
53-
GLib.OptionArg.NONE,
54-
_("Start in image conversion mode"),
55-
None,
56-
)
5749

5850
# Setup signals
5951
self.connect("activate", self.on_activate)
@@ -120,9 +112,6 @@ def on_handle_local_options(self, app: Adw.Application, options: GLib.VariantDic
120112
print(f"{APP_NAME} {APP_VERSION}")
121113
return 0 # Exit successfully
122114

123-
if options.contains("image-mode"):
124-
self.image_mode = True
125-
126115
return -1 # Continue processing
127116

128117
def on_activate(self, app: Adw.Application) -> None:
@@ -138,14 +127,8 @@ def on_activate(self, app: Adw.Application) -> None:
138127
# Check if we already have a window open
139128
win = self.get_active_window()
140129
if not win:
141-
# Check for image mode
142-
if getattr(self, "image_mode", False):
143-
# Launch ImageOcrWindow
144-
win = ImageOcrWindow(app)
145-
logger.info("Started in image mode")
146-
else:
147-
# Create the main window
148-
win = BigOcrPdfWindow(app)
130+
# Create the main window
131+
win = BigOcrPdfWindow(app)
149132

150133
# Show the window
151134
win.present()

src/bigocrpdf/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020

2121
APP_NAME: Final[str] = "Big OCR PDF"
2222
APP_ID: Final[str] = "br.com.biglinux.bigocrpdf"
23+
IMAGE_APP_ID: Final[str] = "br.com.biglinux.bigocrimage"
2324
APP_VERSION: Final[str] = "3.0.0"
2425
APP_DESCRIPTION: Final[str] = _("Add OCR to your PDF documents to make them searchable")
2526
APP_WEBSITE: Final[str] = "https://www.biglinux.com.br"
2627
APP_ISSUES: Final[str] = "https://github.com/biglinux/bigocrpdf/issues"
2728
APP_DEVELOPERS: Final[list[str]] = ["BigLinux https://github.com/biglinux/bigocrpdf"]
2829
APP_ICON_NAME: Final[str] = "bigocrpdf"
30+
IMAGE_APP_ICON_NAME: Final[str] = "bigocrimage"
2931

3032

3133
# ============================================================================

src/bigocrpdf/image_application.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
BigOcrPdf - Image OCR Application Module
3+
4+
Standalone GTK application for Image OCR, separate from the PDF application.
5+
Uses a different application_id for proper Wayland taskbar grouping.
6+
"""
7+
8+
import gi
9+
10+
gi.require_version("Gtk", "4.0")
11+
gi.require_version("Adw", "1")
12+
from gi.repository import Adw, Gio, GLib
13+
14+
from bigocrpdf.ui.image_ocr_window import ImageOcrWindow
15+
from bigocrpdf.ui.widgets import load_css
16+
from bigocrpdf.utils.i18n import _
17+
from bigocrpdf.utils.logger import logger
18+
19+
# Constants for the standalone image app (avoid circular import from config)
20+
IMAGE_APP_ID = "br.com.biglinux.bigocrimage"
21+
IMAGE_APP_ICON = "bigocrimage"
22+
IMAGE_APP_VERSION = "3.0.0"
23+
24+
25+
class ImageOcrApp(Adw.Application):
26+
"""Standalone application for Image OCR.
27+
28+
Uses a separate application_id (br.com.biglinux.bigocrimage) so that
29+
it appears as a separate application in the Wayland taskbar.
30+
"""
31+
32+
def __init__(self) -> None:
33+
"""Initialize the image OCR application."""
34+
super().__init__(
35+
application_id=IMAGE_APP_ID,
36+
flags=Gio.ApplicationFlags.HANDLES_OPEN,
37+
)
38+
39+
# Add version command line option
40+
self.add_main_option(
41+
"version",
42+
ord("v"),
43+
GLib.OptionFlags.NONE,
44+
GLib.OptionArg.NONE,
45+
_("Print version information and exit"),
46+
None,
47+
)
48+
49+
self.connect("activate", self.on_activate)
50+
self.connect("open", self.on_open)
51+
self.connect("handle-local-options", self.on_handle_local_options)
52+
53+
# Set up application icon
54+
self._setup_actions()
55+
56+
def _setup_actions(self) -> None:
57+
"""Set up application actions."""
58+
# About action
59+
about_action = Gio.SimpleAction.new("about", None)
60+
about_action.connect("activate", self.on_about_action)
61+
self.add_action(about_action)
62+
63+
# Quit action
64+
quit_action = Gio.SimpleAction.new("quit", None)
65+
quit_action.connect("activate", lambda *_: self.quit())
66+
self.add_action(quit_action)
67+
68+
# Set keyboard shortcuts
69+
self.set_accels_for_action("app.quit", ["<Control>q"])
70+
self.set_accels_for_action("app.about", ["F1"])
71+
72+
def on_handle_local_options(self, app: Adw.Application, options: GLib.VariantDict) -> int:
73+
"""Handle command line options."""
74+
if options.contains("version"):
75+
print(f"Big Image OCR {IMAGE_APP_VERSION}")
76+
return 0
77+
return -1
78+
79+
def on_activate(self, app: Adw.Application) -> None:
80+
"""Callback for application activation."""
81+
try:
82+
load_css()
83+
win = self.get_active_window()
84+
if not win:
85+
win = ImageOcrWindow(app)
86+
logger.info("Started Image OCR application")
87+
win.present()
88+
except Exception as e:
89+
logger.error(f"Error activating Image OCR: {e}")
90+
91+
def on_open(
92+
self,
93+
app: Adw.Application,
94+
files: list[Gio.File],
95+
n_files: int,
96+
hint: str,
97+
) -> None:
98+
"""Handle opening files."""
99+
self.on_activate(app)
100+
win = self.get_active_window()
101+
102+
if win and files:
103+
# Open the first image file
104+
file_path = files[0].get_path()
105+
if file_path and hasattr(win, "open_image"):
106+
win.open_image(file_path)
107+
logger.info(f"Opened image: {file_path}")
108+
109+
def on_about_action(self, action: Gio.SimpleAction, param: None) -> None:
110+
"""Show the About dialog."""
111+
about = Adw.AboutDialog.new()
112+
about.set_application_name("Big Image OCR")
113+
about.set_application_icon(IMAGE_APP_ICON)
114+
about.set_version(IMAGE_APP_VERSION)
115+
about.set_comments(_("Extract text from images using OCR"))
116+
about.set_website("https://www.biglinux.com.br")
117+
about.set_developers(["BigLinux https://github.com/biglinux/bigocrpdf"])
118+
about.set_license_type(Gio.License.GPL_3_0)
119+
about.present(self.get_active_window())

src/bigocrpdf/services/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self) -> None:
4747

4848
# Output filename settings
4949
self.pdf_suffix: str = DEFAULT_SUFFIX
50+
self.use_original_filename: bool = False
5051
self.overwrite_existing: bool = False
5152

5253
# Date inclusion settings
@@ -140,6 +141,7 @@ def load_settings(self) -> None:
140141

141142
# Output settings
142143
self.pdf_suffix = self._config.get("output.suffix", DEFAULT_SUFFIX)
144+
self.use_original_filename = self._config.get("output.use_original_filename", False)
143145
self.overwrite_existing = self._config.get("output.overwrite_existing", False)
144146
self.save_in_same_folder = self._config.get("output.save_in_same_folder", False)
145147
self.destination_folder = self._config.get("output.destination_folder", "")
@@ -421,6 +423,9 @@ def _save_all_settings(self) -> None:
421423

422424
# Output settings
423425
self._config.set("output.suffix", self.pdf_suffix, save_immediately=False)
426+
self._config.set(
427+
"output.use_original_filename", self.use_original_filename, save_immediately=False
428+
)
424429
self._config.set(
425430
"output.overwrite_existing", self.overwrite_existing, save_immediately=False
426431
)

src/bigocrpdf/ui/pdf_options_callbacks_mixin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ def _save_pdf_options(
312312
else: # YYYY-MM-DD
313313
self.window.settings.date_format_order = {"year": 1, "month": 2, "day": 3}
314314

315+
# Persist settings to disk
316+
self.window.settings._save_all_settings()
317+
logger.info(_("PDF output settings saved"))
318+
315319
# Close dialog and call callback
316320
dialog.destroy()
317321
callback(True)

src/bigocrpdf/ui/pdf_options_ui_mixin.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,24 @@ def _create_pdf_options_content(self, dialog: Adw.Window, callback: Callable) ->
5454
header_bar = self._create_pdf_options_header(dialog, callback)
5555
toolbar_view.add_top_bar(header_bar)
5656

57-
# Create scrolled content with preferences page
57+
# Create main vertical box to hold scrolled content + fixed preview
58+
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
59+
60+
# Create scrolled content with preferences page (without preview)
5861
scrolled_content, prefs_page = self._create_pdf_options_scrolled_content()
59-
toolbar_view.set_content(scrolled_content)
62+
main_box.append(scrolled_content)
63+
64+
# Create fixed preview group at bottom (outside scrolled area)
65+
preview_group = self._create_preview_group()
66+
preview_group.set_margin_start(12)
67+
preview_group.set_margin_end(12)
68+
preview_group.set_margin_bottom(12)
69+
main_box.append(preview_group)
70+
71+
# Store preview group reference in prefs_page for callback access
72+
prefs_page.preview_group = preview_group
73+
74+
toolbar_view.set_content(main_box)
6075

6176
return toolbar_view, prefs_page, header_bar
6277

@@ -114,25 +129,23 @@ def _create_pdf_preferences_page(self) -> Adw.PreferencesPage:
114129
"""
115130
prefs_page = Adw.PreferencesPage()
116131

117-
# Add all preference groups
132+
# Add all preference groups (preview is now added separately outside scroll)
118133
file_group = self._create_file_settings_group()
119134
text_group = self._create_text_extraction_group()
120135
odf_group = self._create_odf_extraction_group()
121136
date_group = self._create_date_time_group()
122-
preview_group = self._create_preview_group()
123137

124138
prefs_page.add(file_group)
125139
prefs_page.add(text_group)
126140
prefs_page.add(odf_group)
127141
prefs_page.add(date_group)
128-
prefs_page.add(preview_group)
129142

130143
# Store references for access in callbacks
131144
prefs_page.file_group = file_group
132145
prefs_page.text_group = text_group
133146
prefs_page.odf_group = odf_group
134147
prefs_page.date_group = date_group
135-
prefs_page.preview_group = preview_group
148+
# Note: preview_group is added in _create_pdf_options_content()
136149

137150
return prefs_page
138151

@@ -195,7 +208,10 @@ def _create_warning_row(self) -> Adw.ActionRow:
195208
warning_row = Adw.ActionRow()
196209
warning_row.set_title(_("Warning"))
197210
warning_row.set_subtitle(
198-
_("If saving to the same folder as original, this will replace the original files")
211+
_(
212+
"To replace original files, also enable 'Overwrite Existing Files' below "
213+
"and save to the same folder"
214+
)
199215
)
200216
warning_icon = Gtk.Image.new_from_icon_name("dialog-warning-symbolic")
201217
warning_icon.set_pixel_size(16)

usr/bin/bigocrimage

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
#!/bin/bash
1+
#!/bin/sh
22

3-
# Wrapper to call bigocrpdf for image OCR
3+
# Search bigocrpdf package in Python site-packages or legacy share location
4+
for i in /usr/lib/python3.{6..25}/site-packages/bigocrpdf /usr/share/biglinux/bigocrpdf; do
5+
if [ -e "$i/__init__.py" ]; then
6+
cd "$i"
7+
break
8+
fi
9+
done
410

5-
bigocrpdf --image-mode "$@"
11+
# Run the Image OCR application with its own application_id for Wayland taskbar
12+
exec python3 -c "from bigocrpdf import main_image; main_image()" "$@"

usr/share/applications/br.com.biglinux.bigocrimage.desktop

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Name[zh]=提取图像文本 (OCR)
3131
Exec=bigocrimage %f
3232
Terminal=false
3333
Icon=bigocrimage
34+
StartupWMClass=bigocrimage
3435
Type=Application
3536
NoDisplay=true
3637
MimeType=inode/directory;image/avif;image/gif;image/heif;image/jpeg;image/jxl;image/png;image/bmp;image/x-eps;image/x-icns;image/x-ico;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-xbitmap;image/x-xpixmap;image/tiff;image/x-psd;image/x-webp;image/webp;image/x-tga;application/x-krita;image/x-kde-raw;image/x-canon-cr2;image/x-canon-crw;image/x-kodak-dcr;image/x-adobe-dng;image/x-kodak-k25;image/x-kodak-kdc;image/x-minolta-mrw;image/x-nikon-nef;image/x-olympus-orf;image/x-pentax-pef;image/x-fuji-raf;image/x-panasonic-rw;image/x-sony-sr2;image/x-sony-srf;image/x-sigma-x3f;image/x-sony-arw;image/x-panasonic-rw2;

0 commit comments

Comments
 (0)