Gelöst! Zwei PDFs zusammenfügen

9. Juli 2020 15:48

Hallo zusammen!

Ich habe das Problem, dass ich für einen Kunden zwei PDFs (nach dem Generieren mit Report.SAVEASPDF) zu einem einzigen PDF zusammenfügen soll, um es dann per Mail zu versenden. Im Prinzip dürfte es ein ähnliches Problem sein wie in "Zwei verschiedene Repors zusammen drucken" (viewtopic.php?f=66&t=33852&p=128497&hilit=pdf#p128497) beschrieben. Aber mit dieser Lösung komme ich einfach nicht weiter, u.a. auch weil ich keine funktionierende "itextsharp dotnet library" finden kann.

Wenn mir jemand weiter helfen könnte, wäre ich wahnsinnig dankbar. Hab jetzt schon Stunde um Stunde erfolglos herumprobiert...

Freundliche Grüsse
Armin
Zuletzt geändert von Minu63 am 29. Juli 2020 14:41, insgesamt 1-mal geändert.

Re: Zwei PDFs zusammenfügen

10. Juli 2020 07:29

das hilft dir nicht weiter?
https://www.c-sharpcorner.com/article/merge-pdf/

iTextSharp kann ich problemlos bei einem meiner C#-Projekte verwenden

vielleicht wäre für den Kunden auch noch eine *.zip eine Alternative?

Re: Zwei PDFs zusammenfügen

10. Juli 2020 10:06

Was mir immer geholfen hat war die Anwendung "PDFTK".
Das ist ein Kommandozeilenprogramm, welches einfach mit zwei erstellten Pdfs aufgerufen wird und dann merged.
Kann auch zum Ausfüllen von Formularen verwendet werden.

Wenn nur so etwas wie AGB angehängt werden soll, funktioniert das auch mit PDF-Druckern.

Re: Zwei PDFs zusammenfügen

13. Juli 2020 10:02

Hallo.
Bitte sehr!

Du packst den Pfad der Einzel-PDFs in das Array "Filenames" und rufst damit die Funktion auf.
Der Rest sollte selbsterklärend sein.

Variablen
Code:
Name   DataType   Subtype   Length
pdfDoc   DotNet   iTextSharp.text.Document.'itextsharp, Version=5.5.10.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca'   
pdfCopy   DotNet   iTextSharp.text.pdf.PdfCopy.'itextsharp, Version=5.5.10.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca'   
pdfReader   DotNet   iTextSharp.text.pdf.PdfReader.'itextsharp, Version=5.5.10.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca'   
pdfPage   DotNet   iTextSharp.text.pdf.PdfImportedPage.'itextsharp, Version=5.5.10.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca'   
FileStream   DotNet   System.IO.FileStream.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'   
FileMode   DotNet   System.IO.FileMode.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'   
numberOfPages   Integer      
i   Integer      
pageCount   Integer      
FileManagement   Codeunit   File Management   


Funktion
Code:
PdfMerge(Filenames : ARRAY [99] OF Text;VAR MergedServerFilename : Text)
IF MergedServerFilename = '' THEN
  MergedServerFilename := FileManagement.ServerTempFileName('.pdf');

pdfDoc := pdfDoc.Document;
pdfCopy := pdfCopy.PdfCopy(pdfDoc,FileStream.FileStream(MergedServerFilename,FileMode.Create));
pdfDoc.Open;

i := 1;
//loop through files
WHILE Filenames[i] <> '' DO BEGIN
  pdfReader := pdfReader.PdfReader(Filenames[i]);
  numberOfPages := pdfReader.NumberOfPages;
  //loop through pages
  FOR pageCount := 1 TO numberOfPages DO BEGIN
    pdfPage := pdfCopy.GetImportedPage(pdfReader, pageCount);
    pdfCopy.AddPage(pdfPage);
  END;
  pdfCopy.FreeReader(pdfReader);
  pdfReader.Close;
  CLEAR(pdfReader);
  FileManagement.DeleteServerFile(Filenames[i]);
  i += 1;
END;

//cleanup
pdfCopy.Flush;
pdfCopy.Close;
pdfCopy.Dispose;
CLEAR(pdfCopy);
pdfDoc.Close;
pdfDoc.Dispose;
CLEAR(pdfDoc);

Re: Zwei PDFs zusammenfügen

13. Juli 2020 12:07

Hallo zusammen!

Vielen Dank für Eure Tipps, aber leider scheitert's schon ganz am Anfang: ich bring's einfach nicht fertig, die .dll zu registrieren!
Ich hab eine "iTextSharp.dll" vom 20.03.2017 (Version 5.5.11.0) gefunden.
- Wenn ich sie als Admin mit regsvr32 registrieren möchte, erscheint der Fehler "... wurde geladen, aber der DllRegisterServer-Eingangspunkt wurde nicht gefunden."
- Und wenn ich sie unter "Extras / Benutzerdefinierte Controls" eintragen möchte, erscheint "Das OLE Control konnte nicht registriert werden."
Was mache ich falsch?

Re: Zwei PDFs zusammenfügen

13. Juli 2020 12:16

So viel musst du gar nicht machen. Die dll kommt einfach auf der Servicetiermaschine in das Verzeichnis:

C:\Program Files\Microsoft Dynamics NAV\71\Service\Add-ins

ggf. noch rechte Maustaste -> Eigenschaften und schauen das die Attribute stimmen. (Manchmal passiert es, dass Windows die DLL "sperrt", wenn diese aus unbekannter Quelle kommt. Ich weiß nicht mehr, wie das Attribut dann heißt. Aber man sieht es in den Dateieigenschaften)

Re: Zwei PDFs zusammenfügen

13. Juli 2020 13:53

Vielen Dank für Deine Hilfe, langsam wird ein Schuh draus! Immerhin konnte ich die Variabeln jetzt definieren und den Code kompilieren. Beim Starten erhalte ich allerdings im RTC den Fehler
"Eine Instanz des folgenden .NET Framework-Objekts kann nicht erstellt werden: Montage itextsharp, Version 5.5.11.0, Culture=neutral, PublicToken==8354ae6d2174ddca, Typ iTextSharp.text.Document".

Gemäss Debugger kommt der Fehler gleich bei der ersten "richtigen" Zeile
pdfDoc := pdfDoc.Document;

Re: Zwei PDFs zusammenfügen

13. Juli 2020 14:11

Hallo,

schau mal ins Eventlog des Clients. Evtl. fehlt da das richtige .Net- Framework oder etwas anderes.

Gruß fiddi

Re: Zwei PDFs zusammenfügen

13. Juli 2020 14:20

muss ggf. in der Eigenschaft der Variablen noch RunOnClient gesetzt werden?

Re: Zwei PDFs zusammenfügen

13. Juli 2020 14:33

Das mit dem RunOnClient würde ich persönlich nicht machen. Aber das ist nur meine Meinung. Denn sollte man das später mal automatisieren, läufts ja ggf. sowieso aus Sicht des NST.
Lieber dafür sorgen, dass alle Pfade von der Servicetiermaschine "sichtbar" sind. Also Netzwerkpfade nutzen. Oder mittels Codeunit "File Management" die lokalen Einzel-PDFs vorher auf den Server kopieren und dann in dem Array die Serverpfade angeben. vg

Re: Zwei PDFs zusammenfügen

13. Juli 2020 14:39

vandyke hat geschrieben:Lieber dafür sorgen, dass alle Pfade von der Servicetiermaschine "sichtbar" sind. Also Netzwerkpfade nutzen. Oder mittels Codeunit "File Management" die lokalen Einzel-PDFs vorher auf den Server kopieren und dann in dem Array die Serverpfade angeben. vg

defintiv

Re: Zwei PDFs zusammenfügen

13. Juli 2020 14:44

Hallo,

wenn die DLL nicht passt, weil sie z.B. eine 64- bit Version ist, dann kannst du die u.U. so nicht verwenden.

Ansonsten trifft natürlich das von VanDyke geschriebene zu.


Gruß Fiddi

Re: Zwei PDFs zusammenfügen

14. Juli 2020 11:23

Guten Morgen zusammen!

Damit die PDFs auch vom ServiceTier sichtbar sind, arbeite ich schon mit FileMgt... Aber der Hinweis aufs EventLog hat etwas gebracht! Dort finde ich den Eintrag:

Protokollname: Application
Quelle: MicrosoftDynamicsNavServer$CH2013_CU38_Work
Datum: 14.07.2020 11:10:30
Ereignis-ID: 218
Aufgabenkategorie:(13)
Ebene: Warnung
Schlüsselwörter:Klassisch
Benutzer: Nicht zutreffend
Computer: WSAAB002.amanninformatik.com
Beschreibung:
Server instance: CH2013_CU38_Work
Tenant ID: default
Session type: RoleTailoredClient
Session ID: 1
User: AMANNINFORMATIK\AAB
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavNCLDotNetCreateException
SuppressMessage: False
SuppressExceptionCreatedEvent: False
FatalityScope: Call
Message: Eine Instanz des folgenden .NET Framework-Objekts kann nicht serialisiert werden: Montage itextsharp, Version=5.5.11.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, Typ iTextSharp.text.Document.
StackTrace:
bei Microsoft.Dynamics.Nav.Service.ServiceCall.GetClientReturnValue(Action invokeCallback)
bei Microsoft.Dynamics.Nav.Service.NSClientCallback.InvokeAutomationMethod(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, Object[] args)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.GetObjectDataFromClient(NavClientHandle clientHandle)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.GetDotNetObjectFromNavObject(Type targetType, Object value, List`1& disposeObjects)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.CreateDotNet(Object[] arguments)
Source: Microsoft.Dynamics.Nav.Service
HResult: -2146233088
----------------------------------
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavNCLDotNetCreateException
SuppressMessage: False
SuppressExceptionCreatedEvent: False
FatalityScope: Call
Message: Eine Instanz des folgenden .NET Framework-Objekts kann nicht serialisiert werden: Montage itextsharp, Version=5.5.11.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, Typ iTextSharp.text.Document.
StackTrace:
bei Microsoft.Dynamics.Nav.Client.AutomationHandler.SerializedValue(Object instance)
bei Microsoft.Dynamics.Nav.Client.AutomationHandler.InvokeAutomationMethodCore(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, NavAutomationArgument[] args)
bei Microsoft.Dynamics.Nav.Client.AutomationHandlerBase.InvokeAutomationMethod(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, NavAutomationArgument[] args)
bei Microsoft.Dynamics.Nav.Client.ServiceClientCallback.<>c__DisplayClass4e.<InvokeAutomationMethod>b__4d()
bei Microsoft.Dynamics.Nav.Client.ServiceClientCallback.<>c__DisplayClass1.<RunClientRequest>b__0()
bei Microsoft.Dynamics.Nav.Client.ServerInvocationManager.<>c__DisplayClass8.<WaitForServerResponse>b__6()
bei Microsoft.Dynamics.Nav.Client.ServerInvocationManager.DoClientRequestAndCatch(Action clientRequest, Action`1 sendToServerIfNotFaulted)
Source: Microsoft.Dynamics.Nav.Client.WinForms
HResult: -2146233088

Ereignis-XML:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="MicrosoftDynamicsNavServer$CH2013_CU38_Work" />
<EventID Qualifiers="0">218</EventID>
<Level>3</Level>
<Task>13</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2020-07-14T09:10:30.808807300Z" />
<EventRecordID>48360</EventRecordID>
<Channel>Application</Channel>
<Computer>WSAAB002.amanninformatik.com</Computer>
<Security />
</System>
<EventData>
<Data>Server instance: CH2013_CU38_Work
Tenant ID: default
Session type: RoleTailoredClient
Session ID: 1
User: AMANNINFORMATIK\AAB
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavNCLDotNetCreateException
SuppressMessage: False
SuppressExceptionCreatedEvent: False
FatalityScope: Call
Message: Eine Instanz des folgenden .NET Framework-Objekts kann nicht serialisiert werden: Montage itextsharp, Version=5.5.11.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, Typ iTextSharp.text.Document.
StackTrace:
bei Microsoft.Dynamics.Nav.Service.ServiceCall.GetClientReturnValue(Action invokeCallback)
bei Microsoft.Dynamics.Nav.Service.NSClientCallback.InvokeAutomationMethod(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, Object[] args)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.GetObjectDataFromClient(NavClientHandle clientHandle)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.GetDotNetObjectFromNavObject(Type targetType, Object value, List`1&amp; disposeObjects)
bei Microsoft.Dynamics.Nav.Runtime.NavDotNet.CreateDotNet(Object[] arguments)
Source: Microsoft.Dynamics.Nav.Service
HResult: -2146233088
----------------------------------
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavNCLDotNetCreateException
SuppressMessage: False
SuppressExceptionCreatedEvent: False
FatalityScope: Call
Message: Eine Instanz des folgenden .NET Framework-Objekts kann nicht serialisiert werden: Montage itextsharp, Version=5.5.11.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, Typ iTextSharp.text.Document.
StackTrace:
bei Microsoft.Dynamics.Nav.Client.AutomationHandler.SerializedValue(Object instance)
bei Microsoft.Dynamics.Nav.Client.AutomationHandler.InvokeAutomationMethodCore(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, NavAutomationArgument[] args)
bei Microsoft.Dynamics.Nav.Client.AutomationHandlerBase.InvokeAutomationMethod(Int32 handle, Int32 typeHandle, String methodName, BindingFlags binding, ParameterModifier[] modifiers, NavAutomationArgument[] args)
bei Microsoft.Dynamics.Nav.Client.ServiceClientCallback.&lt;&gt;c__DisplayClass4e.&lt;InvokeAutomationMethod&gt;b__4d()
bei Microsoft.Dynamics.Nav.Client.ServiceClientCallback.&lt;&gt;c__DisplayClass1.&lt;RunClientRequest&gt;b__0()
bei Microsoft.Dynamics.Nav.Client.ServerInvocationManager.&lt;&gt;c__DisplayClass8.&lt;WaitForServerResponse&gt;b__6()
bei Microsoft.Dynamics.Nav.Client.ServerInvocationManager.DoClientRequestAndCatch(Action clientRequest, Action`1 sendToServerIfNotFaulted)
Source: Microsoft.Dynamics.Nav.Client.WinForms
HResult: -2146233088
</Data>
</EventData>
</Event>

Nur sagt mir das halt leider nichts. Welche Framework-Komponente könnte das sein, die ihm hier fehlt?

Re: Zwei PDFs zusammenfügen

14. Juli 2020 12:20

Nutze mal das Paket hier und entpacke auch die anderen dll Dateien: https://github.com/itext/itextsharp/releases/tag/5.5.10

EDIT:
Bzw. die neueste Version hier: https://github.com/itext/itextsharp/rel ... g/5.5.13.1. Hier musst du die .nupkg Dateien mit einem Packprogramm öffnen (oder einfach die Dateieendung zu ZIP ändern). Am Ende hast du 4 dll Dateien.

Re: Zwei PDFs zusammenfügen

29. Juli 2020 14:40

Hallo zusammen!

Entschuldigt bitte die lange "Denkpause", aber ich war ein paar Tage in den Ferien.

Ich konnte die neuste Version der itextsharp.dll installieren und auch den Code in meinem Test-Objekt kompilieren. Zuerst erhielt ich beim Starten im RTC noch einen Fehler, dass die Instanz nicht serialisiert werden könne. Da ich meine Versuche auf einer lokalen Installation unternommen habe, habe ich dann bei allen DotNet-Variabeln das Property "RunOnClient" auf <Yes> gesetzt und dann lief's in der lokalen Umgebung.

Anschliessend habe ich dann meine Test-Codeunit in die Kunden-Datenbank übernommen und "RunOnClient" wieder auf <No> geändert und - siehe da - jetzt läuft's auch dort!


Vielen herzlichen Dank für Eure tatkräftige Unterstützung!