Wenn ich im Büro mal etwas ausdrucken muss, dann ist es in den meisten ein Fällen ein PDF, welches ich erst einmal mit der Vorschau oder dem Acrobat öffnen muss, dann den Druckdialog öffnen und auswählen, ob Schwarz/Weiß oder farbig und ob A3 oder A4. Vielleicht noch einen Haken setzen, dass duplex gedruckt werden soll.
Viel schneller geht das mit einem Hotfolder (bzw. mehreren Hotfolder je nach Farbigkeit und Format), in welchen ich das PDF einfach reinschmeiße und mich um alles andere nicht mehr kümmern muss.

Eingerichtet habe ich meinen "Drucker-Hotfolder" auf einem Ubuntu-Server mit der rechts abgebildeten Unterordner-Hierarchie.
Je nachdem, wo ich mein PDF rein kopiere, kommt es in einem anderen Format, Farbigkeit oder (bei mehrseitigen PDFs) auf Wunsch als Duplex-Druck aus dem Drucker.
Der Ordner Titelumlauf-Ausland ist noch ein kleiner Sonderfall: Bestimmte Ausdrucke bekommen normalerweise noch einen Zettel hinten aufgeklebt. Diesen füge ich hier automatisch dem PDF im Duplex-Druck hinzu. Je nach Dateinamen der PDF-Datei drucke ich auch noch etwas Text auf diesen angefügten Zettel.

Alle Hotfolder überwachen


Andere Hotfolder auf dem Server überwache ich per incron auf neue Dateien.
incron kann allerdings keine Unterordner auf Änderungen überwachen, so bin ich für meinen Drucker-Hotfolder auf das Python-Skript watcher ausgewichen, um nicht zig einzelne incron-Jobs anlegen zu müssen.

Die Config-Datei für watcher sieht wie folgt aus:

~/.watcher/jobs.yml
job1:
  label: Drucker /home/apfelz/hotfolders/Drucken
  watch: /home/apfelz/hotfolders/Drucken
  exclude: []
  events: ['create', 'move_to']
  options: []
  recursive: true
  command: /home/apfelz/scripts/drucken.pl '$filename' $watched $tflags

Sobald watcher läuft (

watcher.py start
), überwacht es im oben angegebenen Fall den Ordner
/home/apfelz/hotfolders/Drucken
und sämtliche Unterordner auf neue Dateien und ruft das Skript
/home/apfelz/scripts/drucken.pl
auf, sobald neue Dateien hineinverschoben (
move_to
) oder hineinkopiert (
create
) wurden.

Das Skript bekommt noch die drei Parameter

filename
(Absoluter Pfad zur neuen Datei; beinhaltet also auch
watched
),
watched
(Absoluter Pfad zum ausgelösten Hotfolder) und
tflags
(Art der Auslösung. In dem Fall auf create oder move_to beschränkt) mit.

Da der Dateiname innerhalb von

$filename
Leerezeichen enthalten könnte, sollte es an dieser Stelle gequotet werden.
$watched
natürlich auch, sollte der zu überwachende Hotfolder oder dessen Überordner Leerzeichen enthalten (in oberem Beispiel nicht der Fall).

Bei Änderungen an der

.yml
-Konfigurationsdatei muss watcher neu geladen werden. Die Steuerungsbefehle lauten:

watcher.py start|stop|restart

Was man so braucht

Ich habe direkt im CUPS den gewünschten Drucker angelegt. Im weiteren Verlauf taucht dieser unter dem Namen
Sharp-MX-6240
auf.

Das Skript greift auf folgende Programme zurück, die nicht standardmäßig installiert sein mögen:

  • GhostScript
  • cpdf, um Text auf dem Ausdruck hinzuzufügen (nur für meinen "Spezialordner" Titelumlauf-Ausland; kann ansonsten weggelassen werden)
  • pdftk Server, um mehrere PDFs zu einem zu vereinen (nur für meinen "Spezialordner" Titelumlauf-Ausland; kann ansonsten weggelassen werden)

Dieses Skript ist bei mir selbst noch mehr oder weniger in der Beta-Phase.
Ich habe noch nicht alle Hotfolder mit allen möglichen PDFs (A4/A3, Hoch/Quer, bunt/schwarzweiß, einseitig/mehrseitig) getestet. Von dem her: Viel Glück beim selbst-etwas-experimentieren ;-)

Skript, welches die PDFs verarbeitet

/home/apfelz/scripts/drucken.pl
#!/usr/bin/perl

use strict;

my $file      = @ARGV[0];
my $hotfolder = @ARGV[1];
my $trigger   = @ARGV[2];

# Wurden keine Argumente mitgegeben, weil ich per Kommandozeile gestartet wurde?
# (um zu verhindern, dass im weiteren Verlauf mit 'rm' Schlimmes passiert)
if ($hotfolder eq "" || $file eq "" || $trigger eq "") {
  print "Dieses Skript wird per watcher.py ausgefuehrt und kann nicht per Kommandozeile gestartet werden!\n";
  exit(0);
  }

# watcher löst auch bei .resourcen-Dateien aus. Abfangen
if ($file =~ m/\/\.[^\/]+$/) { system "rm '$file'"; exit(0); }

# Wenn's kein PDF ist, machen wir garnichts
if ($file !~ m/\.pdf$/i) { exit(0); }

# Wenn jemand den Ordner direkt in das Verzeichnis kopiert,
# fängt die Skriptverarbeitung vielleicht schon während des Kopiervorgangs an.
# Lieber ein paar Sekunden warten...
if ($trigger =~ m/create/i) { sleep(15); }


#
# Dann kann's ja eigentlich los gehen...
#

my ($s, $i, $h, $d, $m, $y, $wd, $yd, $ds) = localtime();
my ($farbe, $format, $duplex, $name) = "";

if ($file =~ m/\/(Graustufen|Farbig)\/(A3|A4)\/(Einzelseiten|Duplex|Titelumlauf-Ausland)\/(.*)$/) {
  $farbe  = $1;
  $format = lc($2);
  $duplex = $3;
  $name   = $4;
  }
       
# Datei ist in irgend einem anderen Verzeichnis, das uns nicht interessiert.
# Löschen und Abbrechen
if ($farbe eq "" || $format eq "" || $duplex eq "" || $name eq "") {
  system "rm '$file'";
  exit(0);
  }

# watcher löst auch bei .resourcen-Dateien aus. Abfangen
# (Nochmals. Das habe ich weiter oben schon gemacht, aber will nicht immer funktionieren)
if ($name =~ m/^\./) { system "rm '$file'"; exit(0); }

my $tmp    = "/tmp/druck$h$i$s";
my $cmd    = "-dPDFFitPage -dNoOutputFonts -sPAPERSIZE=$format";
if ($farbe eq "Graustufen") {
  $cmd .= " -sProcessColorModel=DeviceGray -sColorConversionStrategy=Gray -dOverrideICC";
} else {
  $cmd .= " -sColorConversionStrategy=/LeaveColorUnchanged -dAutoFilterColorImages=true -dAutoFilterGrayImages=true";
  }

# Sonderfall Ordner "Titelumlauf-Aufdruck".
# Hier hängen wir noch eine feste Seite hinten ans PDF ran
# Pfad zu dieser Seite: /home/apfelz/resources/titelumlauf-ausland.pdf
if ($duplex eq "Titelumlauf-Ausland") {
  my $tmp2  = "/tmp/druck$h$i$s.pdf";
  my $tmp3  = "/tmp/ul$h$i$s.pdf";
  my $datum = "$d.$m.20$y";
  `cpdf -add-text "$datum" -pos-left "97mm 245mm" -font "Courier" -font-size 12 /home/apfelz/resources/titelumlauf-ausland.pdf -o $tmp3`;
  # Beginnt der Dateiname der auszudruckenden Datei mit Zahlen oder "obj"+Zahlen?
  # Dann drucken wir diese Zahlen auch noch mit auf das Formular drauf
  if ($name =~ m/(obj|^)(\d+)-?/) { `cpdf -add-text "$2" -pos-left "128mm 261mm" -font "Courier" -font-size 12 $tmp3 -o $tmp3`; }
  # Beinhaltet der Dateiname der auszudruckenden Datei "+he"?
  # Dann drucken wir den Text, der auf dieses "+he" folgt, auch noch mit auf
  if ($name =~ m/\+he([^-#]+)/) { `cpdf -add-text "$1" -pos-left "104mm 273mm" -font "Courier" -font-size 12 $tmp3 -o $tmp3`; }
  `pdftk '$file' $tmp3 output '$tmp2'`;
  `rm '$file'`;
  `rm '$tmp3'`;
  $file   = $tmp2;
  $duplex = "Duplex";
  }

# Für etwas komplexere PDFs, die ansonsten zerstückelt aus dem Drucker kommen
$cmd .= " -dDownsampleMonoImages=true -dDownsampleGrayImages=true -dDownsampleColorImages=true -dColorImageDownsampleType=/Bilinear -dGrayImageDownsampleType=/Bilinear ";
$cmd .= " -dColorImageResolution=150 -dGrayImageResolution=150 -dMonoImageResolution=250 -dColorImageDownsampleThreshold=1.0 -dGrayImageDownsampleThreshold=1.0 -dMonoImageDownsampleThreshold=1.0 -dNoOutputFonts ";

# In temporäres PostScript konvertieren
# (mit allen vorher je Hotfolder beschlossenen Konvertierungsmaßnahmen)
`gs -sDEVICE=ps2write $cmd -o $tmp.ps -f '$file' 2>/dev/null`;
# Druckauftrag absenden
$cmd = "";#"-o fit-to-page";
if ($duplex eq "Duplex") { $cmd .= " -o sides=two-sided-long-edge"; }

`lp -d Sharp-MX-6240 $cmd $tmp.ps`; # Sharp-MX-6240 ist der CUPS-Druckername
`rm '$file'`;
`rm $tmp*`;