Zugriff auf GhostScript (PDF erstellen u. v. m.)

  • PDF-Dateien erstellen, bearbeiten, zusammenstellen usw. kann man mit GhostScript . Der Weg über die Kommandozeile erfordert immer zusätzlichen Ressourcen und manchmal auch zusätzliche Rechte (W2K3). Da ist der Zugriff über die DLL günstiger. Die kleine UDF _gs_dll_2PDF() in gs_dll.au3 organisiert das.
    Die UDF _gs_dll_warg() kann direkt mit einem Array aufgerufen werden und so viele Dateien auf einmal zur Verabreitung entgegen nehmen (getestet mit 400 PDF-Dateien), auf der Kommandozeile ist nach 256 Zeichen Schluss.
    Im Array können alle Parameter untergebracht werden, mit denen gswin32c.exe aufgerufen werden könnte (siehe die aktuelle Dokumentation ).

    Spoiler anzeigen
    [autoit]

    ;gs_dll.au3
    #include-once
    #include <Array.au3>
    Opt("MustDeclareVars", 0)

    [/autoit] [autoit][/autoit] [autoit]

    exit
    ;===============================================================================
    ; Description: Anwendungsbeispiel
    ; Author(s): Tomas Dils
    ; Example: _gs_dll_2PDF("C:\ziel.pdf","C:\quelle1.ps","C:\quelle2.pdf,"C:\quelle3.eps")
    ; Parameter(s): $varPDAT - zu erstellende Datei (mit vollem Pfad)
    ; $varQDAT1 - eine bis zu sieben Quelldateien in den Formaten
    ; ... die GhostScript verarebieten kann, also .ps, .pdf
    ; $varQDAT7 und .eps
    ; Requirement(s): GhostScript ab Version 8.60 ordentlich installiert
    ; Note(s): Das erste Feld des $strARRAY kann beliebigen Inhalt haben.
    ; Die anderen Felder sollten mit sinnvollem Inhalt gefüllt sein.
    ; Das Array hat den Vorteil, dass bei der Konvertierung ver-
    ; schiedener Dateien nur die entsprechenden Felder neu bestimmt
    ; werden müssen. Durch das Anhängen von Feldern mit Quelldateien
    ; lassen sich viele Dateien (500 getestet) in einem Rutsch zusammenfassen.
    ;===============================================================================

    [/autoit] [autoit][/autoit] [autoit]

    Func _gs_dll_2PDF($varPDAT,$varQDAT1,$varQDAT2='',$varQDAT3='',$varQDAT4='',$varQDAT5='',$varQDAT6='',$varQDAT7='')
    Local $strARRAY[15]
    ; Umgesetzte Kommandozeile
    ; " -q -dNOSAFER -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -o " & _
    ; $varZielDAT & " -c save pop .setpdfwrite -f " & $varQuellDatei1 & " " & $varQuellDatei2 , "", @SW_HIDE)
    $strARRAY[0]="GS_DLL"
    $strARRAY[1]="-q"
    $strARRAY[2]="-dNOSAFER"
    $strARRAY[3]="-sDEVICE=pdfwrite"
    $strARRAY[4]="-dCompatibilityLevel=1.5"
    $strARRAY[5]= "-dNumRenderingThreads=2" ;erst ab GhostScript Version 8.63, ohne dem Version 8.60
    $strARRAY[6]="-r300"
    $strARRAY[7]="-o"
    $strARRAY[8]=""&$varPDAT&""
    $strARRAY[9]="-c"
    $strARRAY[10]="save"
    $strARRAY[11]="pop"
    $strARRAY[12]=".setpdfwrite"
    $strARRAY[13]="-f"
    $strARRAY[14]=FileGetShortName($varQDAT1)
    For $I=2 TO @NUMPARAMS-1
    IF FileExists(EVAL("varQDAT"&$I)) Then
    _ArrayAdd($strARRAY, FileGetShortName(EVAL("varQDAT"&$I)))
    EndIF
    Next
    ; Ergänzung für die Linearisierung von PDF-Dateien
    ; If Not IsDeclared("$varGSC") Then Global $varGSC = _gs_dll_SuchGhostScript()
    ; IF FileExists(FileGetShortName(StringReplace($varGSC,"bin\win32c.exe","lib\pdfopt.ps"))) Then
    ; _ArrayAdd($strARRAY, "pdfopt.ps")
    ; EndIf
    Local $varFehler=_gs_dll_warg($strARRAY)
    If @error Then
    MsgBox(16,"GS_DLL","Der Aufruf der Funktion _gs_dll_warg wurde mit folgender Fehlermeldung beendet:" & @CRLF & _
    $varFehler & @CRLF & _
    "Prüfen sie die Ergebnisse der weiteren Arbeit sorgfältig!")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If FileExists($varPDAT) Then
    Return 0
    ;~ ShellExecuteWait($varPDAT)
    ;~ FileDelete($varPDAT)
    Else
    MsgBox(0,"GS_DLL.au3 _gs_dll_2PDF","Die Zieldatei"&@CRLF&$varPDAT&@CRLF&"wurde nicht erstellt.")
    Return SetError(1,0,$varFehler)
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Description: Spricht die GS.DLL direkt an.
    ; Parameter(s): $strARRAY - alle Parameter als String
    ; Requirement(s): GhostScript ab Version 8.60 ordentlich installiert
    ; Return Value(s): On Success - 0 und @error=0
    ; On Failure - Fehlermeldung und @error=1
    ; Author(s): Tomas Dils
    ; Note(s): $varGSC mit dem vollständigen Pfad zu gswin32c.exe
    ; $varGSD mit dem vollständigen Pfad zu gswin32.dll
    ; $var_gs_dll_revision mit der Revisionsnummer der DLL
    ; können global definiert werden, um Zeit zu sparen.
    ;===============================================================================
    Func _gs_dll_warg($strARRAY)

    [/autoit] [autoit][/autoit] [autoit]

    ;GS_DLL finden
    If Not IsDeclared("$varGSC") Then Global $varGSC = _gs_dll_SuchGhostScript()
    If @error Then Return SetError(1,0,"Kein GhostScript gefunden.")
    If Not IsDeclared("$varGSD") Then Global $varGSD =FileGetShortName(StringReplace($varGSC,"win32c.exe","dll32.dll"))
    If Not FileExists($varGSD) Then
    ;MsgBox(0,"GS_DLL","Die Datei " & @CRLF & $varGSD & @CRLF & " wurde nicht gefunden.")
    Return SetError(1,0,"Datei " & $varGSD & "existiert nicht.")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;GS_DLL prüfen
    If Not IsDeclared("$var_gs_dll_revision") Then Global $var_gs_dll_revision=_gs_dll_revision($varGSD)
    If @error<>0 Then Return SetError(1,0,"Fehler bei Bestimmung der Revisionsnummer.")
    If $var_gs_dll_revision<860 Then Return SetError(1,0,"GhostScript sollte mindestens Version 8.60 haben. Gefunden wurde " & $var_gs_dll_revision &".")
    ;Array säubern von leeren Einträgen
    Local $_strARRAY[1]
    For $I=1 To UBound($strARRAY)-1
    Switch $strARRAY[$I]
    Case "", " ", @TAB
    Case Else
    _ArrayAdd($_strARRAY,$strARRAY[$I])
    EndSwitch
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;GS_DLL initialisieren
    Local $dllGS= DllOpen($varGSD)
    Local $GSInstanceHandle=DllStructCreate("int_ptr")
    Local $pGSInstanceHandle=DllStructGetPtr($GSInstanceHandle)
    If Not $dllGS<1 Then
    Local $varErgebnis0 = DllCall($dllGS,"int","gsapi_new_instance","int_ptr",$pGSInstanceHandle,"int_ptr",0)
    If ($varErgebnis0 < 0) Then
    ;~ MsgBox(0,"gs_dll.au3", "Die Initialisierung der" & @CRLF & _
    ;~ $varGSD & @CRLF & _
    ;~ "ist mit dem Ergebnis" & @CRLF & _
    ;~ $varErgebnis0 & @CRLF & _
    ;~ "gescheitert.")
    return SetError(1,0,"Die Initialisierung der" & @CRLF & _
    $varGSD & @CRLF & _
    "ist mit dem Ergebnis" & @CRLF & _
    $varErgebnis0 & @CRLF & _
    "gescheitert.")
    EndIf
    Else
    $pGSInstanceHandle=0
    $GSInstanceHandle=0
    Return SetError(1,0,"Initialisierung der GhostScript-DLL ist fehlgeschalgen.")
    EndIF
    Local $intGSInstanceHandle=DllStructGetData($GSInstanceHandle,1)
    ;=>GS_DLL initialisieren

    [/autoit] [autoit][/autoit] [autoit]

    Local $varVAR, $varByte
    If IsArray($_strARRAY) Then
    For $I=0 To UBound($_strARRAY)-1
    $varVAR&="char["&Execute(StringLen($_strARRAY[$I])+1)&"];"
    $varByte&="int_ptr;"
    Next
    $varVAR=StringTrimRight($varVAR,1)
    $varByte=StringTrimRight($varByte,1)
    Else
    Return SetError(1,0)
    EndIf
    Local $byteArgs = DllStructCreate($varVAR)
    Local $intptrArgs = DllStructCreate($varByte)
    Local $intElementCount = UBound($_strARRAY)
    ;~ Dim $strStruc ;zum Test
    For $I=1 To UBound($_strARRAY)
    DllStructSetData($byteArgs,$I,CharToOEM($_strARRAY[$I-1]))
    DllStructSetData($intptrArgs,$I,DllStructGetPtr($byteArgs,$I))
    ;~ $strStruc &= @CRLF & DllStructGetPtr($byteArgs,$I) & " " & Execute(8*StringLen($strARRAY[$I-1])+8) & " "& StringLen(_String2Binary($strARRAY[$I-1] & Chr(0))) & " "& DllStructGetData($byteArgs,$I)
    Next
    ;~ MsgBox(0,"DllStructur", "Struct Size: " & DllStructGetSize($byteArgs) & @CRLF & _
    ;~ "Struct pointer: " & DllStructGetPtr($byteArgs) & @CRLF & _
    ;~ "Count pointer: " & DllStructGetPtr($intElementCount) & @CRLF & _
    ;~ "Data:" & DllStructGetData($intElementCount,1)& $strStruc )
    Local $Ergebnis = DllCall($dllGS,"int","gsapi_init_with_args","ptr",$intGSInstanceHandle,"int",$intElementCount,"int_ptr", DllStructGetPtr($intptrArgs))
    $byteArgs = 0
    $intptrArgs = 0
    $GSInstanceHandle=0
    ;DLL schließen, ohne dem kann die Ziel-Datei nicht weiter verarbeitet werden!
    DllCall($dllGS,"int","gsapi_exit","ptr",$intGSInstanceHandle)
    DllCall($dllGS,"int","gsapi_delete_instance","ptr",$intGSInstanceHandle)
    If $dllGS > 0 Then DllClose($dllGS)
    $dllGS = 0
    ;Rückmeldung
    If $Ergebnis[0]=0 OR $Ergebnis[0]="e_Quit" Then
    Return SetError(0,0)
    Else
    Return SetError(1,0,_ArrayToString($Ergebnis," | "))
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Description: Gibt die Versionsnummer der übergebenen GS.DLL zurück.
    ; Parameter(s): $_varGSD - Vollständiger Pfad und Name der DLL als String
    ; Requirement(s): None
    ; Return Value(s): On Success - Die Revisionsnummer und @error=0
    ; On Failure - @error=1 Abfrage ging fehl
    ; @error=2 Datei existiert nicht
    ; Author(s): Tomas Dils
    ; Note(s): es könnte noch das Datum zurückgegeben werden
    ; Produktname und Copyright sind fehlerhaft angesprochen/ausgewertet
    ;===============================================================================
    Func _gs_dll_revision($_varGSD)
    If Not FileExists($_varGSD) Then Return SetError(2,0)
    Local $gsapi_revision=DllStructCreate("int_ptr product;int_ptr copyright;long revision;long revisiondate")
    Local $charProduct=DllStructCreate("char[32]")
    DllStructSetData($gsapi_revision,"product",DllStructGetPtr($charProduct))
    Local $charCopyright=DllStructCreate("char[32]")
    DllStructSetData($gsapi_revision,"copyright",DllStructGetPtr($charCopyright))
    Local $p_gsapi_revision=DllStructGetPtr($gsapi_revision)
    Local $s_gsapi_revision= DllStructGetSize($gsapi_revision) ; muss 16 sein
    Local $varErgebnis = DllCall($_varGSD,"int","gsapi_revision","int_ptr",$p_gsapi_revision,"int",$s_gsapi_revision)
    Local $varRevision=DllStructGetData($gsapi_revision,"revision")
    ;~ MsgBox(0,"TEST",_ArrayToString($varErgebnis," | ") & @CRLF & _
    ;~ "Größe:" & @TAB & @TAB & $s_gsapi_revision & @CRLF & _
    ;~ "Produkt:" & @TAB & @TAB & DllStructGetData($charProduct,1) & @CRLF & _
    ;~ "CopyRight:" & @TAB & DllStructGetData($charProduct,1) & @CRLF & _
    ;~ "Version:" & @TAB & @TAB & $varRevision & @CRLF & _
    ;~ "Datum:" & @TAB & @TAB & DllStructGetData($gsapi_revision,"revisiondate"))
    $gsapi_revision=0
    $charProduct=0
    $charCopyright=0
    If $varErgebnis[0]=0 Then
    Return SetError(0,0,$varRevision)
    Else
    Return SetError($varErgebnis[0],0,$varRevision)
    EndIf
    EndFunc ;=> _gs_dll_revision

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Description: GhostScript zu Fuß
    ; Parameter(s): $_strARRAY - Parameter als String oder als Array
    ; - wenn leer, wird der Hilfetext angezeigt
    ; $_intTimeOut - Sekunden bis zum Abbruch
    ; - Vorgabewert 120 Sekunden
    ; Requirement(s): Gobale $varGSC mit vollständiger Pfad und Name der gswin32c.exe
    ; als String oder _gs_dll_SuchGhostScript
    ; Return Value(s): On Success - StdOut und @error=0
    ; On Failure - StdOut und StdErr und @error=1
    ; Author(s): Tomas Dils
    ; Note(s): gut zum Testen, da Rückmeldung als Text
    ;===============================================================================
    Func _gs_dll_RunGSC($_strARRAY="-h",$_intTimeOut=120)
    Local $strLine, $strError
    If Not IsDeclared("$varGSC") Then
    Global $varGSC = _gs_dll_SuchGhostScript()
    If @error Then Return SetError(1,0,"Kein GhostScript gefunden.")
    ElseIf Not FileExists($varGSC) Then
    Global $varGSC = _gs_dll_SuchGhostScript()
    If @error Then Return SetError(1,0,"Kein GhostScript gefunden.")
    EndIf
    If IsArray($_strARRAY) Then
    Local $varProzess=Run($varGSC &" " & _ArrayToString($_strARRAY," ",1),"",@SW_HIDE,BitOR(4,2))
    Else
    Local $varProzess=Run($varGSC &" " & $_strARRAY,"",@SW_HIDE,BitOR(4,2))
    EndIf
    While 1
    $strError &= StderrRead($varProzess)
    If @error Then ExitLoop
    $strLine &= StdoutRead($varProzess)
    If @error Then ExitLoop
    Wend
    StdioClose($varProzess)
    ProcessWaitClose($varProzess,$_intTimeOut) ; was nach 2 Minuten nicht geworden ist, wird wohl auch nicht mehr werden
    If ProcessExists($varProzess) Then ProcessClose($varProzess)
    IF $strError="" Then
    IF $_strARRAY="-h" Then MsgBox(32,"_gs_dll_RunGSC", $strLine)
    Return SetError(0,0,$strLine)
    Else
    MsgBox(16,"_gs_dll_RunGSC", $strLine & @CRLF & $strError)
    Return SetError(1,0,$strLine & @CRLF & $strError)
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Description: GhostScript suchen
    ; Parameter(s): $varGSV - optional Mindestversion Parameter als Integer oder String
    ; Requirement(s): _gs_dll_fProgDateiVorhanden
    ; Return Value(s): On Success - vollständiger Pfad zur aktuellsten Version der gswin32c.exe
    ; On Failure - 0
    ; Author(s): Tomas Dils [email='dils@arcor.de'][/email]
    ; Note(s):
    ;===============================================================================
    Func _gs_dll_SuchGhostScript($varGSV = 863)
    Local $varVER
    ; weil man ja nicht mit jeder neuen GhostScriptVersion das Programm ändert
    For $varI = 1 To 100
    $varVER = RegEnumKey("HKLM\SOFTWARE\GPL Ghostscript\", $varI)
    If @error <> 0 Then
    $varVER = StringReplace(RegEnumKey("HKLM\SOFTWARE\GPL Ghostscript\", $varI - 1), ".", "")
    If $varGSV < $varVER Then $varGSV = $varVER
    ExitLoop
    EndIf
    Next
    $varGSV = StringTrimRight($varGSV, 2) & "." & StringRight($varGSV, 2)
    ;damit insbesondere IrfanView auch auf GhostScript zugreifen kann
    Local $varAFPL=RegRead("HKLM\SOFTWARE\GPL Ghostscript\"&$varGSV,"GS_DLL")
    RegWrite("HKLM\SOFTWARE\AFPL Ghostscript\"&$varGSV,"GS_DLL","REG_SZ",$varAFPL)
    $varAFPL=RegRead("HKLM\SOFTWARE\GPL Ghostscript\"&$varGSV,"GS_LIB")
    RegWrite("HKLM\SOFTWARE\AFPL Ghostscript\"&$varGSV,"GS_LIB","REG_SZ",$varAFPL)
    Local $varDateiName = "gs\gs" & $varGSV & "\bin\gswin32c.exe"
    Local $varDateiPfad = "C:\"
    Select
    Case FileExists($varDateiPfad & "\" & $varDateiName)
    Return $varDateiPfad & "\" & $varDateiName
    Case FileExists(@ProgramFilesDir & "\" & $varDateiName)
    Return @ProgramFilesDir & "\" & $varDateiName
    Case FileExists(@CommonFilesDir & "\" & $varDateiName)
    Return @CommonFilesDir & "\" & $varDateiName
    Case FileExists(@WindowsDir & "\" & $varDateiName)
    Return @WindowsDir & "\" & $varDateiName
    Case FileExists(@SystemDir & "\" & $varDateiName)
    Return @SystemDir & "\" & $varDateiName
    Case FileExists(@ScriptFullPath & "\" & $varDateiName)
    Return @ScriptFullPath & "\" & $varDateiName
    Case FileExists(@WorkingDir & "\" & $varDateiName)
    Return @WorkingDir & "\" & $varDateiName
    Case FileExists(@TempDir & "\" & $varDateiName)
    Return @TempDir & "\" & $varDateiName
    Case Else
    MsgBox(16, "GD_DLL Fehlermeldung", "Das Programm " & $varDateiName & Chr(10) & " wurde nicht im erwarteten Pfad " & $varDateiPfad & " gefunden.")
    Return 0
    EndSelect
    EndFunc ;==>_SuchGhostScript

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _gs_dll_SDateiName()
    ; Description ...: gibt einen noch nicht belegten seriellen Dateinnamen zurück
    ; Syntax.........: _gs_dll_SDateiName([$sDateiName = "ADMS"[, $sEndung=".PDF"[, $sDateiPfad = @TempDir[, $vsStartwert="0000"]]]])
    ; Parameters ....: $sDateiName - Dateiname, Standard "ADMS"
    ; $sEndung - Dateiendung im .3-Format, Standard ".PDF"
    ; $sDateiPfad - Dateipfad, Standard @TempDir
    ; $sStartwert - definiert Zählbeginnn und Länge des seriellen Namensanteils, Standard "0000"
    ; Return values .: Success - vollständiger Dateienname der Form "C:\temp\ADMS0001.PDF"
    ; Failure - 0
    ; Author ........: Tomas Dils
    ; Modified.......: 12.09.2008
    ; ===============================================================================================================================
    Func _gs_dll_SDateiName($sDateiName = "ADMS", $sEndung = ".PDF", $sDateiPfad = @TempDir, $sStartwert = "0000")
    Local $iZahllang = StringLen($sStartwert)
    While FileExists($sDateiPfad & "\" & $sDateiName & $sStartwert & $sEndung)
    $sStartwert = StringRight("0000000000000000000" & String(Execute($sStartwert + 1)), $iZahllang)
    WEnd
    Return $sDateiPfad & "\" & $sDateiName & $sStartwert & $sEndung
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;ANSI ASCII Übersicht
    ;http://www.goascii.de/#table2

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Name: OemToChar
    ; Description: Wandelt einen ASCII- in einen ANSI-String
    ; Parameter(s): $szSrc = String der umgewandelt werden soll
    ; Requirement(s): keine
    ; Return Value(s): bei Erfolg: umgewandelter String
    ; bei Fehler: "" und @error = 1
    ; Author(s): bernd670
    ;===============================================================================
    Func OemToChar($szSrc)
    ;~ Private Declare Function OemToChar Lib "user32.dll" Alias "OemToCharA" (ByVal lpszSrc As String, ByVal lpszDst As String) As Long
    Local $placeholder
    For $i = 0 To StringLen($szSrc)
    $placeholder &= " "
    Next
    Local $lRetVal = DllCall("user32.dll", "long", "OemToChar", "str", $szSrc, "str",$placeholder)
    If IsArray($lRetVal) And $lRetVal[0] = 1 Then
    Return SetError(0,0,$lRetVal[2])
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(1,0,"")
    EndFunc ;==>OemToChar

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Name: CharToOEM
    ; Description: Wandelt einen ANSI- in einen ASCII-String
    ; Parameter(s): $szSrc = String der umgewandelt werden soll
    ; Requirement(s): keine
    ; Return Value(s): bei Erfolg: umgewandelter String
    ; bei Fehler: "" und @error = 1
    ; Author(s): Prog@ndy
    ;===============================================================================
    Func CharToOEM($szSrc)
    Local $placeholder
    For $i = 0 To StringLen($szSrc)
    $placeholder &= " "
    Next
    Local $lRetVal = DllCall("user32.dll", "long", "CharToOem", "str", $szSrc, "str",$placeholder)
    If IsArray($lRetVal) And $lRetVal[0] = 1 Then
    Return SetError(0,0,$lRetVal[2])
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(1,0,"")
    EndFunc ;==>OemToChar

    [/autoit]

    Mit einer speziellen Version von GhostScript , bei der das cFax-Device einbezogen ist, kann man sff-Dateien für Fritz!Fax von AVM erstellen.

    PS.: Dank an bernd670 für OemToChar() und Prog@ndy für CharToOEM()

    Einmal editiert, zuletzt von bztomas (6. Oktober 2008 um 01:52)