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== | ||