simple-scan-team team mailing list archive
-
simple-scan-team team
-
Mailing list archive
-
Message #00316
[Merge] lp:~holger+lp/simple-scan/simple-scan-cli into lp:simple-scan
Holger Hans Peter Freyther has proposed merging lp:~holger+lp/simple-scan/simple-scan-cli into lp:simple-scan.
Requested reviews:
Simple Scan Development Team (simple-scan-team)
For more details, see:
https://code.launchpad.net/~holger+lp/simple-scan/simple-scan-cli/+merge/91558
I was not able to find a tool that can scan to a PDF from cli (scanimage does not support it). I hacked this together, it hardcodes a lot (A4, DPI, scan mode), I messed up the author and (bzr rewrite has no interactive mode that would allow me to fix it).
Right now the question is if you would do:
1.) Build a libsimplescan and install it (.vapi file so I could build my cli with that)
2.) Include a cli directly
--
https://code.launchpad.net/~holger+lp/simple-scan/simple-scan-cli/+merge/91558
Your team Simple Scan Development Team is requested to review the proposed merge of lp:~holger+lp/simple-scan/simple-scan-cli into lp:simple-scan.
=== modified file '.bzrignore'
--- .bzrignore 2011-06-12 10:13:06 +0000
+++ .bzrignore 2012-02-04 17:34:18 +0000
@@ -32,3 +32,10 @@
src/scanner.c
src/simple-scan.c
src/ui.c
+src/simple-scan-cli.c
+src/libsimplescan_a_vala.stamp
+src/simple-scan-cli
+src/simple-scan.h
+src/simple-scan.vapi
+src/simple_scan_cli_vala.stamp
+
=== modified file 'configure.ac'
--- configure.ac 2011-12-08 04:37:24 +0000
+++ configure.ac 2012-02-04 17:34:18 +0000
@@ -11,6 +11,7 @@
AM_PROG_VALAC([0.13.0])
AM_PROG_CC_C_O
AC_HEADER_STDC
+AC_PROG_RANLIB
GLIB_GSETTINGS
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2011-07-10 06:59:21 +0000
+++ src/Makefile.am 2012-02-04 17:34:18 +0000
@@ -1,6 +1,7 @@
-bin_PROGRAMS = simple-scan
+bin_PROGRAMS = simple-scan simple-scan-cli
+noinst_LIBRARIES = libsimplescan.a
-simple_scan_SOURCES = \
+libsimplescan_a_SOURCES = \
config.vapi \
book.vala \
book-view.vala \
@@ -9,21 +10,38 @@
page.vala \
page-view.vala \
sane.vapi \
+ scanner.vala
+
+libsimplescan_a_VALAFLAGS = --library simple-scan -H simple-scan.h
+
+BUILT_SOURCES = simple-scan.vapi
+
+simple-scan.vapi: libsimplescan.a
+
+simple_scan_SOURCES = \
+ config.vapi \
+ sane.vapi \
+ simple-scan.vapi \
simple-scan.vala \
- scanner.vala \
ui.vala
-simple_scan_VALAFLAGS = \
+simple_scan_cli_SOURCES = \
+ config.vapi \
+ sane.vapi \
+ simple-scan.vapi \
+ simple-scan-cli.vala
+
+VALAFLAGS = \
--pkg=zlib \
--pkg=gudev-1.0 \
--pkg=gio-2.0 \
--pkg=gtk+-3.0
if HAVE_COLORD
-simple_scan_VALAFLAGS += -D HAVE_COLORD
+VALAFLAGS += -D HAVE_COLORD
endif
-simple_scan_CFLAGS = \
+AM_CFLAGS = \
$(SIMPLE_SCAN_CFLAGS) \
$(COLORD_CFLAGS) \
$(WARN_CFLAGS) \
@@ -38,13 +56,23 @@
simple_scan_LDADD = \
$(SIMPLE_SCAN_LIBS) \
$(COLORD_LIBS) \
+ libsimplescan.a \
+ -lsane \
+ -ljpeg \
+ -lm
+
+simple_scan_cli_LDADD = \
+ $(SIMPLE_SCAN_LIBS) \
+ $(COLORD_LIBS) \
+ libsimplescan.a \
-lsane \
-ljpeg \
-lm
CLEANFILES = \
$(patsubst %.vala,%.c,$(filter %.vala, $(SOURCES))) \
- *_vala.stamp
+ *_vala.stamp \
+ simple-scan.vapi
DISTCLEANFILES = \
Makefile.in
=== added file 'src/simple-scan-cli.vala'
--- src/simple-scan-cli.vala 1970-01-01 00:00:00 +0000
+++ src/simple-scan-cli.vala 2012-02-04 17:34:18 +0000
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2009-2011 Canonical Ltd.
+ * Author: Robert Ancell <robert.ancell@xxxxxxxxxxxxx>
+ *
+ * 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 Application
+{
+ static bool show_version;
+ static bool debug_enabled;
+ static string? output_name;
+ public static const OptionEntry[] options =
+ {
+ { "version", 'v', 0, OptionArg.NONE, ref show_version,
+ /* Help string for command line --version flag */
+ N_("Show release version"), null},
+ { "debug", 'd', 0, OptionArg.NONE, ref debug_enabled,
+ /* Help string for command line --debug flag */
+ N_("Print debugging messages"), null},
+ { "output", 'o', 0, OptionArg.STRING, ref output_name,
+ /* Help string for --output */
+ N_("Store the PDF to this file"), null},
+ { null }
+ };
+ private static Timer log_timer;
+ private static FileStream? log_file;
+
+ private ScanDevice? default_device = null;
+ private bool have_devices = false;
+ private GUdev.Client udev_client;
+ private Scanner scanner;
+ private Book book;
+ private GLib.MainLoop loop = new MainLoop ();
+
+ private void initialize_book ()
+ {
+ book = new Book ();
+ book.append_page (1260, 1771,
+ 150,
+ ScanDirection.BOTTOM_TO_TOP);
+ }
+
+ public Application (ScanDevice? device = null)
+ {
+ default_device = device;
+
+ initialize_book ();
+
+ scanner = Scanner.get_instance ();
+ scanner.update_devices.connect (update_scan_devices_cb);
+ scanner.request_authorization.connect (authorize_cb);
+ scanner.expect_page.connect (scanner_new_page_cb);
+ scanner.got_page_info.connect (scanner_page_info_cb);
+ scanner.got_line.connect (scanner_line_cb);
+ scanner.page_done.connect (scanner_page_done_cb);
+ scanner.document_done.connect (scanner_document_done_cb);
+ scanner.scan_failed.connect (scanner_failed_cb);
+ scanner.scanning_changed.connect (scanner_scanning_changed_cb);
+
+ string[]? subsystems = { "usb", null };
+ udev_client = new GUdev.Client (subsystems);
+ udev_client.uevent.connect (on_uevent);
+
+ if (default_device != null)
+ {
+ List<ScanDevice> device_list = null;
+
+ device_list.append (default_device);
+ }
+ }
+
+ public void start ()
+ {
+ stdout.printf(_("Starting simple-scan cli.\n"));
+ scanner.start ();
+ }
+
+ public void run ()
+ {
+ loop.run ();
+ }
+
+ private void update_scan_devices_cb (Scanner scanner, List<ScanDevice> devices)
+ {
+ var devices_copy = devices.copy ();
+
+ /* If the default device is not detected add it to the list */
+ if (default_device != null)
+ {
+ var default_in_list = false;
+ foreach (var device in devices_copy)
+ {
+ if (device.name == default_device.name)
+ {
+ default_in_list = true;
+ break;
+ }
+ }
+
+ if (!default_in_list)
+ devices_copy.prepend (default_device);
+ }
+
+ have_devices = devices_copy.length () > 0;
+ //ui.set_scan_devices (devices_copy);
+
+ stdout.printf("Found scan devices. Starting\n");
+ scan ();
+ }
+
+ private void authorize_cb (Scanner scanner, string resource)
+ {
+ stderr.printf ("Authorization not implemented.\n");
+ //string username, password;
+ //scanner.authorize (username, password);
+ }
+
+ private Page append_page ()
+ {
+ /* Use current page if not used */
+ var page = book.get_page (-1);
+ if (page != null && !page.has_data ())
+ {
+ page.start ();
+ return page;
+ }
+
+ /* Copy info from previous page */
+ var scan_direction = ScanDirection.TOP_TO_BOTTOM;
+ bool do_crop = false;
+ string named_crop = null;
+ var width = 100, height = 100, dpi = 100, cx = 0, cy = 0, cw = 0, ch = 0;
+ if (page != null)
+ {
+ scan_direction = page.get_scan_direction ();
+ width = page.get_width ();
+ height = page.get_height ();
+ dpi = page.get_dpi ();
+
+ do_crop = page.has_crop ();
+ if (do_crop)
+ {
+ named_crop = page.get_named_crop ();
+ page.get_crop (out cx, out cy, out cw, out ch);
+ }
+ }
+
+ page = book.append_page (width, height, dpi, scan_direction);
+ if (do_crop)
+ {
+ if (named_crop != null)
+ {
+ page.set_named_crop (named_crop);
+ }
+ else
+ page.set_custom_crop (cw, ch);
+ page.move_crop (cx, cy);
+ }
+ page.start ();
+
+ return page;
+ }
+
+ public void scan ()
+ {
+ stdout.printf("Going to scan a page.\n");
+ if (!scanner.is_scanning ())
+ append_page();
+
+ var options = new ScanOptions ();
+ options.type = ScanType.SINGLE;
+ options.scan_mode = ScanMode.LINEART;
+ options.dpi = 150;
+ options.depth = 2;
+ options.paper_width = 0;
+ options.paper_height = 0;
+ scanner.scan(null, options);
+ }
+
+ private void scanner_new_page_cb (Scanner scanner)
+ {
+ append_page ();
+ }
+
+ private string? get_profile_for_device (string device_name)
+ {
+#if HAVE_COLORD
+ var device_id = "sane:%s".printf (device_name);
+ debug ("Getting color profile for device %s", device_name);
+
+ var client = new Colord.Client ();
+ try
+ {
+ client.connect_sync ();
+ }
+ catch (Error e)
+ {
+ debug ("Failed to connect to colord: %s", e.message);
+ return null;
+ }
+
+ Colord.Device device;
+ try
+ {
+ device = client.find_device_by_property_sync (Colord.DEVICE_PROPERTY_SERIAL, device_id);
+ }
+ catch (Error e)
+ {
+ debug ("Unable to find colord device %s: %s", device_name, e.message);
+ return null;
+ }
+
+ try
+ {
+ device.connect_sync ();
+ }
+ catch (Error e)
+ {
+ debug ("Failed to get properties from the device %s: %s", device_name, e.message);
+ return null;
+ }
+
+ var profile = device.get_default_profile ();
+ if (profile == null)
+ {
+ debug ("No default color profile for device: %s", device_name);
+ return null;
+ }
+
+ try
+ {
+ profile.connect_sync ();
+ }
+ catch (Error e)
+ {
+ debug ("Failed to get properties from the profile %s: %s", device_name, e.message);
+ return null;
+ }
+
+ if (profile.filename == null)
+ {
+ debug ("No icc color profile for the device %s", device_name);
+ return null;
+ }
+
+ debug ("Using color profile %s for device %s", profile.filename, device_name);
+ return profile.filename;
+#else
+ return null;
+#endif
+ }
+
+ private void scanner_page_info_cb (Scanner scanner, ScanPageInfo info)
+ {
+ debug ("Page is %d pixels wide, %d pixels high, %d bits per pixel",
+ info.width, info.height, info.depth);
+
+ /* Add a new page */
+ var page = append_page ();
+ page.set_page_info (info);
+
+ /* Get ICC color profile */
+ /* FIXME: The ICC profile could change */
+ /* FIXME: Don't do a D-bus call for each page, cache color profiles */
+ page.set_color_profile (get_profile_for_device (info.device));
+ }
+
+ private void scanner_line_cb (Scanner scanner, ScanLine line)
+ {
+ var page = book.get_page ((int) book.get_n_pages () - 1);
+ page.parse_scan_line (line);
+ }
+
+ private void scanner_page_done_cb (Scanner scanner)
+ {
+ var page = book.get_page ((int) book.get_n_pages () - 1);
+ page.finish ();
+
+ stdout.printf("Finished a page.\n");
+ book.save("pdf", File.new_for_path(output_name));
+ quit();
+ }
+
+ private void remove_empty_page ()
+ {
+ var page = book.get_page ((int) book.get_n_pages () - 1);
+
+ /* Remove a failed page */
+ if (page.has_data ())
+ page.finish ();
+ else
+ book.delete_page (page);
+ }
+
+ private void scanner_document_done_cb (Scanner scanner)
+ {
+ remove_empty_page ();
+ }
+
+ private void scanner_failed_cb (Scanner scanner, int error_code, string error_string)
+ {
+ remove_empty_page ();
+ if (error_code != Sane.Status.CANCELLED)
+ {
+ stderr.printf("%s: %s\n", _("Failed to scan"), error_string);
+ }
+ }
+
+ private void scanner_scanning_changed_cb (Scanner scanner)
+ {
+ }
+
+ private void quit()
+ {
+ book = null;
+ udev_client = null;
+ scanner.free ();
+
+ stdout.printf("Quit...\n");
+ loop.quit ();
+ }
+
+ private static void log_cb (string? log_domain, LogLevelFlags log_level, string message)
+ {
+ /* Log everything to a file */
+ if (log_file != null)
+ {
+ string prefix;
+
+ switch (log_level & LogLevelFlags.LEVEL_MASK)
+ {
+ case LogLevelFlags.LEVEL_ERROR:
+ prefix = "ERROR:";
+ break;
+ case LogLevelFlags.LEVEL_CRITICAL:
+ prefix = "CRITICAL:";
+ break;
+ case LogLevelFlags.LEVEL_WARNING:
+ prefix = "WARNING:";
+ break;
+ case LogLevelFlags.LEVEL_MESSAGE:
+ prefix = "MESSAGE:";
+ break;
+ case LogLevelFlags.LEVEL_INFO:
+ prefix = "INFO:";
+ break;
+ case LogLevelFlags.LEVEL_DEBUG:
+ prefix = "DEBUG:";
+ break;
+ default:
+ prefix = "LOG:";
+ break;
+ }
+
+ log_file.printf ("[%+.2fs] %s %s\n", log_timer.elapsed (), prefix, message);
+ }
+
+ /* Only show debug if requested */
+ if ((log_level & LogLevelFlags.LEVEL_DEBUG) != 0)
+ {
+ if (debug_enabled)
+ Log.default_handler (log_domain, log_level, message);
+ }
+ else
+ Log.default_handler (log_domain, log_level, message);
+ }
+
+ private void on_uevent (GUdev.Client client, string action, GUdev.Device device)
+ {
+ scanner.redetect ();
+ }
+
+ public static int main (string[] args)
+ {
+ Intl.setlocale (LocaleCategory.ALL, "");
+ Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALE_DIR);
+ Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
+ Intl.textdomain (Config.GETTEXT_PACKAGE);
+
+ var c = new OptionContext (/* Arguments and description for --help text */
+ _("[DEVICE...] - Scanning utility"));
+ c.add_main_entries (options, Config.GETTEXT_PACKAGE);
+ try
+ {
+ c.parse (ref args);
+ }
+ catch (Error e)
+ {
+ stderr.printf ("%s\n", e.message);
+ stderr.printf (/* Text printed out when an unknown command-line argument provided */
+ _("Run '%s --help' to see a full list of available command line options."), args[0]);
+ stderr.printf ("\n");
+ return Posix.EXIT_FAILURE;
+ }
+ if (show_version)
+ {
+ /* Note, not translated so can be easily parsed */
+ stderr.printf ("simple-scan-cli %s\n", Config.VERSION);
+ return Posix.EXIT_SUCCESS;
+ }
+
+ ScanDevice? device = null;
+ if (args.length > 1)
+ {
+ device = new ScanDevice ();
+ device.name = args[1];
+ device.label = args[1];
+ }
+
+
+ /* Log to a file */
+ log_timer = new Timer ();
+ var path = Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", null);
+ DirUtils.create_with_parents (path, 0700);
+ path = Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", "simple-scan-cli.log", null);
+ log_file = FileStream.open (path, "w");
+ Log.set_default_handler (log_cb);
+
+ debug ("Starting Simple Scan CLI %s, PID=%i", Config.VERSION, Posix.getpid ());
+
+ Application app = new Application (device);
+ app.start ();
+ app.run ();
+
+ return Posix.EXIT_SUCCESS;
+ }
+}
=== modified file 'src/ui.vala'
--- src/ui.vala 2011-12-08 04:37:24 +0000
+++ src/ui.vala 2012-02-04 17:34:18 +0000
@@ -652,7 +652,7 @@
var options = new ScanOptions ();
if (document_hint == "text")
{
- options.scan_mode = ScanMode.GRAY;
+ options.scan_mode = ScanMode.LINEART;
options.dpi = get_text_dpi ();
options.depth = 2;
}
Follow ups