![]() |
PDF Merge
Hallo Zusammen,
habe Ihr denn Erfahrungen mit PDF Merge? Was könnt Ihr da am besten empfehlen, damit ich aus der IDE 2 PDF´s in 1 zusammenbringen kann? |
AW: PDF Merge
Wir nutzten PDFBox (
![]() Sehr gute Ergebnisse bei Textextraction und Splitten von PDF. Ich vermute der Merge ist auch mit wenig Problemen verbunden. |
AW: PDF Merge
Hallöle...:P
Ghostscript DLL: Zitat:
![]() |
AW: PDF Merge
Ein Kunde hat mal was mit ITextSharp in C# programmiert.
|
AW: PDF Merge
Zitat:
Aber es scheint ich bin zu doof das aus Delphi aufzurufen:roll:
Code:
Was mache ich falsch???
procedure TForm1.Button1Click(Sender: TObject);
var xProg:String; begin xProg := 'gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE='+ JvFilenameEdit3.Text +'-dBATCH '+JvFilenameEdit1.Text+' '+JvFilenameEdit2.Text; JvCreateProcess1.CommandLine := ExtractFilePath(Application.ExeName) + xProg; JvCreateProcess1.Run; end; gs ist installiert! |
AW: PDF Merge
ITextSharp hat Dual-Lizenz (AGPL bzw. Commercial License).
Als aufpassen das dies nicht eine teure Integration wird. |
AW: PDF Merge
Was ist der Fehlercode/Text
Ich Tipp aber auf fehlende Backslash bei der Pfadangabe |
AW: PDF Merge
Ich auf eventuelle Leerzeichen in Pfaden (fehlende ")
und vorallem auf ein fehlendes Leerzeichen vor -dBATCH :angle: |
AW: PDF Merge
Meldung: Das System kann die angegebe Datei nicht finden!
Backshlash habe ich drinne, mir scheint das er einfach "gs" nicht finden kann, wenn ich es im CMD mache, dann habe ich das gleiche! |
AW: PDF Merge
gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=C:\Austausch\Test.pdf -dBATCH C:\Austausch\DV\jg121035219.PDF C:\Austausch\DV\jg1209120740.PDF
das wird versucht aufzurufen! Habe ich vielleicht das gs falsch installiert? habs von hier: ![]() |
AW: PDF Merge
Ich habe den Fehler gefunden!
Ich muss den kompletten Pfad angeben, dann funktioniert es! Coole Sache :)
Delphi-Quellcode:
var
xProg: String; begin xProg := '"C:\Program Files (x86)\gs\gs9.53.3\bin\gswin32.exe" -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=' + JvFilenameEdit3.Text + ' -dBATCH ' + JvFilenameEdit1.Text + ' ' + JvFilenameEdit2.Text; showmessage(xprog); JvCreateProcess1.CommandLine := xProg; JvCreateProcess1.Run; end; |
AW: PDF Merge
Zitat:
Und dennoch solltest du sicherheitshalber "eventuelle" Leerzeichen beachten (Parameter in " einschließen), nicht nur bei der EXE, sondern auch bei den PDFs. und das eine fehlende Leerzeichen einfügen. siehe #8 Außerdem ist denn das aktuelle Arbeitsverzeichnis auch das Verzeichnis wo die PDFs liegen? Sicherheitshalber immer nur mit absoluten Pfaden arbeiten. |
AW: PDF Merge
Hmm..
Alternativ kannst du auch von GS die DLL direkt in deinem Programm verwenden, dann braucht gar kein GS mehr installiert werden und es muss auch kein (externes) Programm mehr aufgerufen werden. Als Parameter werden die gleichen an einen Funktionsaufruf übergeben, wie beim Aufruf der Exe. Die API-Pas files waren von Alessandro Briosi und müssen nur auf UniCode angepasst werden. |
AW: PDF Merge
Delphi-Quellcode:
Danke HolgerX!
procedure TForm1.Button2Click(Sender: TObject);
var argv: Array of PAnsiChar; instance: Pointer; x: Integer; begin // new(instance); //how many bytes, this really doesn't make sense with a untyped pointer! // setlength(argv, 4); // argv[0] := PANsiChar('ps2pdf'); // argv[1] := PAnsiChar('-dNOPAUSE'); // argv[2] := PAnsiChar('-dBATCH'); // argv[3] := PAnsiChar('-dSAFER'); // gsapi_init_with_args(instance, Length(argv), PPAnsiChar(argv)); // gsapi_exit(instance); gsapi_new_instance(instance, instance); // ShowMessage(inttostr(x)); // new(instance); //how many bytes, this really doesn't make sense with a untyped pointer! setlength(argv, 5); argv[0] := PAnsiChar(''); argv[1] := PAnsiChar('-dNOPAUSE'); argv[2] := PAnsiChar('-sDEVICE=pdfwrite'); argv[3] := PAnsiChar('-sOUTPUTFILE= ' + JvFilenameEdit3.Text); argv[4] := PAnsiChar(' -dBATCH ' + JvFilenameEdit1.Text + ' ' + JvFilenameEdit2.Text); gsapi_init_with_args(instance, Length(argv), PPAnsiChar(argv)); gsapi_exit(instance); showmessage('fertig!'); end; Das funktioniert aber nicht, kommt nicht mal ne Fehlermeldung! |
AW: PDF Merge
Falls es ohne Abhängigkeit zu GhostScript laufen soll:
![]() Viele Grüsse, Julian |
AW: PDF Merge
argv[0] // ein Pointer auf nil, sicher das die API damit etwas anfangen kann?
argv[3] // warum ein Leerzeichen nach dem = ? argv[4] // warum ein Leerzeichen am Anfang ? |
AW: PDF Merge
Ich blick es nicht:oops:
Was mache ich falsch, es kommt hier nun immer der Errocode 100 Kann vielleicht mal jemand Source testen?
Delphi-Quellcode:
Ich verzweifle:roll:
procedure TForm1.Button2Click(Sender: TObject);
var ArgV: Array of PAnsiChar; instance: Pointer; x, code: Integer; xArgV: PPAnsiChar; begin code := gsapi_new_instance(instance, nil); if code < 0 then raise Exception.Create ('Impossible to open an instance of ghostscript. Error code: ' + IntToStr(code)); setlength(ArgV, 4); ArgV[0] := PAnsiChar('-dNOPAUSE' + #0); ArgV[1] := PAnsiChar('-sDEVICE=pdfwrite' + #0); ArgV[2] := PAnsiChar('-sOUTPUTFILE="' + JvFilenameEdit3.Text + '"' + #0); ArgV[3] := PAnsiChar('-dBATCH ' + '"' + JvFilenameEdit1.Text + '"' + ' ' + '"' + JvFilenameEdit2.Text + '"' + #0); code := gsapi_init_with_args(instance, Length(ArgV), @ArgV); if code < 0 then raise Exception.Create('ERROR: init_args: ' + IntToStr(code)); gsapi_exit(instance); showmessage('fertig!'); end; |
AW: PDF Merge
Hmm..
JvFilenameEdit1.Text dürfte wohl Unicode sein... Ghostscipt DLL kann nur ANSI oder UTF8 Für UTF8 muss das Encodiung vor gsapi_init_with_args gesetzt werden (gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF8)) Somit die UnicodeStrings nach UTF8, dann dass Encoding setzen, dann gsapi_init_with_args. |
AW: PDF Merge
Moin...:P
ein funktionierendes Beispiel:
Delphi-Quellcode:
PS:
function TGhostscript.PDFShrink(FileName: string): Boolean;
var TargetFileName: string; InitError: Integer; begin if FDLLHandle = 0 then begin if not LoadDLL(FDLLPath) then begin Result := False; Exit; end; end; try TargetFileName := IncludeTrailingPathDelimiter(ExtractFilePath(FileName)) + conFileNameTempPDF; SetLength(FParameters, 7); FParameters[0] := ''; FParameters[1] := '-dNOPAUSE'; FParameters[2] := '-dBATCH'; FParameters[3] := '-dPDFSETTINGS=/ebook'; FParameters[4] := '-sDEVICE=pdfwrite'; FParameters[5] := PAnsiChar(AnsiString('-sOutputFile=' + TargetFileName)); FParameters[6] := PAnsiChar(AnsiString(FileName)); InitError := FGsApiInitWithArgs(FGsInstance, Length(FParameters), FParameters); Result := (InitError = 0); if InitError <> 0 then begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehlercode: %d', [InitError])); end; end; finally FGsApiExit(FGsInstance); end; if Result then begin if not TToolsIO.IsFileInUse(FileName) then begin try TFile.Delete(FileName); if not TToolsIO.IsFileInUse(FileName) then begin if not RenameFile(TargetFileName, FileName) then begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehler beim Umbenennen von TempPDF.pdf: %s', ['Rename'])); end; end; end else begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehler beim Umbenennen von TempPDF.pdf: %s', ['InUse'])); end; end; except if Assigned(FOnError) then begin FOnError(Self, Format('Fehler beim Umbenennen von TempPDF.pdf: %s', ['Delete'])); end; end; end else begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehler beim Umbenennen von TempPDF.pdf (in Benutzung): %s', [FileName])); end; end; end; end; So eine Funktion gehört nicht auf die Form sondern in eine seperate Unit / Klasse. Dieser Klasse übergiebst du dann die Dateien...:zwinker: |
AW: PDF Merge
Hi Danke für den Test, aber ich will ja Merge machen, aber das funktioniert nicht.
Habe es auch in einer eigenen Klasse deklariert!
Delphi-Quellcode:
function TGhostscript.PDFMerge(InFile1, InFile2, InFile3,
OutFile: Ansistring): Boolean; var xDLLFile: String; begin if not FileExists(InFile1) then begin ShowMessage('PDF Nr1 wurde nicht gefunden!!!'); Exit; end; if not FileExists(InFile2) then begin ShowMessage('PDF Nr2 wurde nicht gefunden!!!'); Exit; end; if FDLLHandle = 0 then begin xDLLFile := IncludeTrailingBackslash(FDLLPath) + conDLLName; if FileExists(xDLLFile) then LoadDLL(xDLLFile); end; try SetLength(FParameters, 4); FParameters[0] := ('-dNOPAUSE'); FParameters[1] := PAnsiChar('-dBATCH ' + '"'+InFile1+ '"' +' ' + '"'+InFile2+ '"') ; FParameters[2] := ('-sDEVICE=pdfwrite'); FParameters[3] := PAnsiChar('-sOUTPUTFILE=' + '"'+OutFile+ '"' ); Result := (FGsApiInitWithArgs(FGsInstance, Length(FParameters), FParameters) = 0); ShowMessage(booltostr(Result)); finally FGsApiExit(FGsInstance); end; end; |
AW: PDF Merge
...griegst du gleich. 8-) Ich hatte gestern Probleme mit "dynamischen" Parametern.
![]()
Delphi-Quellcode:
Das ist der Knackpunkt. Die Files gehören ans Ende als separate Parameter!
FParameters[1] := PAnsiChar('-dBATCH ' + '"'+InFile1+ '"' +' ' + '"'+InFile2+ '"') ;
|
AW: PDF Merge
@gaisser: Bei dieser ART von DLLs, wo man die "selben" Parameter reingibt, wie für die EXE,
dort muß man oftmals/meistens auch den Param0 mit reingeben (gefüllt oder leer ist oft egal), also den "Programmaufruf" und erst ab Param1 die Parameter, da in der DPP praktisch der "selbe" Code steckt, wie in der EXE.
Delphi-Quellcode:
FParameters[0] := '';
FParameters[1] := ...; |
AW: PDF Merge
Super, vielen Dank!
Also ich hab mal die Unit wo funktioniert angehängt!
Delphi-Quellcode:
Der Aufruf ist dann :
unit uGhostscript;
interface uses Winapi.Windows, Vcl.dialogs, Generics.Collections, System.Classes, System.SysUtils, System.IOUtils; const conDLLName = 'gsdll32.dll'; conFileNameTempPDF = 'TempPDF.pdf'; type TStdIoFunction = function(CallerHandle: Pointer; Buffer: PAnsiChar; Length: Integer): Integer stdcall; TGsInit = function(I: Pointer; P: Pointer): Integer; stdcall; TGsApiInitWithArgs = function(I: Pointer; L: Integer; A: array of PAnsiChar) : Integer; stdcall; TGsApiExit = function(I: Pointer): Integer; stdcall; TGsApiDeleteInstance = function(I: Pointer): Integer; stdcall; TOnErrorEvent = procedure(Sender: TObject; MessageText: string) of object; TGhostscript = class private FDLLPath: string; FDLLHandle: THandle; FGsInit: TGsInit; FGsApiInitWithArgs: TGsApiInitWithArgs; FGsApiExit: TGsApiExit; FGsApiDeleteInstance: TGsApiDeleteInstance; FGsInstance: Pointer; FParameters: array of PAnsiChar; FOnError: TOnErrorEvent; function LoadDLL(PathDLL: string): Boolean; function IsFileInUse(FileName: string): Boolean; public constructor Create(PathDLL: string = ''); destructor Destroy; override; property OnError: TOnErrorEvent read FOnError write FOnError; function PDFShrink(FileName: string): Boolean; function PDFMerge(OutputFile: string; FileList: TStrings): Boolean; end; implementation { TGhostscript } // Initialisation constructor TGhostscript.Create(PathDLL: string); begin FDLLPath := PathDLL; FDLLHandle := 0; end; destructor TGhostscript.Destroy; begin if FDLLHandle > 0 then begin FreeLibrary(FDLLHandle); end; inherited; end; // Work function TGhostscript.LoadDLL(PathDLL: string): Boolean; var CurrentDLLPath: string; begin if PathDLL = '' then begin CurrentDLLPath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + conDLLName; end else begin CurrentDLLPath := PathDLL; end; FDLLHandle := LoadLibrary(PChar(CurrentDLLPath)); if FDLLHandle > 0 then begin FGsInit := GetProcAddress(FDLLHandle, 'gsapi_new_instance'); Result := (FGsInit(@FGsInstance, nil) = 0); if Result then begin FGsApiInitWithArgs := GetProcAddress(FDLLHandle, 'gsapi_init_with_args'); FGsApiExit := GetProcAddress(FDLLHandle, 'gsapi_exit'); FGsApiDeleteInstance := GetProcAddress(FDLLHandle, 'gsapi_delete_instance'); end else begin FOnError(Self, 'Die Ghostscript Instanz konnte nicht erzeugt werden.'); Result := False; end; end else begin FOnError(Self, Format('Die Ghostscript DLL %s wurde nicht geladen.', [QuotedStr(CurrentDLLPath)])); Result := False; end; end; function TGhostscript.IsFileInUse(FileName: string): Boolean; var Stream: TFileStream; begin Result := False; Stream := nil; if not FileExists(FileName) then Exit; try Stream := TFileStream.Create(FileName, fmOpenRead); // Alternative: 'or fmShareExclusive' except Result := True; end; Stream.Free; end; function TGhostscript.PDFMerge(OutputFile: string; FileList: TStrings): Boolean; var ParametersTemp: TList<AnsiString>; InitError: Integer; procedure CreateMergeFiles; var I: Integer; begin ParametersTemp := TList<AnsiString>.Create; for I := 0 to FileList.Count - 1 do begin ParametersTemp.Add(AnsiString(FileList[I])); // <-- FParameters[I + 8] := PAnsiChar(ParametersTemp[I]); // <-- end; end; var xDLLFile: String; begin xDLLFile := IncludeTrailingBackslash(FDLLPath) + conDLLName; if FileExists(xDLLFile) then LoadDLL(xDLLFile); if FDLLHandle = 0 then begin if not LoadDLL(xDLLFile) then begin Result := False; Exit; end; end; try ParametersTemp := TList<AnsiString>.Create; // <-- try SetLength(FParameters, FileList.Count + 8); FParameters[0] := ''; FParameters[1] := '-dNOPAUSE'; FParameters[2] := '-dBATCH'; FParameters[3] := '-Author=ProTRxxx Software GmbH'; FParameters[4] := '-Creator=ProTRxxx Software GmbH'; FParameters[5] := '-dPDFSETTINGS=/printer'; FParameters[6] := '-sDEVICE=pdfwrite'; FParameters[7] := PAnsiChar(AnsiString('-sOutputFile=' + OutputFile)); CreateMergeFiles; InitError := FGsApiInitWithArgs(FGsInstance, Length(FParameters), FParameters); Result := (InitError = 0); if InitError <> 0 then begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehlercode: %d', [InitError])); end; end; finally ParametersTemp.Free; end; finally FGsApiExit(FGsInstance); end; if not Result then begin if Assigned(FOnError) then begin FOnError(Self, Format('Fehler beim Erstellen: %s', [OutputFile])); end; end; end; function TGhostscript.PDFShrink(FileName: string): Boolean; var TargetFileName: string; begin if FDLLHandle = 0 then begin LoadDLL(FDLLPath); end; try TargetFileName := IncludeTrailingPathDelimiter(ExtractFilePath(FileName)) + conFileNameTempPDF; SetLength(FParameters, 7); FParameters[0] := ''; FParameters[1] := '-dNOPAUSE'; FParameters[2] := '-dBATCH'; FParameters[3] := '-dPDFSETTINGS=/ebook'; FParameters[4] := '-sDEVICE=pdfwrite'; FParameters[5] := PAnsiChar(AnsiString('-sOutputFile=' + TargetFileName)); FParameters[6] := PAnsiChar(AnsiString(FileName)); Result := (FGsApiInitWithArgs(FGsInstance, Length(FParameters), FParameters) = 0); finally FGsApiExit(FGsInstance); end; if Result then begin if not IsFileInUse(FileName) then begin TFile.Delete(FileName); RenameFile(TargetFileName, FileName); end; end end; end.
Delphi-Quellcode:
Danke Euch allen:-D
procedure TForm1.Button3Click(Sender: TObject);
var xPDF: TGhostscript; xFiles:TStringList; begin if not Assigned(xPDF) then xPDF := TGhostscript.Create(ExtractFilePath(Application.ExeName)); xFiles:=TStringList.Create; xFiles.Add(JvFilenameEdit1.Text); xFiles.Add(JvFilenameEdit2.Text); xPDF.PDFMerge(JvFilenameEdit3.Text,xFiles ); xFiles.Free; xPDF.Free; end; |
AW: PDF Merge
:P...soviel "Diebstahl" ist ein :cheers: auf den nächsten Delphi Tagen wert... :thumb:
|
AW: PDF Merge
Mit Sicherheit :):):):bouncing4::bouncing4::bouncing4:
Aber ein Phänomen hab ich noch... Unter Debug Comp geht es, aber unter Release nicht, an was kann dies liegen? Er bekommt den FDDLPath nicht zugewiesen??? |
AW: PDF Merge
Hallo,
habe gerade versucht, zwei FastReport PDF's mit Ghostscript zu mergen aber trotz Aufrufs von gsapi_set_arg_encoding(FGsInstance, GS_ARG_ENCODING_UTF8), wie von HolgerX vorgeschlagen, werden die Umlaute in Hieroglyphen umgewandelt. Hat jemand eine Idee, wie man das korrigieren kann? Viele Grüße |
AW: PDF Merge
Hmm..
Zitat:
In den Quelltexten von gaisser wird nur nach AnsiString konvertiert und nicht nach UTF8, und dann gehen schon so einige Zeichen verloren... |
AW: PDF Merge
Ja ich habe überall wo "Ansi" steht UTF8 eingesetzt. Fehler kamen keine...
Aufgeruft habe ich die Funktion an dieser Stelle
Delphi-Quellcode:
...
FGsInit := GetProcAddress(FDLLHandle, 'gsapi_new_instance'); Result := (FGsInit(@FGsInstance, nil) = 0); if Result then begin Fgsapi_set_arg_encoding := GetProcAddress(FDLLHandle, 'gsapi_set_arg_encoding'); Fgsapi_set_arg_encoding(FGsInstance, GS_ARG_ENCODING_UTF8); ... |
AW: PDF Merge
Hmm...
Zitat:
gsapi_new_instance gsapi_set_arg_encoding gsapi_init_with_args gsapi_exit Bei den Argumenten (gsapi_init_with_args) muss der erste Eintrag ein '' sein, da dieser von der GS-APi ignoriert wird ( ![]() Bei den anderen Argumenten, welche Strings als Wert enhalten musst du deinen Delphistring mit UTF8Encode nach UTF umcodieren! Einfach nur aus 'AnsiString' ein 'UTF8String' zu machen, wird wohl nichts bringen... Sprich z.B. (Src von gaisser):
Delphi-Quellcode:
SetLength(FParameters, 8);
FParameters[0] := ''; FParameters[1] := '-dNOPAUSE'; FParameters[2] := '-dBATCH'; FParameters[3] := '-Author=ProTRxxx Software GmbH'; FParameters[4] := '-Creator=ProTRxxx Software GmbH'; FParameters[5] := '-dPDFSETTINGS=/printer'; FParameters[6] := '-sDEVICE=pdfwrite'; FParameters[7] := PAnsiChar(AnsiString('-sOutputFile=' + UTF8Encode(OutputFile))); |
AW: PDF Merge
Hallo,
vielen Dank für dein Hilfe aber ich kriege es nicht hin, habe jetzt viel herumexperimentiert und versucht mit UTF8Encode die Strings um zu kodieren aber ich bekomme immer das gleiche Resultat. Keine Ahnung was ich jetzt noch versuchen kann... |
AW: PDF Merge
Ich nehme für sowas immer das Befehlszeilenprogramm
![]() pdftk dateiname1.pdf dateiname2.pdf ... dateinameN.pdf cat output ausgabedatei.pdf hängt die alle aneinander an. Man kann sogar Seiten drehen dabei, einzelne Seiten ausschneiden und vieles mehr. Man braucht die EXE Datei und eine DLL, und das wars. Keine Installation. |
AW: PDF Merge
Ja so habe ich es jetzt auch gelöst.
Hätte es nur gerne hinbekommen... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:12 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz