diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/app-window.vala | 107 | ||||
| -rw-r--r-- | src/autosave-manager.vala | 2 | ||||
| -rw-r--r-- | src/book-view.vala | 13 | ||||
| -rw-r--r-- | src/book.vala | 30 | ||||
| -rw-r--r-- | src/meson.build | 1 | ||||
| -rw-r--r-- | src/page-icon.vala | 68 | ||||
| -rw-r--r-- | src/page-view.vala | 15 | ||||
| -rw-r--r-- | src/postprocessor.vala | 44 | ||||
| -rw-r--r-- | src/preferences-dialog.vala | 35 | ||||
| -rw-r--r-- | src/scanner.vala | 4 | ||||
| -rwxr-xr-x | src/simple-scan-postprocessing.sh | 83 | ||||
| -rw-r--r-- | src/simple-scan.vala | 3 | 
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; | 
