summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff.email>2022-03-19 18:05:05 +0100
committerJörg Frings-Fürst <debian@jff.email>2022-03-19 18:05:05 +0100
commit8ac2508eb094459c062d0c31b6367da393b4fa6e (patch)
treea3dd69ae2a2f90e59914e9ede6acdc94e3a6712d /src
parent05315c3da6d3761ba95f1ae96b852768dd651c25 (diff)
New upstream version 42.0upstream/42.0
Diffstat (limited to 'src')
-rw-r--r--src/app-window.vala107
-rw-r--r--src/autosave-manager.vala2
-rw-r--r--src/book-view.vala13
-rw-r--r--src/book.vala30
-rw-r--r--src/meson.build1
-rw-r--r--src/page-icon.vala68
-rw-r--r--src/page-view.vala15
-rw-r--r--src/postprocessor.vala44
-rw-r--r--src/preferences-dialog.vala35
-rw-r--r--src/scanner.vala4
-rwxr-xr-xsrc/simple-scan-postprocessing.sh83
-rw-r--r--src/simple-scan.vala3
12 files changed, 302 insertions, 103 deletions
diff --git a/src/app-window.vala b/src/app-window.vala
index e163047..cea6837 100644
--- a/src/app-window.vala
+++ b/src/app-window.vala
@@ -720,7 +720,10 @@ public class AppWindow : Hdy.ApplicationWindow
save_button.sensitive = false;
try
{
- yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file, (fraction) =>
+ yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file,
+ settings.get_boolean ("postproc-enabled"), settings.get_string ("postproc-script"),
+ settings.get_string ("postproc-arguments"), settings.get_boolean ("postproc-keep-original"),
+ (fraction) =>
{
progress_bar.set_fraction (fraction);
}, cancellable);
@@ -793,7 +796,7 @@ public class AppWindow : Hdy.ApplicationWindow
prompt_to_save_async.begin (/* Text in dialog warning when a document is about to be lost */
_("Save current document?"),
/* Button in dialog to create new document and discard unsaved document */
- _("Discard Changes"), (obj, res) =>
+ _("_Discard Changes"), (obj, res) =>
{
if (!prompt_to_save_async.end(res))
return;
@@ -905,14 +908,17 @@ public class AppWindow : Hdy.ApplicationWindow
case ScanType.SINGLE:
scan_single_radio.active = true;
scan_options_image.icon_name = "scanner-symbolic";
+ scan_button.tooltip_text = _("Scan a single page from the scanner");
break;
case ScanType.ADF:
scan_adf_radio.active = true;
scan_options_image.icon_name = "scan-type-adf-symbolic";
+ scan_button.tooltip_text = _("Scan multiple pages from the scanner");
break;
case ScanType.BATCH:
scan_batch_radio.active = true;
scan_options_image.icon_name = "scan-type-batch-symbolic";
+ scan_button.tooltip_text = _("Scan multiple pages from the scanner");
break;
}
}
@@ -1396,39 +1402,7 @@ public class AppWindow : Hdy.ApplicationWindow
box.add (page_box);
}
- /* Get colours for each page (from Tango palette) */
- var r = 1.0;
- var g = 1.0;
- var b = 1.0;
- switch (side)
- {
- case 'F':
- /* Plum */
- r = 0x75 / 255.0;
- g = 0x50 / 255.0;
- b = 0x7B / 255.0;
- break;
- case 'B':
- /* Orange */
- r = 0xF5 / 255.0;
- g = 0x79 / 255.0;
- b = 0.0;
- break;
- case 'C':
- /* Butter to Scarlet Red */
- var p = (items[i] - '1') / 5.0;
- r = (0xED / 255.0) * (1 - p) + 0xCC * p;
- g = (0xD4 / 255.0) * (1 - p);
- b = 0;
- break;
- }
-
- /* Mix with white to look more paper like */
- r = r + (1.0 - r) * 0.7;
- g = g + (1.0 - g) * 0.7;
- b = b + (1.0 - b) * 0.7;
-
- var icon = new PageIcon ("%c".printf (items[i]), r, g, b);
+ var icon = new PageIcon (side, items[i] - '1');
icon.visible = true;
page_box.add (icon);
}
@@ -1502,7 +1476,10 @@ public class AppWindow : Hdy.ApplicationWindow
filename = "scan.jpg";
}
var file = File.new_for_path (Path.build_filename (dir, filename));
- yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file, null, null);
+ yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file,
+ settings.get_boolean ("postproc-enabled"), settings.get_string ("postproc-script"),
+ settings.get_string ("postproc-arguments"), settings.get_boolean ("postproc-keep-original"),
+ null, null);
var command_line = "xdg-email";
if (mime_type == "application/pdf")
command_line += " --attach %s".printf (file.get_path ());
@@ -1567,29 +1544,23 @@ public class AppWindow : Hdy.ApplicationWindow
{
string[] authors = { "Robert Ancell <robert.ancell@canonical.com>" };
- /* The license this software is under (GPL3+) */
- string license = _("This program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <http://www.gnu.org/licenses/>.");
-
- /* Title of about dialog */
string title = _("About Document Scanner");
- /* Description of program */
string description = _("Simple document scanning tool");
Gtk.show_about_dialog (this,
- "title", title,
- "program-name", _("Document Scanner"),
- "version", VERSION,
- "comments", description,
- "logo-icon-name", "org.gnome.SimpleScan",
- "authors", authors,
- "translator-credits", _("translator-credits"),
- "website", "https://gitlab.gnome.org/GNOME/simple-scan",
- "copyright", "Copyright © 2009-2018 Canonical Ltd.",
- "license", license,
- "wrap-license", true,
- null);
- }
+ "title", title,
+ "authors", authors,
+ "translator-credits", _("translator-credits"),
+ "comments", description,
+ "copyright", "Copyright © 2009-2018 Canonical Ltd.",
+ "license-type", Gtk.License.GPL_3_0,
+ "program-name", _("Document Scanner"),
+ "logo-icon-name", "org.gnome.SimpleScan",
+ "version", VERSION,
+ "website", "https://gitlab.gnome.org/GNOME/simple-scan",
+ "wrap-license", true);
+ }
private void about_cb ()
{
@@ -1601,7 +1572,7 @@ public class AppWindow : Hdy.ApplicationWindow
prompt_to_save_async.begin (/* Text in dialog warning when a document is about to be lost */
_("Save document before quitting?"),
/* Text in dialog warning when a document is about to be lost */
- _("Quit without Saving"), (obj, res) =>
+ _("_Quit without Saving"), (obj, res) =>
{
if (!prompt_to_save_async.end(res))
return;
@@ -1883,23 +1854,23 @@ public class AppWindow : Hdy.ApplicationWindow
var gear_menu = new Menu ();
var section = new Menu ();
gear_menu.append_section (null, section);
- section.append (_("Email"), "app.email");
- section.append (_("Print"), "app.print");
- section.append (C_("menu", "Reorder Pages"), "app.reorder");
+ section.append (_("_Email"), "app.email");
+ section.append (_("Pri_nt"), "app.print");
+ section.append (C_("menu", "_Reorder Pages"), "app.reorder");
section = new Menu ();
gear_menu.append_section (null, section);
- section.append (_("Preferences"), "app.preferences");
- section.append (_("Keyboard Shortcuts"), "win.show-help-overlay");
- section.append (_("Help"), "app.help");
- section.append (_("About Document Scanner"), "app.about");
+ section.append (_("_Preferences"), "app.preferences");
+ section.append (_("_Keyboard Shortcuts"), "win.show-help-overlay");
+ section.append (_("_Help"), "app.help");
+ section.append (_("_About Document Scanner"), "app.about");
menu_button.set_menu_model (gear_menu);
app.add_window (this);
/* Populate ActionBar (not supported in Glade) */
/* https://bugzilla.gnome.org/show_bug.cgi?id=769966 */
- var button = new Gtk.Button.with_label (/* Label on new document button */
- _("New Document"));
+ var button = new Gtk.Button.with_mnemonic (/* Label on new document button */
+ _("_New Document"));
button.visible = true;
button.clicked.connect (new_document_cb);
action_bar.pack_start (button);
@@ -1996,7 +1967,7 @@ public class AppWindow : Hdy.ApplicationWindow
private string state_filename
{
- owned get { return Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", "state"); }
+ owned get { return Path.build_filename (Environment.get_user_config_dir (), "simple-scan", "state"); }
}
private void load_state ()
@@ -2021,11 +1992,11 @@ public class AppWindow : Hdy.ApplicationWindow
window_height = 400;
window_is_maximized = state_get_boolean (f, "window", "is-maximized");
window_is_fullscreen = state_get_boolean (f, "window", "is-fullscreen");
- scan_type = Scanner.type_from_string(state_get_string (f, "scanner", "scan-type", "single"));
+ scan_type = Scanner.type_from_string(state_get_string (f, "scanner", "scan-type"));
set_scan_type (scan_type);
}
- private string state_get_string (KeyFile f, string group_name, string key, string default)
+ private string state_get_string (KeyFile f, string group_name, string key, string default = "")
{
try
{
@@ -2061,6 +2032,7 @@ public class AppWindow : Hdy.ApplicationWindow
}
}
+ private static string STATE_DIR = Path.build_filename (Environment.get_user_config_dir (), "simple-scan", null);
private void save_state (bool force = false)
{
if (!force)
@@ -2086,6 +2058,7 @@ public class AppWindow : Hdy.ApplicationWindow
f.set_string ("scanner", "scan-type", Scanner.type_to_string(scan_type));
try
{
+ DirUtils.create_with_parents (STATE_DIR, 0700);
FileUtils.set_contents (state_filename, f.to_data ());
}
catch (Error e)
diff --git a/src/autosave-manager.vala b/src/autosave-manager.vala
index c5eb65e..7e92d33 100644
--- a/src/autosave-manager.vala
+++ b/src/autosave-manager.vala
@@ -337,7 +337,7 @@ public class AutosaveManager
try
{
- DirUtils.create_with_parents (AUTOSAVE_DIR, 0777);
+ DirUtils.create_with_parents (AUTOSAVE_DIR, 0700);
FileUtils.set_contents (AUTOSAVE_PATH, file.to_data ());
}
catch (Error e)
diff --git a/src/book-view.vala b/src/book-view.vala
index 59e2469..df2beb4 100644
--- a/src/book-view.vala
+++ b/src/book-view.vala
@@ -189,14 +189,7 @@ public class BookView : Gtk.Box
private void add_cb (Book book, Page page)
{
- Gdk.RGBA page_ruler_color;
- if (!get_style_context ().lookup_color ("theme_fg_color", out page_ruler_color))
- {
- warning ("Couldn't get theme_fg_color from GTK theme, needed to draw the page view ruler");
- /* Use a bright color so that theme makers notice it. */
- page_ruler_color.parse ("#00ff00");
- }
- var page_view = new PageView (page, page_ruler_color);
+ var page_view = new PageView (page);
page_view.changed.connect (page_view_changed_cb);
page_view.size_changed.connect (page_view_size_changed_cb);
page_data.insert (page, page_view);
@@ -450,6 +443,8 @@ public class BookView : Gtk.Box
for (var i = 0; i < book.n_pages; i++)
pages.append (get_nth_page (i));
+ var ruler_color = get_style_context ().get_color (get_state_flags ());
+
/* Render each page */
foreach (var page in pages)
{
@@ -462,7 +457,7 @@ public class BookView : Gtk.Box
context.save ();
context.translate (-x_offset, 0);
- page.render (context);
+ page.render (context, ruler_color);
context.restore ();
if (page.selected)
diff --git a/src/book.vala b/src/book.vala
index 798fe98..d2aa54d 100644
--- a/src/book.vala
+++ b/src/book.vala
@@ -136,10 +136,14 @@ public class Book : Object
return pages.index (page);
}
- public async void save_async (string mime_type, int quality, File file, ProgressionCallback? progress_cb, Cancellable? cancellable = null) throws Error
+ public async void save_async (string mime_type, int quality, File file,
+ bool postproc_enabled, string postproc_script, string postproc_arguments, bool postproc_keep_original,
+ ProgressionCallback? progress_cb, Cancellable? cancellable = null) throws Error
{
var book_saver = new BookSaver ();
- yield book_saver.save_async (this, mime_type, quality, file, progress_cb, cancellable);
+ yield book_saver.save_async (this, mime_type, quality, file,
+ postproc_enabled, postproc_script, postproc_arguments, postproc_keep_original,
+ progress_cb, cancellable);
}
}
@@ -155,12 +159,15 @@ private class BookSaver
private AsyncQueue<WriteTask> write_queue;
private ThreadPool<EncodeTask> encoder;
private SourceFunc save_async_callback;
+ private Postprocessor postprocessor = new Postprocessor();
/* save_async get called in the main thread to start saving. It
* distributes all encode tasks to other threads then yield so
* the ui can continue operating. The method then return once saving
* is completed, cancelled, or failed */
- public async void save_async (Book book, string mime_type, int quality, File file, ProgressionCallback? progression_callback, Cancellable? cancellable) throws Error
+ public async void save_async (Book book, string mime_type, int quality, File file,
+ bool postproc_enabled, string postproc_script, string postproc_arguments, bool postproc_keep_original,
+ ProgressionCallback? progression_callback, Cancellable? cancellable) throws Error
{
var timer = new Timer ();
@@ -239,6 +246,23 @@ private class BookSaver
timer.stop ();
debug ("Save time: %f seconds", timer.elapsed (null));
+
+ if ( postproc_enabled ) {
+ /* Perform post-processing */
+ timer = new Timer ();
+ var return_code = postprocessor.process(postproc_script,
+ mime_type, // MIME Type
+ postproc_keep_original, // Keep Original
+ file.get_path(), // Filename
+ postproc_arguments // Arguments
+ );
+ if ( return_code != 0 ) {
+ warning ("Postprocessing script execution failed. ");
+ }
+ timer.stop ();
+ debug ("Postprocessing time: %f seconds", timer.elapsed (null));
+ }
+
}
/* Those methods are run in the encoder threads pool. It process
diff --git a/src/meson.build b/src/meson.build
index 3f699eb..240b56d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -22,6 +22,7 @@ simple_scan = executable ('simple-scan',
'page.vala',
'page-icon.vala',
'page-view.vala',
+ 'postprocessor.vala',
'preferences-dialog.vala',
'simple-scan.vala',
'scanner.vala',
diff --git a/src/page-icon.vala b/src/page-icon.vala
index 793ca5b..f1a25ea 100644
--- a/src/page-icon.vala
+++ b/src/page-icon.vala
@@ -12,18 +12,14 @@
public class PageIcon : Gtk.DrawingArea
{
- private string text;
- private double r;
- private double g;
- private double b;
+ private char side;
+ private int position;
private const int MINIMUM_WIDTH = 20;
- public PageIcon (string text, double r = 1.0, double g = 1.0, double b = 1.0)
+ public PageIcon (char side, int position)
{
- this.text = text;
- this.r = r;
- this.g = g;
- this.b = b;
+ this.side = side;
+ this.position = position;
}
public override void get_preferred_width (out int minimum_width, out int natural_width)
@@ -57,15 +53,61 @@ public class PageIcon : Gtk.DrawingArea
c.translate ((get_allocated_width () - w) / 2, (get_allocated_height () - h) / 2);
- c.rectangle (0.5, 0.5, w - 1, h - 1);
+ bool dark = Hdy.StyleManager.get_default ().dark;
+ bool hc = Hdy.StyleManager.get_default ().high_contrast;
+
+ if (dark && !hc)
+ c.rectangle (1, 1, w - 2, h - 2);
+ else
+ c.rectangle (0, 0, w, h);
+
+ Gdk.RGBA rgba = {};
+
+ switch (side)
+ {
+ case 'F':
+ /* Purple 2 */
+ rgba.parse ("#c061cb");
+ break;
+ case 'B':
+ /* Orange 3 */
+ rgba.parse ("#ff7800");
+ break;
+ default:
+ /* Yellow 3 to Red 2 */
+ Gdk.RGBA start = {}, end = {};
+ start.parse ("#f6d32d");
+ end.parse ("#ed333b");
+
+ double progress = position / 5.0;
+ rgba.red = start.red + (end.red - start.red) * progress;
+ rgba.green = start.green + (end.green - start.green) * progress;
+ rgba.blue = start.blue + (end.blue - start.blue) * progress;
+ break;
+ }
- c.set_source_rgb (r, g, b);
- c.fill_preserve ();
+ rgba.alpha = 0.3;
+
+ Gdk.cairo_set_source_rgba (c, rgba);
+ c.fill ();
c.set_line_width (1.0);
- c.set_source_rgb (0.0, 0.0, 0.0);
+ if (hc && dark)
+ c.set_source_rgba (1, 1, 1, 0.5);
+ else if (hc)
+ c.set_source_rgba (0, 0, 0, 0.5);
+ else
+ c.set_source_rgba (0, 0, 0, 0.15);
+
+ c.rectangle (0.5, 0.5, w - 1, h - 1);
c.stroke ();
+ if (dark)
+ c.set_source_rgb (1, 1, 1);
+ else
+ c.set_source_rgb (0, 0, 0);
+
+ var text = @"$(position + 1)";
Cairo.TextExtents extents;
c.text_extents (text, out extents);
c.translate ((w - extents.width) * 0.5 - 0.5, (h + extents.height) * 0.5 - 0.5);
diff --git a/src/page-view.vala b/src/page-view.vala
index 342df27..148dcca 100644
--- a/src/page-view.vala
+++ b/src/page-view.vala
@@ -45,8 +45,6 @@ public class PageView : Object
}
}
- private Gdk.RGBA ruler_color;
-
private int ruler_width = 8;
private int border_width = 2;
@@ -86,13 +84,9 @@ public class PageView : Object
public signal void size_changed ();
public signal void changed ();
- /* It is necessary to ask the ruler color since it is themed with the GTK */
- /* theme foreground color, and this class doesn't have any GTK widget */
- /* available to lookup the color. */
- public PageView (Page page, Gdk.RGBA ruler_color)
+ public PageView (Page page)
{
this.page = page;
- this.ruler_color = ruler_color;
page.pixels_changed.connect (page_pixels_changed_cb);
page.size_changed.connect (page_size_changed_cb);
page.crop_changed.connect (page_overlay_changed_cb);
@@ -828,7 +822,10 @@ public class PageView : Object
}
}
- public void render (Cairo.Context context)
+ /* It is necessary to ask the ruler color since it is themed with the GTK */
+ /* theme foreground color, and this class doesn't have any GTK widget */
+ /* available to lookup the color. */
+ public void render (Cairo.Context context, Gdk.RGBA ruler_color)
{
update_animation ();
update_page_view ();
@@ -845,7 +842,7 @@ public class PageView : Object
context.paint ();
/* Draw page border */
- context.set_source_rgb (ruler_color.red, ruler_color.green, ruler_color.blue);
+ Gdk.cairo_set_source_rgba (context, ruler_color);
context.set_line_width (border_width);
context.rectangle (0,
diff --git a/src/postprocessor.vala b/src/postprocessor.vala
new file mode 100644
index 0000000..2d036c9
--- /dev/null
+++ b/src/postprocessor.vala
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+/*
+ * Copyright (C) 2022 Alexander Vogt
+ * Author: Alexander Vogt <a.vogt@fulguritus.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+public class Postprocessor {
+
+ public Postprocessor(){
+
+ }
+
+ public int process(string script, string mime_type, bool keep_original, string source_file, string arguments) throws Error {
+ // Code copied and adapted from https://valadoc.org/glib-2.0/GLib.Process.spawn_sync.html
+ string[] spawn_args = {script, mime_type, keep_original ? "true" : "false", source_file, arguments };
+ string[] spawn_env = Environ.get ();
+ string process_stdout;
+ string process_stderr;
+ int process_status;
+
+ print ("Executing script%s\n", script);
+ Process.spawn_sync (null, // inherit parent's working dir
+ spawn_args,
+ spawn_env,
+ SpawnFlags.SEARCH_PATH,
+ null,
+ out process_stdout,
+ out process_stderr,
+ out process_status);
+ debug ("status: %d\n", process_status);
+ debug ("STDOUT: \n");
+ debug ("process_stdout");
+ debug ("STDERR: \n");
+ debug ("process_stderr");
+
+ return process_status;
+ }
+}
diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala
index 8d992ab..02bbaf8 100644
--- a/src/preferences-dialog.vala
+++ b/src/preferences-dialog.vala
@@ -51,6 +51,14 @@ private class PreferencesDialog : Hdy.PreferencesWindow
private unowned Gtk.Adjustment brightness_adjustment;
[GtkChild]
private unowned Gtk.Adjustment contrast_adjustment;
+ [GtkChild]
+ private unowned Gtk.Switch postproc_enable_switch;
+ [GtkChild]
+ private unowned Gtk.Entry postproc_script_entry;
+ [GtkChild]
+ private unowned Gtk.Entry postproc_args_entry;
+ [GtkChild]
+ private unowned Gtk.Switch postproc_keep_original_switch;
public PreferencesDialog (Settings settings)
{
@@ -133,6 +141,33 @@ private class PreferencesDialog : Hdy.PreferencesWindow
page_delay_6s_button.toggled.connect ((button) => { if (button.active) settings.set_int ("page-delay", 6000); });
page_delay_10s_button.toggled.connect ((button) => { if (button.active) settings.set_int ("page-delay", 10000); });
page_delay_15s_button.toggled.connect ((button) => { if (button.active) settings.set_int ("page-delay", 15000); });
+
+ // Postprocessing settings
+ var postproc_enabled = settings.get_boolean ("postproc-enabled");
+ postproc_enable_switch.set_state(postproc_enabled);
+ toggle_postproc_visibility (postproc_enabled);
+ postproc_enable_switch.state_set.connect ((is_active) => { toggle_postproc_visibility (is_active);
+ settings.set_boolean("postproc-enabled", is_active);
+ return true; });
+
+ var postproc_script = settings.get_string("postproc-script");
+ postproc_script_entry.set_text(postproc_script);
+ postproc_script_entry.changed.connect (() => { settings.set_string("postproc-script", postproc_script_entry.get_text()); });
+
+ var postproc_arguments = settings.get_string("postproc-arguments");
+ postproc_args_entry.set_text(postproc_arguments);
+ postproc_args_entry.changed.connect (() => { settings.set_string("postproc-arguments", postproc_args_entry.get_text()); });
+
+ var postproc_keep_original = settings.get_boolean ("postproc-keep-original");
+ postproc_keep_original_switch.set_state(postproc_keep_original);
+ postproc_keep_original_switch.state_set.connect ((is_active) => { settings.set_boolean("postproc-keep-original", is_active);
+ return true; });
+ }
+
+ private void toggle_postproc_visibility(bool enabled) {
+ postproc_script_entry.get_parent ().get_parent ().get_parent ().get_parent ().set_visible(enabled);
+ postproc_args_entry.get_parent ().get_parent ().get_parent ().get_parent ().set_visible(enabled);
+ postproc_keep_original_switch.get_parent ().get_parent ().get_parent ().get_parent ().set_visible(enabled);
}
private void set_page_side (ScanSide page_side)
diff --git a/src/scanner.vala b/src/scanner.vala
index 809ba6c..495ee9d 100644
--- a/src/scanner.vala
+++ b/src/scanner.vala
@@ -367,6 +367,10 @@ public class Scanner : Object
var devices = new List<ScanDevice> ();
for (var i = 0; device_list[i] != null; i++)
{
+ /* Virtual devices tend to not be scanners. Skip them. */
+ if (device_list[i].type == "virtual device")
+ continue;
+
debug ("Device: name=\"%s\" vendor=\"%s\" model=\"%s\" type=\"%s\"",
device_list[i].name, device_list[i].vendor, device_list[i].model, device_list[i].type);
diff --git a/src/simple-scan-postprocessing.sh b/src/simple-scan-postprocessing.sh
new file mode 100755
index 0000000..39fb461
--- /dev/null
+++ b/src/simple-scan-postprocessing.sh
@@ -0,0 +1,83 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2022 Alexander Vogt
+# Author: Alexander Vogt <a.vogt@fulguritus.com>
+#
+# Sample postprocessing script for gnome-simple-scan for OCR in PDFs
+#
+# This script first identifies a suitable instance of ocrmypdf
+# (https://github.com/ocrmypdf/OCRmyPDF) and then applies this as a
+# postprocessing step to PDFs generated by simple-scan.
+#
+# Usage:
+# =====
+# simple-scan-postprocessing mime-type keep-origin input-file args
+#
+# Currently, only mime-type "application/pdf" is supported, the script will
+# exit without an error if "image/jpeg", "image/png", or "image/webp" is
+# provided. Any other mime-type results in an error.
+# All args are provided to ocrmypdf.
+# If keep-origin is set to "true", a copy of the source file is kept.
+#
+# Example:
+# =======
+# simple-scan-postprocessing application/pdf true scan.pdf -l eng+deu
+# simple-scan-postprocessing application/pdf true scan.pdf -rcd --jbig2-lossy -l deu
+#
+set -e +m
+
+# Arguments
+mime_type="$1"
+keep_original="$2"
+target="$3"
+remainder="${@:4}"
+# Globals
+_ocrmypdfcontainer="jbarlow83/ocrmypdf"
+
+source="${target%.*}_orig.${target##*.}"
+
+# Helper functions
+function findOcrMyPdf() {
+ # Determines the path of ocrmypdf in the following order:
+ # 1. ocrmypdf from the $PATH (local installation)
+ # 2. ocrmypdf through podman (if podman in $PATH)
+ # 3. ocrmypdf through docker (if podman in $PATH)
+ _ocrmypdf=$(which ocrmypdf) && return
+ _ocrmypdf="$(which podman) run --rm -i ${_ocrmypdfcontainer} " && return
+ _ocrmypdf="$(which docker) run --rm -i ${_ocrmypdfcontainer} "
+ if [ $? -ne 0 ]; then
+ echo "No suitable instance of ocrmypdf found. Please check your setup. "
+ exit 1
+ fi
+}
+
+case ${mime_type} in
+ "application/pdf")
+ mv "$target" "$source" # create a backup
+
+ # Determine the version of ocrmypdf to use
+ findOcrMyPdf
+ # Execute OCR
+ ${_ocrmypdf} ${remainder} - - <"$source" >"$target"
+ ;;
+ "image/jpeg")
+ exit 0 # Nothing implemented
+ ;;
+ "image/png")
+ exit 0 # Nothing implemented
+ ;;
+ "image/webp")
+ exit 0 # Nothing implemented
+ ;;
+ *)
+ echo "Unsupported mime-type \"${mime_type}\""
+ exit 1
+ ;;
+esac
+
+# Clean up
+if [ "$keep_original" == "true" ]; then
+ exit 0
+else
+ rm "$source"
+fi
diff --git a/src/simple-scan.vala b/src/simple-scan.vala
index c15a541..5deedcf 100644
--- a/src/simple-scan.vala
+++ b/src/simple-scan.vala
@@ -14,7 +14,7 @@ public class SimpleScan : Gtk.Application
static bool show_version;
static bool debug_enabled;
static string? fix_pdf_filename = null;
- public const OptionEntry[] options =
+ const OptionEntry[] options =
{
{ "version", 'v', 0, OptionArg.NONE, ref show_version,
/* Help string for command line --version flag */
@@ -51,6 +51,7 @@ public class SimpleScan : Gtk.Application
base.startup ();
Hdy.init ();
+ Hdy.StyleManager.get_default ().color_scheme = PREFER_LIGHT;
app = new AppWindow ();
book = app.book;