theunreal
Goto Top

Powershell itextSharp Zeilenumbruch

Moin zusammen,

ich habe vor mit Hilfe eines Powershellskriptes eine Email abzurufen und komplett inkl. Attachements als PDF zu speichern, da Thunderbird ums verrecken keine pdf Anhänge
automatisch drucken kann.

Ich arbeite mit Mailkit (Danke nochmal Uwe face-smile) und iTextSharp.

Mit Mailkit extrahiere ich aus dem TextBody der Email eine von ID und speichere den Body zur automatisierten Verarbeitung als ID.TXT, und die Mail mit Attachements als ID.pdf.
Das funktioniert auch wunderbar - bis auf ein Problem :

itextsharp entfernt die Zeilenumbrüche aus dem mailBody face-sad. So erhalte ich eine fomatierte Textdatei aber eine unformatierte PDF.

             $pdfFile.Open()
    
                    $pdf_Content = $PdfWriter.directContent
                    $pdf_Content.saveState()
                    $pdf_Content.beginText()
                    #Textposition angeben :
                    $pdf_Content.SetTextMatrix(25,800)
                    $pdf_Content.setFontAndSize($CourierFont, 14)
                   
                    # Text zufügen :
                    $pdf_Content.ShowText($m.TextBody)
                    $pdf_Content.endText()
                    $pdf_Content.restoreState()
                    
                  
                    $pdfFile.Close()
                    $FileStream.Close()

Und viel mehr mache ich mit der txt auch nicht :
   
                $txtContent = $($DOWNLOADPATH + $m.TextBody.Substring(0,12)+".txt")  
                $m.TextBody | Add-content $txtContent

Da so ziemlich alle Tutorials in c# sind, ist es für mich grad schwer, die Lösung zu finden :/
Gruß Sascha

edit:

Mit Notepad++ wird [CR][LF] auch beim "aus der PDF" kopierten, unvollständigen Text angezeigt. Die Umbrüche sind also vorhanden, werden aber scheinbar nicht richtig interpretiert?

Content-ID: 572835

Url: https://administrator.de/contentid/572835

Ausgedruckt am: 25.11.2024 um 05:11 Uhr

godlie
godlie 19.05.2020 um 12:50:38 Uhr
Goto Top
Hallo,

wie sieht denn dein TextBody aus ?
Welche Zeilenumbrüche beinhaltet er?
TheUnreal
TheUnreal 19.05.2020 aktualisiert um 12:59:16 Uhr
Goto Top
Hi godlie,

die Umbrüche sind als CR LF kodiert, wie es unter Windowssystem sein sollte.

Der Mailbody ist fest als [String]$m.TextBody deklariert.

Wie ich im edit ergänzt habe, scheint es bei Itext# noch eine Funktion geben zu müssen, mit der der LFCR auch beachtet wird.
Ich wälze grad die Doku face-smile.

Gruß Sascha

Grad was gefunden :
https://stackoverflow.com/questions/10756171/adding-a-new-line-in-itexts ...

So wie es aussieht, bastel ich grad "line to line", und sollte den PdfContentByte nutzen.
Dann versuche ich mal mein Glück...
godlie
godlie 19.05.2020 aktualisiert um 13:07:39 Uhr
Goto Top
Hallo,

hm kann es evtl sein, dass dein
$m.TextBody | Add-content $txtContent 
<-- dir die LineBreaks verwirft?
hatte selbiges mal bei einem StreamRead von einer TXT
144260
144260 19.05.2020 aktualisiert um 13:20:09 Uhr
Goto Top
So wie es aussieht, bastel ich grad "line to line", und sollte den PdfContentByte nutzen.
Nein musst du nicht dafür gibt es das Paragraph Object, dort den Text hineinschreiben und das Paragraph Element z.B. einem ColumnText-Object hinzufügen.
https://api.itextpdf.com/iText5/5.5.9/com/itextpdf/text/Paragraph.html
Dann werden auch Zeilenumbrüche wie gehabt genutzt.
TheUnreal
TheUnreal 19.05.2020 aktualisiert um 13:27:24 Uhr
Goto Top
@godlie

Danke für die Idee, aber $m.TextBody bleibt dabei doch unangetastet?
Ich schreibe ja nur den Inhalt in eine Textdatei.

@144260
Danke, dann schau ich mal dass ich das Paragraph Objekt ausprobiere - wie du schon angeerkt hast, der PdfContentByte hat mich auch nicht
weiter gebracht face-smile.

Gruß von hier nach da !
colinardo
Lösung colinardo 19.05.2020, aktualisiert am 20.05.2020 um 07:13:04 Uhr
Goto Top
Servus.

Funktionsfähiges Beispiel (getestet)
# ....

# neues PDF Dokument erstellen
$doc = [iTextSharp.text.Document]::new([iTextSharp.text.PageSize]::A4)
$writer = [iTextSharp.text.pdf.PdfWriter]::GetInstance($doc,[System.IO.File]::Create("E:\Pfad\test.pdf"))  
$doc.Open()

# neuen Absatz erstellen
$p = New-Object iTextSharp.text.Paragraph
# font Stil und Größe festlegen
$font = [iTextSharp.text.pdf.BaseFont]::CreateFont([iTextSharp.text.pdf.BaseFont]::COURIER,[iTextSharp.text.pdf.BaseFont]::CP1252,[iTextSharp.text.pdf.BaseFont]::NOT_EMBEDDED)
$p.Font = $font
$p.Font.Size = 10
# Text dem Absatz hinzufügen
$p.Add($m.TextBody) | out-null

# ColumnText Rahmen erstellen, positionieren und den Absatz hinzufügen
$colText = New-Object iTextSharp.text.pdf.ColumnText $writer.DirectContent
$colText.SetSimpleColumn(20,20,$doc.PageSize.Width-20,$doc.PageSize.Height-20)
$colText.AddElement($p)
$colText.Go() | out-null

$doc.Close()
$writer.Close()

# ....
Grüße Uwe
filippg
filippg 20.05.2020 um 00:47:38 Uhr
Goto Top
Hallo,

ohne die geringste Ahnung von "iTextSharp" zu haben (Ahnungslosigkeit ist immer eine gute Voraussetzung ;) ): Eine Eigenart von PowerShell ist ihre ganz besondere Vorliebe für Arrays. Ich weiß nicht, wo bzw. wie du "$m.TextBody" (das ist wohl dein Text?) herbekommst. Aber möglicherweise ist das kein String mit Zeilenumbrüchen, sondern ein Array von Strings ohne Zeilenumbrüche.
Beispiel mit get-content:
$lines = Get-Content .\foo.txt # Textdatei mit drei Zeilen
$lines.GetType().FullName
# => System.Object

$lines.Length
# => 3 #Anzahl der Zeilen in Datei bzw. Elemente im Array

$stringLines = $lines -join "`r`n"  
$stringLines.GetType().FullName
# => System.String
$stringLines.Length
# => 49 #Anzahl der Zeichen in Textdatei bzw. String

Konsequenterweise erzeugt "$lines | Add-Content foo2.txt" wiederum eine Datei mit mehreren Zeilen: Die Elemente des Arrays werden einzeln an Add-Content übergeben, das erzeugt dann für jedes Element eine Ausgabe (also jeweils einen eigenen Schreibvorgang) und beendet diese mit einen Zeilenumbruch. Wenn ich das richtig verstehe, enthält dein $txtContent ja Zeilenumbrüche; das könnte die Erklärung sein.

Grüße

Filipp
colinardo
Lösung colinardo 20.05.2020 aktualisiert um 08:22:58 Uhr
Goto Top
Servus.
Zitat von @filippg:

Ich weiß nicht, wo bzw. wie du "$m.TextBody" (das ist wohl dein Text?) herbekommst. Aber möglicherweise ist das kein String mit Zeilenumbrüchen, sondern ein Array von Strings ohne Zeilenumbrüche.

Nein, es ist ein reiner String, siehe

http://www.mimekit.net/docs/html/P_MimeKit_MimeMessage_TextBody.htm

Und für alle weiteren die hier versuchen mit Vermutungen Ihr Glück zu suchen: Die Methode ShowText des ByteContent Objects supported keine Zeilenumbrüche, deswegen habe ich oben das Beispiel mit dem Paragraph Object gepostet, dieses unterstützt nämlich Multiline-Text!

Grüße Uwe
TheUnreal
TheUnreal 20.05.2020 um 09:01:19 Uhr
Goto Top
Hallo Uwe,

vielen,vielen Dank für deine Hilfe ! Nun läuft es wie es soll face-smile

Gruß Sascha
colinardo
colinardo 20.05.2020 um 09:03:28 Uhr
Goto Top
Na dann kann Himmelfahrt ja kommen face-wink.
TheUnreal
TheUnreal 26.05.2020 um 09:04:06 Uhr
Goto Top
Für alle die hier landen, weil sie sich für ItextSharp interessieren sei :

ItextSharp Tutorial

ans Herz gelegt. Da ist das verständlich erklärt (Programmiersprachenunabhängig).

Gruß nochmal
TheUnreal
TheUnreal 27.05.2020 um 12:26:23 Uhr
Goto Top
Hallo Uwe,

ich habe mich dann doch etwas zu früh grefreut face-sad

Mit den Bildern funktioniert alles, aber das Problem ist, dass ich die PDF nicht eingelesen oder geschrieben bekomme - sicher mache ich schon wieder eine Kleinigkeit verkehrt face-smile? Allerdings möchte ich auch gerne verstehen, was ich falsch mache?

Ist es eigentlich möglich, die Anhänge "on-the-fly" an $Image zu übergeben? Also ohne zwischenspeichern im System?

switch ($a.ContentType.MediaType) {

                            "image" {            
                                                $doc.NewPage()
                                                #Datei ins System schreiben
                                                $targetfile = ($a.Filename)
                                                $fs = [IO.File]::Create("$AttachementPath" + "$targetfile")  
                                                $a.Content.DecodeTo($fs)
                                                $fs.Close();$fs.Dispose()
                                                #Datei in die PDF aufnehmen
                                                $Image = ([iTextSharp.text.Image]::getInstance("$AttachementPath" + "$targetfile"))                                       
                                                $Image.ScaleToFit($doc.PageSize)
                                                $doc.Add($Image)
                                   }

                            "application"{  
                                            if ($a.ContentType.MediaSubtype= ".pdf"){  
                                                #Datei ins System schreiben
                                                $targetfile = ($a.Filename)
                                                $fs = [IO.File]::Create("$AttachementPath" + "$targetfile")  
                                                $a.Content.DecodeTo($fs)
                                                $fs.Dispose();$fs.Close()                                    
                                                
                                                # Datei im reader öffnen
                                                $reader = [iTextSharp.text.pdf.PdfReader]::GetImportedPage("$AttachementPath" + "$targetfile")  
                                                
                                                #$pdfCopy = [iTextSharp.text.pdf.PdfCopy]::GetInstance($doc,$pdf_stream)                                   
                                                #$pdfCopy = New-Object iTextSharp.text.pdf.PdfCopy($doc,$pdf_stream)                                   
                                                                                                
                                                $pCount = $reader.NumberOfPages

                                                    for ($i = 1; $i -lt $pCount ; $i++) {$doc.AddPage($writer.GetImportedPage($reader, $i))}    
                                                                                                                                                                        
                                                $reader.Dispose()
                                            }
                                            else {
                                               $targetfile = ($a.Filename)
                                               $fs = [IO.File]::Create("$constPath"  + "$targetfile")  
                                                $a.Content.DecodeTo($fs)
                                                $fs.Dispose();$fs.Close()
                                                $doc.NewPage()
                                                $doc.AddText("$targetfile" im DMS)  
                                             }
                                        }
144260
144260 27.05.2020 aktualisiert um 13:58:20 Uhr
Goto Top
ich habe mich dann doch etwas zu früh grefreut
Irgendwie Off-Topic ?!
TheUnreal
TheUnreal 29.05.2020 um 08:14:33 Uhr
Goto Top
?
Verstehe deinen Kommentar irgendwie nicht - Hätte ich ein neues Thema eröffnen müssen?

Meine Lösung zu dem Problem sieht nun so aus, dass ich den MailBody und ggfls. Bilder in eine PDF schreibe, und PDFs aus Anhängen dann
damit in einer neuen PDF merge. Funktioniert - aber ich hätte es mir anders gewünscht.

Allerdings, wenn man weder C# kann, noch Powershell ist das bis hierher schon okay face-smile

Gruß