branch: externals/scanner
commit d549ca5c36f78e6f44cc3e0ecbc9ca5b5bf01635
Author: Raffael Stocker <[email protected]>
Commit: Raffael Stocker <[email protected]>
make generation of program option lists table-driven
This commit simplifies the generation of program option lists. This is in
preparation of adding unpaper as a new backend.
Program options (switches and their arguments) are now specified as a table
instead of in the -args functions.
* scanner.el (scanner--when-switch): new function
(scanner--size): new function
(scanner--scanimage-args): now just calls scanner--program-args
(scanner--tesseract-args): now just calls scanner--program-args
(scanner--scanimage-argspec): new variable
(scanner--tesseract-argspec): new variable
(scanner--program-args): new function
---
scanner-test.el | 7 +--
scanner.el | 130 ++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 101 insertions(+), 36 deletions(-)
diff --git a/scanner-test.el b/scanner-test.el
index 64668c92b3..46645c99c6 100644
--- a/scanner-test.el
+++ b/scanner-test.el
@@ -89,6 +89,7 @@
(scanner-doc-papersize :a4)
(scanner-paper-sizes '(:a4 (210 297)))
(scanner-image-size '(200 250))
+ (scanner-image-format '(:doc "pnm" :image "tiff"))
(-compare-fn #'string=))
(should (-contains-p (scanner--scanimage-args :image switches "jpeg")
"--format=jpeg"))
@@ -105,7 +106,7 @@
(should (-is-infix-p '("-y" "250") (scanner--scanimage-args :image
switches
"jpeg")))
(should (-contains-p (scanner--scanimage-args :doc switches "jpeg")
- "--format=jpeg"))
+ "--format=pnm"))
(should (-contains-p (scanner--scanimage-args :doc switches "jpeg")
"--mode=Gray"))
(should (-contains-p (scanner--scanimage-args :doc switches "jpeg")
@@ -136,7 +137,7 @@
(scanner--make-scanimage-command
(scanner--scanimage-args :doc nil "pnm")
"outfile")))
- (should-not (string-match " > outfile$"
+ (should-not (string-match " > outfile\\'"
(car (last (scanner--make-scanimage-command
(scanner--scanimage-args :doc nil "pnm")
"outfile"))))))
@@ -149,7 +150,7 @@
(scanner--make-scanimage-command
(scanner--scanimage-args :doc nil "pnm")
"outfile")))
- (should (string-match " > outfile$"
+ (should (string-match " > outfile\\'"
(car (last (scanner--make-scanimage-command
(scanner--scanimage-args :doc nil "pnm")
"outfile")))))))
diff --git a/scanner.el b/scanner.el
index e282ddf3f7..5d3e996ad2 100644
--- a/scanner.el
+++ b/scanner.el
@@ -400,6 +400,83 @@ name, the device type, and the vendor and model names."
(--filter (= 3 (length it))
(mapcar (lambda (x) (split-string x
"|")) scanners)))))
+(defmacro scanner--when-switch (switch args form)
+ "Evaluate FORM if SWITCH is in ‘(plist-get ARGS :device-dependent)’."
+ (declare (indent 2))
+ `(when (member ,switch (plist-get ,args :device-dependent))
+ ,form))
+
+(defun scanner--size (scan-type)
+ "Return the size information appropriate for SCAN-TYPE.
+SCAN-TYPE may be either ‘:doc’ or ‘:image’. If no size is
+configured, return nil."
+ (cl-case scan-type
+ (:doc (plist-get scanner-paper-sizes
+ scanner-doc-papersize))
+ (:image scanner-image-size)
+ (t nil)))
+
+(defvar scanner--scanimage-argspec
+ (list "-d" 'scanner-device-name
+ "--format=" (lambda (args)
+ (if (eq :doc (plist-get args
:scan-type))
+ (plist-get
scanner-image-format :doc)
+ (or (plist-get args :img-fmt)
+ (plist-get
scanner-image-format :image))))
+ "--mode=" (lambda (args)
+ (scanner--when-switch "--mode" args
+ (plist-get scanner-scan-mode
+ (plist-get
args :scan-type))))
+ "--resolution=" (lambda (args)
+ (scanner--when-switch
"--resolution" args
+ (number-to-string
+ (plist-get
scanner-resolution
+
(plist-get args :scan-type)))))
+ "-x" (lambda (args)
+ (scanner--when-switch "-x" args
+ (-when-let (size (scanner--size (plist-get
args :scan-type)))
+ (number-to-string (car size)))))
+ "-y" (lambda (args)
+ (scanner--when-switch "-y" args
+ (-when-let (size (scanner--size (plist-get
args :scan-type)))
+ (number-to-string (cadr size)))))
+ 'user-switches 'scanner-scanimage-switches)
+ "The arguments list specification for scanimage.")
+
+(defun scanner--program-args (argspec &rest args)
+ "Return an arguments list as specified in ARGSPEC, assuming ARGS.
+
+ARGSPEC is expected to be a list of the form:
+ (\"--switch1\" 'argument1
+ \"--switch2=\" (lambda (args) \"bar\"))
+ \"--never-used\" nil
+ 'symbol \"--always-there\"
+ 'other-symbol (\"baz\" \"quux\"))
+
+Assuming ‘argument1’ is ‘\"foo\"’, this specification will be
+translated into the arguments list:
+ (\"--switch1\" \"foo\" \"--switch2=bar\" \"--always-there\" \"baz\"
+ \"quux\")"
+ (cl-labels ((make-option (sw val)
+ (when val
+ (if (stringp sw)
+ (if
(string-match ".=\\'" sw)
+ (list
(concat sw val))
+ (list sw
val))
+ (list val))))
+ (process-option (switch value)
+ (cond ((functionp
value)
+
(make-option switch (funcall value args)))
+ ((and
(symbolp value) (boundp value))
+
(make-option switch (symbol-value value)))
+ (value
(make-option switch value))
+ (t
nil)))
+ (process-argspec (spec)
+ (when spec
+ (nconc
(process-option (car spec) (cadr spec))
+
(process-argspec (cddr spec))))))
+ (-flatten (process-argspec argspec))))
+
(defun scanner--scanimage-args (scan-type switches img-fmt)
"Construct the argument list for scanimage(1).
SCAN-TYPE is either ‘:image’ or ‘:doc’, SWITCHES is a list of
@@ -411,27 +488,8 @@ argument for the intermediate representation before
conversion to
the document format. If any of the required options from
‘scanner--device-specific-switches’ are unavailable, they are
simply dropped."
- (let ((size (cond ((eq :doc scan-type)
- (plist-get scanner-paper-sizes
scanner-doc-papersize))
- ((eq :image scan-type)
scanner-image-size)
- (t nil))))
- (-flatten (list (and scanner-device-name
- (list "-d"
scanner-device-name))
- (concat "--format=" img-fmt)
- (--map (pcase it
- ("--mode" (concat
"--mode="
-
(plist-get scanner-scan-mode
-
scan-type)))
- ("--resolution"
- (concat
"--resolution="
-
(number-to-string
-
(plist-get scanner-resolution scan-type))))
- ((and "-x" (guard
size))
- (list "-x"
(number-to-string (car size))))
- ((and "-y" (guard
size))
- (list "-y"
(number-to-string (cadr size)))))
- switches)
- scanner-scanimage-switches))))
+ (scanner--program-args scanner--scanimage-argspec :img-fmt img-fmt
+ :scan-type scan-type
:device-dependent switches))
(defun scanner--program-version (program version-switch)
"Determine the version of PROGRAM using VERSION-SWITCH."
@@ -471,24 +529,30 @@ scanimage this will construct a shell command."
(defconst scanner--tesseract-version-dpi-switch "4.0.0"
"Minimum tesseract(1) version to have the --dpi switch.")
+(defvar scanner--tesseract-argspec
+ (list 'input-files (lambda (args) (plist-get args :input))
+ 'output-filename (lambda (args) (plist-get args :output))
+ "-l" (lambda (_)
+ (mapconcat #'identity scanner-tesseract-languages
"+"))
+ "--dpi" (lambda (_)
+ (unless (version< (scanner--program-version
+
scanner-tesseract-program
+
"--version")
+
scanner--tesseract-version-dpi-switch)
+ (number-to-string (plist-get
scanner-resolution :doc))))
+ "--tessdata-dir" 'scanner-tessdata-dir
+ 'user-switches 'scanner-tesseract-switches
+ 'outputs 'scanner-tesseract-outputs)
+ "The arguments list specification for tesseract.")
+
(defun scanner--tesseract-args (input output-base)
"Construct the argument list for ‘tesseract(1)’.
INPUT is the input file name, OUTPUT-BASE is the basename for the
output files. Note that tesseract automatically adds file name
extensions depending on the selected output options, see
‘scanner-tesseract-outputs’."
- (-flatten (list input output-base
- "-l" (mapconcat #'identity
scanner-tesseract-languages "+")
- (unless (version< (scanner--program-version
-
scanner-tesseract-program
-
"--version")
-
scanner--tesseract-version-dpi-switch)
- (list "--dpi" (number-to-string
- (plist-get
scanner-resolution :doc))))
- scanner-tesseract-switches
- "--tessdata-dir"
- scanner-tessdata-dir
- scanner-tesseract-outputs)))
+ (scanner--program-args scanner--tesseract-argspec :input input
+ :output output-base))
(defun scanner--ensure-init ()
"Ensure that scanning device is initialized.