TutoTools: PDF Classifier + Making-of
Wasserzeichen für PDF, als Text oder Bild auf dem Windows-Desktop
Unsere TutoTools-Sammlung bekommt Zuwachs: Mit dem PDF Classifier könnt Ihr Text- oder Bild-Wasserzeichen in PDFs einfügen. Genau genommen geht es darum, PDF-Dokumente einzustufen, also als "Vertraulich", "Highly Confidential" oder ähnliches zu markieren. Natürlich lässt sich der Classifier auch für Copyright-Hinweise oder Hintergrund-Dinosaurier verwenden. Anders ausgedrückt: Eine simple GUI für das Open-Source-Programm markpdf. Die Programmiersprache der Wahl: Natürlich AutoHotkey ;)
markpdf
Das plattformübergreifende markpdf dient dazu, PDF-Dokumente aus dem Terminal heraus mit Wasserzeichen zu versehen. Nun, "Wasserzeichen" werden daraus letztlich ja nur über die Transparenz und/oder gängige, vertraute Optik. Sprich: Es lassen sich Texte und Bilder einfügen, die über die überschaubaren Optionen als Wasserzeichen wahrgenommen werden.
Texte und Bilder lassen sich drehen, exakt auf der Seite platzieren und skalieren. Bilder können zudem mit Transparenz versehen werden - für Texte steht das Feature noch in der Planung. Für Texte lassen dafür drei verschiedene Schriftarten nutzen: Courier, Helvetica und Times New Roman, jeweils in unterschiedlichen Dekorationen (fett, kursiv etc.).
markpdf funktioniert einwandfrei, besteht nur aus einer einzigen ausführbaren Datei und benötigt eigentlich keine grafische Oberfläche - der Aufruf ist einfach genug:
markpdf eingabe.pdf Hallo Welt ausgabe.pdf --offset-x=20 --offset-y=20 --angle=45 font-size=15 color=ff0000
Damit würde der Text "Hallo Welt" gesetzt, gedreht um 45 Grad, in Rot und mit je 20 Pixeln Abstand zum linken und oberen Rand. Wenn man so etwas häufiger benötigt, kann man das wunderbar als kleines Skript umbauen und Dateien dann schlicht per Drag&Drop markieren. Oder man baut sich eine GUI ...
markpdf-GUI mit AutoHotkey
Wenn man hier ein seriöses Tool bauen wollen würde, wäre Python freilich die bessere Wahl - so bleibt es eine Windows-only-GUI. Aber ich spiele nun mal lieber mit AutoHotkey, daher auch die vielen Beiträge dazu. Das einzige nicht umgesetzte Feature: Schriftartenauswahl. Und so sieht sie aus:
Nein, kein Eye-Candy, nur Nutzfläche. Die Funktionsweise sollte selbsterklärend sein. Die Ausgabedatei heißt dabei immer EINGABEDATEI_classified.pdf, also zum Beispiel eingabe.pdf_classified.pdf. So bleibt das Original erhalten. Hier mal ein Beispiel mit Text-Wasserzeichen:
Und jetzt ein Bild-Wasserzeichen:
Mit den Werten müsst Ihr ein wenig Herumspielen, die Vorgaben sollten aber klar machen, was erwartet wird; also zum Beispiel Farben in Hex-Notation, Skalierung in Prozent etc. Wenn Ihr wie oben Text als Bild nutzen wollt: Erstellt einfach mit Gimp oder sonst einem Grafikprogramm eine PNG-Datei mit transparentem Hintergrund und stellt Text in den Vordergrund - so lässt sich die noch fehlende Text-Transparenz super kompensieren.
Erwartet bitte nicht zu viel: Soweit funktioniert das alles, aber das Ding ist jetzt nicht lange getestet worden und die GUI validiert auch keine Eingaben - wenn etwas nicht funktioniert, bricht das Programm einfach ab. Die GUI ist auch nur für diesen Artikel und ein kurzes Proof of Concept entstanden. Und natürlich zum Lernen - daher nun auch das Making of.
Making of
Im Folgenden ein Überblick über den Code und dazu ein paar Erklärungen. Wir haben aber auch einen ausführlichen Artikel zum GUI-Bau mit AutoHotkey. Der erste Part ist der reine GUI-Bau, hier zum Beispiel die Elemente "Choose PDF", "Classification" und "Classify with text".
Gui Add, Button, gselection x200 y16 w80 h23, Choose PDF
Gui Add, ComboBox, vclassification x88 y100 w120, Public|Internal|Confidential||Highly_Confidential
Gui Add, Button, ggo x8 y400 w150 h23, &Classify with text
Interessant sind hier vor allem die dritten Einträge jeder Zeile: Das g in gselection und ggo ist ein "G-Label" (Gosub), also quasi ein Go-To-Befehl. Bei Klick auf den Button wird entsprechend ausgeführt, was auch immer weiter unten unter go: beziehungsweise selection: steht - dort wohlgemerkt ohne das g davor.
Das v von vclassification ordnet der Auswahlbox eine Variable zu. Die Optionen des Dialogs stehen hinten, getrennt durch |. Soll eine Option vorgegeben werden, wie hier Confidential, folgt dahinter ||. Übrigens: Das sind nur Vorschläge, in der GUI lässt sich auch frei Text eingeben.
Nun folgen die beiden zugehörigen Labels und die Funktionen, zunächst selection:
selection:
FileSelectFile, mypdf
return
Der "Choose PDF"-Button triggert den Standard-Dateiauswahldialog und speichert den Pfad der gewählten PDF-Datei in der Variablen mypdf.
Und nun go:
go:
Gui, submit
Run, markpdf.exe %mypdf% "%classification2%" %mypdf%_classified.pdf --offset-x=%xoffset% --offset-y=%yoffset% --font-size=%fontsize% --angle=%angle% --color=%color%
Gui, Restore
return
Per Klick auf den "Classify with text"-Button wird zum Label go gesprungen. Es folgt zunächst Gui, submit. Damit werden die in der GUI zugewiesenen Werte in ihren Variablen gespeichert. Anschließend wird direkt markpdf aufgerufen - mit den eben aufgeführten Werten der Variablen mypdf und classification. Plus die übersprungenen Variablen Für Offsets, Angle, Font-size und Color. Wichtig: Der Befehl Gui, return lässt die Oberfläche "leben" - ansonsten würde die GUI verschwinden. Das return markiert dann das Ende der Subroutine.
Im Bereich für Bilder sieht es am Ende etwas komplizierter aus: Bei Wahl einiger Optionen werden andere Optionen ignoriert - beispielsweise die Offsets, wenn die Option Center gewählt wird. Daher gibt es für den "Classify with image"-Button einen kleinen Entscheidungsbaum, der die Optionen zusammensetzt und in der Variablen options speichert - hier eine der vier If-Abfragen:
If tiles = 1
{
options = --opacity=%opacity% --angle=%angle2% --scale=%scale% --tiles --spacing=%spacing%
}
Run, markpdf.exe %mypdf% "%image%" %mypdf%_classified.pdf %options%
If fragt also, ob die Tiles-Option "1", sprich gecheckt ist und setzt dann die hier gültigen Optionen Opacity, Angle, Scale und eben Tiles samt Spacing. Der Run-Befehl startet markpdf entsprechend wieder mit Eingabedatei, Bild, Ausgabedatei plus die in options gespeicherten Optionen.
Ein Tipp zum Schluss: Im Artikel zum GUI-Bau mit AutoHotkey verweise ich auf das Design-Tool AutoGUI. Für die komplette Entwicklung taugt es absolut nicht! Ändert man nämlich manuell den von AutoGUI generierten Code, lässt sich das Vorschaufenstern nicht mehr aufrufen - sprich AutoGUI funktioniert dann schlicht gar nicht mehr. Aber AutoGUI ist super, um sich ein Grundlayout zu bauen. Ist der Code für Buttons und sonstige Elemente einmal im Editor, lässt sich mit Copy&Paste super schnell eine GUI zusammenbasteln.
Mehr zum Thema AutoHotkey. Oder vielleicht direkt zu einer AutoHotkey-basierten Schaltleiste? Oder einer völlig wirren Bastelei?
Anhang
Zunächst El Tutos PDF Classifier als ZIP: markpdf ist mit dabei, die GUI findet Ihr als AHK-Version, also reines AutoHotkey-Skript, sowie als EXE-Version - falls Ihr AutoHotkey selbst nicht installieren woll.
Falls Ihr keinen Bock auf Downloads habt, hier der komplette Quelltext:
#NoEnv
#SingleInstance Force
SetWorkingDir %A_ScriptDir%
Menu Tray, Icon, %A_ScriptDir%\tuto-icon.ico
;;; The GUI
Gui Add, Button, gselection x200 y16 w80 h23, Choose PDF
Gui Add, Text, x0 y53 w500 h2 0x10
Gui Add, Text, x250 y53 w2 h347 0x11
;Text options
Gui Add, ComboBox, vclassification x88 y100 w120, Public|Internal|Confidential||Highly_Confidential
Gui Add, Edit, vxoffset x88 y130 w70 h21, 10
Gui Add, Edit, vyoffset x88 y160 w70 h21, 70
Gui Add, Edit, vcolor x88 y190 w70 h21, FF0000
Gui Add, Edit, vfontsize x88 y220 w70 h21, 12
Gui Add, Edit, vangle x88 y250 w70 h21, 45
Gui Add, Text, x8 y72 w70 h23 +0x200, Text options
Gui Add, Text, x8 y96 w65 h23 +0x200, Classification
Gui Add, Text, x8 y130 w65 h23 +0x200, X-Offset
Gui Add, Text, x8 y160 w65 h23 +0x200, Y-Offset
Gui Add, Text, x8 y190 w65 h23 +0x200, Color
Gui Add, Text, x8 y220 w65 h23 +0x200, Font size
Gui Add, Text, x8 y250 w65 h23 +0x200, Angle
Gui Add, Button, ggo x8 y400 w150 h23, &Classify with text
;Image option
Gui Add, Text, x292 y72 w70 h23 +0x200, Image options
Gui Add, Button, gimage x372 y100 w120, Choose image
Gui Add, Edit, vxoffset2 x372 y130 w70 h21, 10
Gui Add, Edit, vyoffset2 x372 y160 w70 h21, 70
Gui Add, Edit, vopacity x372 y190 w70 h21, 0.5
Gui Add, Edit, vscale x372 y220 w70 h21, 100
Gui Add, Edit, vangle2 x372 y250 w70 h21, 45
Gui Add, CheckBox, vcenter x292 y280, Center (offsets ignored)
Gui Add, CheckBox, vstretchtop x292 y310, Stretch top (offsets, scale ignored)
Gui Add, CheckBox, vstretchmiddle x292 y340, Stretch middle (overrides stretch top)
Gui Add, CheckBox, vtiles x292 y370, Tiles with Spacing:
Gui Add, Edit, vspacing x405 y370 w30 h21, 20
Gui Add, Text, x292 y100 w65 h23 +0x200, Classification
Gui Add, Text, x292 y130 w65 h23 +0x200, X-Offset
Gui Add, Text, x292 y160 w65 h23 +0x200, Y-Offset
Gui Add, Text, x292 y190 w65 h23 +0x200, Opacity
Gui Add, Text, x292 y220 w65 h23 +0x200, Scale
Gui Add, Text, x292 y250 w65 h23 +0x200, Angle
Gui Add, Button, ggo2 x292 y400 w150 h23, &Classify with image
; Exit button
Gui Add, Button, gexit x200 y400 w80 h23, &Exit
Gui Show, w500 h450, Window
Return
GuiEscape:
GuiClose:
ExitApp
;;; Main
; Variables
global mypdf
global classification
global center
global stretchtop
global stretchmiddle
global centerize
global stretcherizemiddle
global stretcherizetop
; PDF selection
selection:
FileSelectFile, mypdf
; Optional for compiling into exe:
;FileInstall, markpdf.exe, %A_WorkingDir%\markpdf.exe, 1
;FileInstall, copying.txt, %A_WorkingDir%\copying.txt, 1
return
; Image selection
image:
FileSelectFile, image
return
; Start text classification
go:
Gui, submit
If classification = Highly_Confidential
{
classification2 := "Highly Confidential"
}
else
{
classification2 := classification
}
Run, markpdf.exe %mypdf% "%classification2%" %mypdf%_classified.pdf --offset-x=%xoffset% --offset-y=%yoffset% --font-size=%fontsize% --angle=%angle% --color=%color%
Gui, Restore
return
; Start image classification
go2:
Gui, submit
options = --offset-x=%xoffset2% --offset-y=%yoffset2% --opacity=%opacity% --angle=%angle2% --scale=%scale%
If center = 1
{
centerize = --center
options = --opacity=%opacity% --angle=%angle2% --scale=%scale% %centerize%
}
If stretchtop = 1
{
stretcherizetop = -w
options = --opacity=%opacity% %stretcherizetop%
}
If stretchmiddle = 1
{
stretcherizemiddle = -W
options = --opacity=%opacity% %stretcherizemiddle%
}
If tiles = 1
{
options = --opacity=%opacity% --angle=%angle2% --scale=%scale% --tiles --spacing=%spacing%
}
Run, markpdf.exe %mypdf% "%image%" %mypdf%_classified.pdf %options%
Gui, Restore
return
exit:
ExitApp
Fragen, Verbesserungen und Häme bitte in die Kommentare. (Wohin auch sonst frage ich mich immer, blöde Floskeln ...)
Und hier noch etwas schicke Hardware als perfekte AutoHotkey-Ergänzung: