JPG+PDF zu einer PDF machen

  • VB.NET

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Volker Bunge.

    JPG+PDF zu einer PDF machen

    Hallo zusammen,

    Ich habe folgendes vor

    1. Eine JPG und eine PDF zu einer PDF machen. Die JPG muss aber als erste Seite in der neuen PDF Datei sein.

    2. Mehrere Bilder per Drag & Drop in Pictureboxen ziehen (müsste ich noch hinbekommen) und dann diese Bilder in eine PDF-Datei packen, so dass jedes Bild eine bestimmte Größe (Bsp. 600 x 800) hat und pro Bild eine Seite ist. Die Bilder stammen aus einer e-Mail und sind entweder Anhänge oder direkt als Bild in der Nachricht drin. Ein Missquelle ist auch denkbar. Daher soll der Benutzer diese auf die leeren Pictureboxen ziehen und somit bestimmen, welche Bilder er zusammenfassen möchte.

    Das Ganze sind zwar für zwei verschiedene Projekte, aber das Ziel ist das selbe.

    Wenn es ohne Report geht, um so besser. Irgendein Merge-Funktion oder ähnliches würde mir schon reichen. Der Benutzer soll am Ende möglichst nichts bis ganz wenig tun und es sollte recht schnell gehen, also so max. 10 Sekunden wären super (natürlich abhängig von den Rechner, die sind aber schon recht neu und mit 16 GB Arbeitsspeicher ausgerüstet).

    Könnt Ihr mir da ein paar Starthilfen geben, wie ich da am besten vorgehen sollte/muss. Welche Erweiterungen braucht mein VB Studio 2019 (CrystalReports oder ähnliches). Kostenlose Erweiterungen nehme ich gerne, sofern die nötig sind. Kostenpflichte hängt dann vom Preis ab, sollten aber vorher kostenlos testbar sein.

    Vielen Dank

    Volker

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „bungev“ ()

    @bungev Willkommen im Forum. :thumbup:
    Habe ich Dich richtig verstanden?
    Du willst eine Seite mit Bildern in eine PDF drucken.
    Du willst an diese eine Seite (in Form eines PDF) eine andere fertige PDF-Datei dranhängen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo RodFromGermany,

    genau.

    Noch mal etwas weiter ausgeholt.

    Fall 1: Das Ganze läuft so ab: Ich scanne Ablesebelege ein, die werden erkannt, ich korrigiere ggf. einige Felder und kann auch einige Belege zur Nachbearbeitung "markieren". Wenn ich damit fertig bin, bekomme ich eine CSV-Datei in der meine ganzen Ergebnisse drin stehen, diese wird dann in unser System eingespielt. Die gescannten Belege stecken dann in jeweils einer PDF. die das Erkennungsprogramm erzeugt. Die CSV-Datei dann noch mit Excel per Makro eingelesen und für jeden markierten Belege wird über eine Excel Seite ein Deckblatt generiert. Dieser Tabellenbereich speichere ich als JPG zu der PDF dazu ab. Diese JPG dient so zu sagen als Deckblatt für die PDF-Datei. (Läuft somit bis hierher einwandfrei und hier kann und brauche ich auch nichts ändern)

    Normalerweise rufe ich jetzt mein Scanprogramm auf, importiere alle "markierten" Belege und das Scanprogramm zieht schön erst die JPG-Datei und dann die passende PDF Datei. Jeder Beleg besteht nun aus JPG + PDF Datei. Das Ganze kann ich dann kpl. markieren und als e-Mail versenden. Dabei ist jeder Beleg eine PDF-Datei.

    Jetzt habe ich schon für diesen Prozess ein Zusatzprogramm erstellt. Mein Gedanke wäre nun, dass dieses Programm beim Beenden oder per Klick (hier muss ich mir aber noch mal evtl. Gedanken machen) das Erstellen dieser E-Mail - PDF übernimmt und mir auch gleich die e-Mail verschickt (Empfänger ist immer der Selbe).

    Fall 2:

    Wir bekommen von Kunden Bilder per e-Mail geschickt. Diese werden jetzt normaler Weise ausgedruckt und ich scanne diese wieder ein und archiviere diese. Auf diesen Ausdrucken ist jetzt noch ein Barcode, den die Mitarbeiter vorher zuweisen und das System weis somit welcher Barcode wo hin gehört.

    Und ja, diese Methode ist leider für viele die einzeige Möglichkeit, das Bild zu archivieren. Weil abspeichern bzw. als PDF-Drucken und diese dann zuweisen kennen die meisten nicht (oder wollen es auch aus Gewohnheit nicht). Ist leider so.

    Da jetzt aber auch nicht immer nur ein Bild geschickt wird, sondern mehrere, und diese dann auch noch im Text stehen, war halt meine Idee/Versuch, ein Programm zu schreiben, welches einige Pictureboxen bietet, in den der Benutzer die einzelne Bilder ablegen kann (also Drag&Drop).

    Den E-Mail Text könnte man ggf. auch noch markieren und in eine Textbox ziehen. Vielleicht sogar die ganze e-Mail, um dann den gesamten Text als Extraseite mit in die PDF zu nehmen.
    Wenn man die gesamte e-Mail in mein Programm ziehen könnte und dann alle Bilder und den Text extrahieren könnte wäre das natürlich die Ultimative Lösung.

    (Der obere Abschnitt fiel mir gerade beim Schreiben noch ein)

    So, hoffe mal dass mein Problem jetzt deutlicher geworden ist.

    Kurz noch mal zusammengefasst

    1. Existierende JPG (als Deckblatt bzw. 1. Seite in neuer PDF) + fertige PDF = neue PDF-Datei
    2. E-Mail Text + E-Mail Anhänge (Bilder) = neue PDF-Datei (per einzelnen Drag&Drop oder nur die e-Mail ist mir egal (letzteres wäre die Top-Lösung)

    E-Mail Programm ist Outlook 365 Exchange (seit letzter Woche).

    Gruß

    Volker
    @bungev Für den Druck der ersten Seite empfehle ich Dir, den PDF-Drucker als Standarddrucker zu verwenden und einfach ein Blatt auszugeben.
    Drucken mehrseitiger Dokumente
    Sieh Dir das Fein-Tuning im PrintPreviewDialog an, das geht fix und ist sofort verfügbar.
    Zum Mergen von PDFs gibt es mehrere Varianten, ich empfehle Dir PdfSharp, da musst Du mal ein wenig recherchieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo zusammen,

    so, mein erstes Problem habe ich gelöst. Mein Excel-Deckblatt wird über Excel als PDF abgespeichert. Somit habe ich also schon einmal 2 PDF-Dateien.

    Habe zuhause noch eine PDF-Merger (PDFSplitMerge) Lösung gefunden und die hier auch soweit erfolgreich eingebunden, oder auch nicht.

    Gibt es die zusammengeführte Datei nicht, dann kann ich die zusammengeführte PDF auch normal öffnen. Starte ich hingegen das Ganze noch einmal, so klappt die Anzeige nicht mehr. Mein PDF-Anzeigeprogramm sagt mir immer, dass es keine PDF-Datei sei. Merkwürdig, denn ich lösche doch vorher diese Dateien per Kill-Befehl

    Jetzt ist halt die Frage woran dies liegen kann.

    Habe daher mal ein paar MSGBOXen eingebaut um somit das Warten zu simulieren. Leider ohne Erfolg.

    Zum Using-Befehl: Auch hier habe ich mal gelesen. dass hier ein Lesen simuliert wird es erst dann weiter geht, wenn die Datei lesbar ist. Klappt aber auch nicht. (sofern dies überhaupt ein Ansatz gewesen sein kann).

    Jetzt ist halt die Frage: Woran liegt es und was muss ich ändern.

    Hier mal der Code

    VB.NET-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. Dim pdf As PDFSplitMerge.CPDFSplitMergeObj
    3. Dim Dateien As String
    4. Dim DateiSplit() As String
    5. Dim Ziel As String
    6. Dim OutlookAnhänge As String
    7. Dim NQuelle As String
    8. Dim z As Integer
    9. Timer1.Stop()
    10. ' Evtl. alte Outlook-Anhänge löschen
    11. 'For z = 0 To 100
    12. ' OutlookAnhänge(z) = ""
    13. 'Next
    14. OutlookAnhänge = ""
    15. z = 0 ' für die neuen Outlook-Anhänge
    16. For Each Dir As String In Directory.GetDirectories("C:\Daten\")
    17. ' MessageBox.Show(Dir)
    18. pdf = New CPDFSplitMergeObj
    19. NQuelle = Dir
    20. If NQuelle = "" Then
    21. Exit Sub
    22. Else
    23. Dateien = Dateien_Ermitteln(NQuelle)
    24. ' MsgBox(Dateien)
    25. End If
    26. DateiSplit = Split(Dateien, "|")
    27. Ziel = NQuelle & "\" & Replace(Path.GetFileName(DateiSplit(0)), "0_", "9_")
    28. ' Evtl. alte Zieldatei löschen
    29. Try
    30. Kill(Ziel)
    31. Using fs As New System.IO.FileStream(Ziel, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite)
    32. End Using
    33. MessageBox.Show("alte Datei gelöscht")
    34. Catch ex As Exception
    35. ' MessageBox.Show(ex.Message)
    36. End Try
    37. 'MsgBox(Ziel)
    38. pdf.Merge(Dateien, Ziel)
    39. Using fs As New System.IO.FileStream(Ziel, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite)
    40. End Using
    41. 'fs = Nothing
    42. pdf = Nothing
    43. ' Die Outlook-Anhänge festhalten
    44. OutlookAnhänge = OutlookAnhänge & Ziel & "|"
    45. MessageBox.Show("Datei " & Ziel & " erstellt. ")
    46. z = z + 1
    47. Next
    48. Using fs As New System.IO.FileStream(Ziel, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite)
    49. End Using
    50. MessageBox.Show("Datei " & Ziel & " erstellt. ")
    51. ' letzter | entfernen
    52. OutlookAnhänge = Mid(OutlookAnhänge, 1, Len(OutlookAnhänge) - 1)
    53. ' E-Mail erstellen
    54. Call Outlook_Mail_erzeugen(,, OutlookAnhänge)
    55. End Sub
    56. Public Function Dateien_Ermitteln(Pfad As String, Optional MaxLänge As Integer = 10) As String
    57. Dateien_Ermitteln = ""
    58. For Each items As String In System.IO.Directory.GetFiles(Pfad)
    59. If Len(System.IO.Path.GetExtension(items)) < MaxLänge And InStr(System.IO.Path.GetExtension(items), ".pdf") > 0 Then
    60. If Mid(Pfad, Len(Pfad), 1) <> "\" Then
    61. Dateien_Ermitteln = Dateien_Ermitteln & Pfad & "\" & System.IO.Path.GetFileName(items) & "|"
    62. Else
    63. Dateien_Ermitteln = Dateien_Ermitteln & Pfad & System.IO.Path.GetFileName(items) & "|"
    64. End If
    65. End If
    66. Next
    67. Dateien_Ermitteln = Mid(Dateien_Ermitteln, 1, Len(Dateien_Ermitteln) - 1)
    68. End Function
    69. Public Sub Outlook_Mail_erzeugen(Optional ByVal Betreff As String = "Fehlerhafte Ablesungen",
    70. Optional ByVal Bodytext As String = "",
    71. Optional ByVal Anhang As String = "Datei als Anhang",
    72. Optional ByVal Empfaenger As String = "xx@yyy.de",
    73. Optional ByVal CCEmpfaenger As String = "")
    74. Try
    75. '--- Check ob der Outlook läuft (ab win8 muss das so)
    76. If Process.GetProcessesByName("outlook").Count > 0 Then
    77. '--- Tue nichts, alles fein ---
    78. Else
    79. '--- Outlook starten ---
    80. Process.Start("outlook")
    81. Application.DoEvents()
    82. End If
    83. '--- Objekte des Outlook-Objektmodels initialisieren ---
    84. Dim objOutlook As Object
    85. Dim objOutlookMsg As Object
    86. Const cMailItem = 0
    87. Dim Anhänge() As String
    88. '--- evtl. weitere wichtige, selbsterklärende Konstanten ---
    89. 'Const cBCC = 3
    90. 'Const cImportanceHigh = 1
    91. 'Const cCC = 2
    92. Const cTo = 1
    93. '--- erstellen der notwendigen Objekte ---
    94. objOutlook = CreateObject("Outlook.Application")
    95. objOutlookMsg = objOutlook.CreateItem(cMailItem)
    96. '--- Zusammenbasteln der Mail ---
    97. With objOutlookMsg
    98. Dim objOutlookRecip As Object = .Recipients.Add(Empfaenger)
    99. objOutlookRecip.type = cTo
    100. .Subject = Betreff
    101. .Body = Bodytext
    102. .CC = CCEmpfaenger
    103. If Anhang <> "" Then
    104. Anhänge = Split(Anhang, "|")
    105. For a = 1 To Anhänge.Length - 1
    106. .Attachments.add(Anhänge(a))
    107. Next
    108. End If
    109. '.Importance = olImportanceHigh
    110. .Display() ' Display() zeigt die neue Nachricht, .Send() sendet direkt
    111. End With
    112. '--- Objekte zerstören ---
    113. objOutlookMsg = Nothing
    114. objOutlook = Nothing
    115. Catch ex As Exception
    116. '--- Fehler abfangen falls kein Outlook installiert ist ---
    117. MsgBox(ex.Message.ToString)
    118. '----------------------------------------------------------
    119. End Try
    120. End Sub


    Der Code ist jetzt noch nicht von evtl. Müll befreit. Am Ende soll noch eine e-Mail per Outlook Exchange erstellt werden. Dies klappt auch schon.

    Dabei gibt es aber auch ein Problem. Immer die letzte Datei wird nicht eingefügt ob wohl sie da ist und beim ersten Mal auch geöffnet werden kann.

    Hoffe, mir kann einer von Euch weiterhelfen.

    Gruß

    Volker
    Hallo zusammen,

    habe jetzt die Lösung gefunden.

    1. Ich habe das Löschen der alten zusammengeführten Dateien, das Mergen und das Suchen der Anhänge jeweils in eine For Each-Schleife gepackt.
    2. Das Problem des fehlenden Anhanges war ein Null-basierter Zählerfehler. Zeile 134 musss bei 0 anfangen also For a = 0 To Anhänge.Length - 1. Somit fehlte nicht der letzte, sondern der erste Dateiname

    Warum das nicht in einer Schleife geht, bleibt als Frage dann noch übrig.

    Hier noch einmal der Vollständigkeit halber der Button_Click-Code kpl. und auch bereinigt.

    VB.NET-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. Dim pdf As PDFSplitMerge.CPDFSplitMergeObj
    3. Dim Dateien As String
    4. Dim DateiSplit() As String
    5. Dim Ziel As String
    6. Dim OutlookAnhänge As String
    7. Dim NQuelle As String
    8. ' Den Zwischenablageüberprüfungstimer stoppen
    9. Timer1.Stop()
    10. ' Hier nun erst einmal evtl. alte zusammengefügte Dateien löschen
    11. For Each Dir As String In Directory.GetDirectories("C:\Daten\")
    12. For Each items As String In System.IO.Directory.GetFiles(Dir)
    13. If InStr(items.ToString, "\9_") > 0 Then
    14. System.IO.File.Delete(items.ToString)
    15. End If
    16. Next
    17. Next
    18. For Each Dir As String In Directory.GetDirectories("C:\Daten\")
    19. pdf = New CPDFSplitMergeObj
    20. NQuelle = Dir
    21. If NQuelle = "" Then
    22. Exit Sub
    23. Else
    24. Dateien = Dateien_Ermitteln(NQuelle)
    25. End If
    26. DateiSplit = Split(Dateien, "|")
    27. Ziel = NQuelle & "\" & Replace(Path.GetFileName(DateiSplit(0)), "0_", "9_")
    28. pdf.Merge(Dateien, Ziel)
    29. pdf = Nothing
    30. Next
    31. 'Anhänge für Outlook ermitteln
    32. OutlookAnhänge = ""
    33. For Each Dir As String In Directory.GetDirectories("C:\Daten\")
    34. For Each items As String In System.IO.Directory.GetFiles(Dir)
    35. If InStr(items.ToString, "\9_") > 0 Then
    36. OutlookAnhänge = OutlookAnhänge & items.ToString & "|"
    37. End If
    38. Next
    39. Next
    40. ' letztes Trennzeichen | entfernen
    41. OutlookAnhänge = Mid(OutlookAnhänge, 1, Len(OutlookAnhänge) - 1)
    42. ' E-Mail erstellen
    43. Call Outlook_Mail_erzeugen(,, OutlookAnhänge)
    44. End Sub


    Gruß

    Volker