Scanners: Difference between revisions

imported>Tobias.bora
m Oups forgot to remove one useless headline
imported>Csingley
No edit summary
Line 162: Line 162:
  ...
  ...
}</syntaxhighlight>
}</syntaxhighlight>
==Using the scanner button==
Many scanners feature a hardware button which makes for very convenient operation, especially in combination with an automated document processing system like <tt>paperless</tt>.  NixOS includes the scanner button daemon <tt>scanbd</tt> which can be used for this purpose; however, its setup isn't terribly user friendly.
Basic <tt>scanbd</tt> configuration requires us to provide:
# a config file;
# a script to execute the scanning sequence;
# a systemd service that loads the config file, starts polling the scanner, and executes the script when it detects a button press.
{{Tip|As <tt>scanbd</tt> continuously polls the scanner, it can't be used at the same time by SANE, which must be disabled.}}
There is a more advanced configuration which allows sharing the scanner with SANE frontends, but I haven't yet figured out how to set this up under NixOS (the config is a bit recursive).
Full documentation is in [https://sourceforge.net/p/scanbd/code/HEAD/tree/releases/1.5.1/doc/README.txt the project README].
[https://kliu.io/post/automatic-scanning-with-scansnap-s500m/ kliu's blog] includes in his writeup a nice script, bits of which have been cribbed here.
Here is a working derivation that dumps the scanned document into the <tt>paperless</tt> intake directory; you'll need to modify it to suit your own needs.
<syntaxhighlight lang="nix">
{ config, lib, pkgs, ... }:
with lib;
let
  configDir = "/etc/scanbd";
  saneConfigDir = "${configDir}/sane.d";
  scanbdConf = pkgs.writeText "scanbd.conf"
    ''
      global {
        debug = true
        debug-level = ${toString config.services.scanbd.debugLevel}
        user = ${config.services.scanbd.user}
        group = ${config.services.scanbd.group}
        scriptdir = ${configDir}/scripts
        pidfile = ${config.services.scanbd.pidFile}
        timeout = ${toString config.services.scanbd.timeOut}
        environment {
          device = "SCANBD_DEVICE"
          action = "SCANBD_ACTION"
        }
        multiple_actions = true
        action scan {
          filter = "^scan.*"
          numerical-trigger {
            from-value = 1
            to-value = 0
          }
          desc = "Scan to file"
          script = "scan.script"
        }
        ${config.services.scanbd.extraConfig}
      }
    '';
  scanScript = pkgs.writeScript "scanbd_scan.script"
    ''
      #! ${pkgs.bash}/bin/bash
      export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.sane-frontends pkgs.sane-backends pkgs.ghostscript pkgs.imagemagick ]}
      set -x
      date="$(date --iso-8601=seconds)"
      filename="Scan $date.pdf"
      tmpdir="$(mktemp -d)"
      pushd "$tmpdir"
      scanadf -d "$SCANBD_DEVICE" --source "ADF Duplex" --mode Gray --resolution 200dpi
      # Convert any PNM images produced by the scan into a PDF with the date as a name
      convert image* -density 200 "$filename"
      chmod 0666 "$filename"
      # Remove temporary PNM images
      rm --verbose image*
      # Atomic move converted PDF to destination directory
      paperlessdir="/var/lib/paperless/consume"
      cp -pv "$filename" $paperlessdir/"$filename".tmp &&
      mv $paperlessdir/"$filename".tmp $paperlessdir/"$filename" &&
      rm "$filename"
      popd
      rm -r "$tmpdir"
    '';
in
{
  ###### interface
  options = {
    services.scanbd.enable = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Enable support for scanbd (scanner button daemon).
        <note><para>
          If scanbd is enabled, then saned must be disabled.
        </para></note>
      '';
    };
    services.scanbd.user = mkOption {
      type = types.str;
      default = "scanner";
      example = "";
      description = ''
        scanbd daemon user name.
      '';
    };
    services.scanbd.group = mkOption {
      type = types.str;
      default = "scanner";
      example = "";
      description = ''
        scanbd daemon group name.
      '';
    };
    services.scanbd.extraConfig = mkOption {
      type = types.lines;
      default = "";
      example = ''
        device canon {
          filter = "^genesys.*"
          desc = "Canon LIDE"
          action file {
            filter = "^file.*"
            desc = "File"
            script = "copy.script"
          }
        }
        '';
      description = ''
        Extra configuration lines included verbatim in scanbd.conf.
        Use e.g. in lieu of including device-specific config templates
        under scanner.d/
      '';
    };
    services.scanbd.pidFile = mkOption {
      type = types.str;
      default = "/var/run/scanbd.pid";
      example = "";
      description = ''
        PID file path.
      '';
    };
    services.scanbd.timeOut = mkOption {
      type = types.int;
      default = 500;
      example = "";
      description = ''
        Device polling timeout (in ms).
      '';
    };
    services.scanbd.debugLevel = mkOption {
      type = types.int;
      default = 3;
      example = "";
      description = ''
        Debug logging (1=error, 2=warn, 3=info, 4-7=debug)
      '';
    };
  };
  ###### implementation
  config = mkIf config.services.scanbd.enable {
      users.groups.scanner.gid = config.ids.gids.scanner;
      users.users.scanner = {
        uid = config.ids.uids.scanner;
        group = "scanner";
      };
      environment.etc."scanbd/scanbd.conf".source = scanbdConf;
      environment.etc."scanbd/scripts/scan.script".source = scanScript;
      environment.etc."scanbd/scripts/test.script".source = "${pkgs.scanbd}/etc/scanbd/test.script";
      systemd.services.scanbd = {
        enable = true;
        description = "Scanner button polling service";
        documentation = [ "https://sourceforge.net/p/scanbd/code/HEAD/tree/releases/1.5.1/integration/systemd/README.systemd" ];
        script = "${pkgs.scanbd}/bin/scanbd -c ${configDir}/scanbd.conf -f";
        wantedBy = [ "multi-user.target" ];
        aliases = [ "dbus-de.kmux.scanbd.server.service" ];
      };
}</syntaxhighlight>


==See also==
==See also==