vorgestern hatte ich plötzlich eine Idee für eine technische Umsetzung eines eigentlich nicht vorhandenen Problems.
Ich bin kein allzu großer Fan der Ausführung von command-line-tools in meinen Autohotkey-Skripten.
Es dauert mir einfach zu lange bis alle Operationen durchgeführt sind, da die Tools bei jedem Durchlauf von der Festplatten ins RAM geladen werden um ausgeführt werden zu können.
Die Daten die ich erhalten möchte, lassen sich auch leider nie direkt in der Konsole ausgeben, so daß zig Schreibzugriffe erfolgen.
Bisher habe ich die Xpdf command line tools benutzt. Sind tolle kleine Tools.
Was mich trotz Open Source und der GPL Lizenz stört ist das vorhandene Copyright der Firma Glyph & Cog.
Es gibt noch andere "freie" PDF-Bibliotheken, aber soweit mir bekannt, gibt es keine wirklich freie Software für Windows ohne den genannten Background.
Langer Vorspann, unbedingt nicht kürzer gehaltene Anfrage!
Könntet Ihr den Skript-Code mit verschiedenen PDF-Versionen testen. Ich habe ausschließlich PDF 1.3 oder 1.4 auf meinen Festplatten. Kein PDF/A oder irgendwas anderes.
Das Skript kann noch nicht viel, da ich derzeit nur an den OCR-Text, Metadaten und enthalten Bilddateien kommen wollte.
Allerdings bin ich verdammt erstaunt, das ich das in verhältnismäßig kurzer Zeit hinbekommen habe, zumal alle Daten in einem "Rutsch" extrahiert werden und ich keine 3 einzelnen Programme dafür einsetzen muss.
Der Inhalt einer 1-seitigen PDF Datei wird bei mir im Durchschnitt in 0.35s auf Festplatte ausgegeben (die Festplattenausgabe ist nur für Testzwecke hier im Forum geschrieben).
Ich würde gern wissen ob das tatsächlich so problemlos auch mit allen möglichen PDF Dateien funktioniert.
Ein paar Ungereimtheiten gibt es bei mir bezüglich der genutzten Datenlängen. Es funktioniert bei mir und allzu viel Zeit für detailliertes Nachforschen habe ich seit Monaten nicht mehr.
Ich freue mich auf Eure Hinweise.
Code: Select all
; nearly native Autohotkey PDF2Text and PDF2jpg solution (very useless version!)
; not so quick but very dirty version
; version date: 21.10.2020
;
; you need a copy of zlib1.dll (gz compression and decompression library) for deflating some PDF stream contents
; download link: http://www.winimage.com/zLibDll/zlib123.zip
;
; Autohotkey zlib1 wrapper functions are developed by shajul
; link: https://autohotkey.com/board/topic/63343-zlib/
;
; tested with Autohotkey V1.1.33.2 64bit Unicode on Windows 10
; works with some PDF Version 1.3 & 1.5 files
#NoEnv
SetBatchLines, -1
inflates := Object()
picnr := 1
pdfPath := A_ScriptDir "\test1.pdf"
savePath := A_ScriptDir
SplitPath, pdfPath, pdfname
If !(pdfFile := FileOpen(pdfPath, "r", "CP1252")) {
MsgBox, % "can't open PDF File:`n" pdfPath
ExitApp
}
savefile := FileOpen(savePath "\" "-decoded.txt", "w", "UTF-8")
while !pdfFile.AtEof {
If (StrLen(line := StrReplace(pdfFile.ReadLine(), "`r`n")) = 0)
continue
If RegExMatch(line, "\>stream$") {
RegExMatch(line, "Length\s(?<seek>\d+)", file)
maxbytes := pdfFile.RawRead(tmpvar, fileseek)
out := ""
If RegExMatch(line, "\/Image") {
If RegExMatch(line, "\/DCTDecode") {
out := "jpeg image (Filter: DCTDecode) , filename: pic" picnr ".jpg"
picfile := FileOpen(A_ScriptDir "\pic" picnr ".jpg", "w")
picfile.RawWrite(tmpvar, fileseek)
picfile.Close()
}
}
else if RegExMatch(line, "\/Metadata") {
out := StrGet(&tmpvar, fileseek, "CP1252")
}
else {
osize := zlib_Decompress(deflate, tmpvar, maxbytes*4)
deflate := StrGet(&deflate, maxbytes*4, "CP1252")
If RegExMatch(deflate, "\(.*\)") {
rxpos := 1
out := "<<hocr_data>>`n" deflate "`n`n<<plain_text>>`n"
while, (fpos := RegExMatch(deflate, "\((?<word>[^\)]+)\)", m, rxpos)) {
out .= mword (RegExMatch(mword, "\.\s*$") ? "`n" : " ")
rxpos := fpos + StrLen(mword)
}
out := RTrim(out, "`n<<plain_text>>`n")
out := RegExReplace(out, "`n`n", "`n")
}
else {
out := deflate
}
}
savefile.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
savefile.WriteLine(RegExReplace(line, "(\>)stream$", "$1"))
savefile.WriteLine("file pointer: " SubStr("00000" pdfFile.pos, -4))
savefile.WriteLine("<< datastream bytes -pdf data: " fileseek " / -fileread: "maxbytes ">> | StrLen -deflated string: " StrLen(deflate) ", tmpvar: " StrLen(tmpvar))
savefile.WriteLine("<<original size: " osize " , datastream bytes -pdf data: " fileseek " / -fileread: "maxbytes ">> | StrLen -deflated string: " StrLen(deflate) ", tmpvar: " StrLen(tmpvar))
savefile.WriteLine("-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
savefile.WriteLine(out "`n")
}
}
pdfFile.Close()
saveFile.Close()
ExitApp
/*
Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_NEED_DICT 2
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
#define Z_VERSION_ERROR (-6)
Compression levels.
#define Z_NO_COMPRESSION 0
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_DEFAULT_COMPRESSION (-1)
*/
zlib_Compress(Byref Compressed, Byref Data, DataLen, level = -1) {
; http://www.autohotkey.com/forum/viewtopic.php?t=68170
nSize := DllCall("zlib1\compressBound", "UInt", DataLen, "Cdecl")
VarSetCapacity(Compressed,nSize)
ErrorLevel := DllCall("zlib1\compress2", "ptr", &Compressed, "UIntP", nSize, "ptr", &Data, "UInt", DataLen, "Int"
, level ;level 0 (no compression), 1 (best speed) - 9 (best compression)
, "Cdecl") ;0 means Z_OK
return ErrorLevel ? 0 : nSize
}
zlib_Decompress(Byref Decompressed, Byref CompressedData, DataLen, OriginalSize = -1) {
; http://www.autohotkey.com/forum/viewtopic.php?t=68170
OriginalSize := (OriginalSize > 0) ? OriginalSize : DataLen*10 ;should be large enough for most cases
VarSetCapacity(Decompressed,OriginalSize)
ErrorLevel := DllCall("zlib1\uncompress", "Ptr", &Decompressed, "UIntP", OriginalSize, "Ptr", &CompressedData, "UInt", DataLen)
return ErrorLevel ? 0 : OriginalSize
}
gz_compress(infilename, outfilename) {
; http://www.autohotkey.com/forum/viewtopic.php?t=68170
VarSetCapacity(sOutFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", outfilename, "int", -1, "str", sOutFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := FileOpen(infilename, "r")
outfile := DllCall("zlib1\gzopen", "Str" , sOutFileName , "Str", "wb", "Cdecl")
if (!infile || !outfile)
return 0
nBufferLen := 8192 ; can be increased if gzbuffer function is called beforehand
VarSetCapacity(inbuffer,nBufferLen)
while ((num_read := infile.RawRead(inbuffer, nBufferLen)) > 0)
DllCall("zlib1\gzwrite", "UPtr", outfile, "UPtr", &inbuffer, "UInt", num_read, "Cdecl")
infile.Close()
DllCall("zlib1\gzclose", "UPtr", outfile, "Cdecl")
return 1
}
gz_decompress(infilename, outfilename) {
;http://www.autohotkey.com/forum/viewtopic.php?t=68170
VarSetCapacity(sInFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", infilename, "int", -1, "str", sInFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := DllCall("zlib1\gzopen", "Str" , sInFileName , "Str", "rb", "Cdecl")
outfile := FileOpen(outfilename, "w")
if (!infile || !outfile)
return 0
VarSetCapacity(buffer,8192) ;can be increased after calling gzbuffer beforehand
num_read = 0
while ((num_read := DllCall("zlib1\gzread", "UPtr", infile, "UPtr", &buffer, "UInt", 8192, "Cdecl")) > 0)
outfile.RawWrite(buffer, num_read)
DllCall("zlib1\gzclose", "UPtr", infile, "Cdecl")
infile.Close()
return 1
}