branch: externals/scanner commit d549ca5c36f78e6f44cc3e0ecbc9ca5b5bf01635 Author: Raffael Stocker <r.stoc...@mnet-mail.de> Commit: Raffael Stocker <r.stoc...@mnet-mail.de>
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.