Articolo tecnico

Trasformare file RTF in PDF: una guida per gli sviluppatori

· Programmazione PDF

Conversione di file RTF in PDF: una guida per sviluppatori Delphi, C# e VB.Net.

Nel mondo dell'elaborazione dei documenti, la conversione di file Rich Text Format (RTF) in Portable Document Format (PDF) è un'attività comune. Questa conversione garantisce che il layout del documento rimanga coerente su diverse piattaforme. Questa guida fornisce soluzioni dettagliate per una conversione efficiente da RTF a PDF utilizzando la nostra libreria per sviluppatori PDF. in Delphi, C# e VB.Net. Seguendo questa guida, è possibile convertire senza problemi i file RTF in documenti PDF mantenendo un'alta fedeltà al contenuto originale. Seguiamo passo dopo passo il processo.

Descrizione del problema.

La sfida principale è convertire un file RTF in un file PDF garantendo che la formattazione e il layout del documento originale siano preservati. Ciò comporta:

  1. Caricamento del file RTF.
  2. Configurazione di un contesto dispositivo virtuale per il rendering.
  3. Stampa il contenuto RTF nel contesto del dispositivo virtuale.
  4. Salva il contenuto renderizzato come file PDF.

Passaggi per raggiungere l'obiettivo.

  1. Inizializza l'ambiente.
    • Carica la libreria PDF losLab.
    • Carica il file RTF in un controllo di testo ricco.
  2. Configura il contesto del dispositivo.
    • Crea un contesto del dispositivo virtuale che simula le dimensioni di una pagina A4.
    • Calcola la scala necessaria per adattare il contenuto all'interno della pagina PDF.
  3. Elabora il contenuto RTF:
    • Utilizza il contesto del dispositivo virtuale per formattare e stampare il contenuto RTF.
    • Cattura il contenuto stampato e crea una nuova pagina PDF da esso.
  4. Salva il documento PDF:
    • Salva le pagine PDF generate su disco.
    • Gestisci più pagine iterando attraverso il contenuto RTF e creando nuovi documenti PDF, se necessario.

Esempio di codice Delphi.

Di seguito è riportata un'implementazione in Delphi che dimostra la conversione di un file RTF in un file PDF utilizzando la nostra libreria PDF.
Il seguente esempio utilizza la versione DLL della libreria di sviluppo PDF (è disponibile anche una versione in codice sorgente Pascal per Delphi).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
unit MainUnit;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, PDFlibAX_TLB, ActiveX;
 
type
  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    function PrintRtfBox(hDc: HDC; rtfBox: TRichEdit; FirstChar: Integer): Integer;
  public
  end;
 
var
  Form1: TForm1;
  PdfDoc: TPDFLibrary;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  PdfDoc := TPDFLibrary.Create(Self);
  RichEdit1.Width := Round(ScaleX(210, mmPixel));
  RichEdit1.Height := Round(ScaleY(297, mmPixel));
  RichEdit1.Lines.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Test.rtf');
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Dc: HDC;
  PageNumber, LastChar, PdfDocId: Integer;
begin
  PageNumber := 1;
  LastChar := 0;
  repeat
    Dc := PdfDoc.GetCanvasDC(Round(ScaleX(210, mmPixel)), Round(ScaleY(297, mmPixel)));
    LastChar := PrintRtfBox(Dc, RichEdit1, LastChar);
    PdfDoc.LoadFromCanvasDc(96, 0);
    PdfDocId := PdfDoc.SelectedPdfDocument;
    PdfDoc.SaveToFile(ExtractFilePath(Application.ExeName) + 'Test' + IntToStr(PageNumber) + '.pdf');
    PdfDoc.RemovePdfDocument(PdfDocId);
    Inc(PageNumber);
  until LastChar = 0;
  ShowMessage('Done');
end;
 
function TForm1.PrintRtfBox(hDc: HDC; rtfBox: TRichEdit; FirstChar: Integer): Integer;
var
  RcDrawTo, RcPage: TRect;
  Fr: TFormatRange;
  NextCharPosition: Integer;
begin
  RcPage.Left := 0;
  RcPage.Right := rtfBox.Left + rtfBox.Width + 100;
  RcPage.Top := 0;
  RcPage.Bottom := rtfBox.Top + rtfBox.Height + 100;
  RcDrawTo.Left := rtfBox.Left;
  RcDrawTo.Top := rtfBox.Top;
  RcDrawTo.Right := rtfBox.Left + rtfBox.Width;
  RcDrawTo.Bottom := rtfBox.Top + rtfBox.Height;
 
  Fr.hdc := hDc;
  Fr.hdcTarget := hDc;
  Fr.rc := RcDrawTo;
  Fr.rcPage := RcPage;
  Fr.chrg.cpMin := FirstChar;
  Fr.chrg.cpMax := -1;
 
  NextCharPosition := SendMessage(rtfBox.Handle, EM_FORMATRANGE, 1, LPARAM(@Fr));
  if NextCharPosition < Length(rtfBox.Text) then
    Result := NextCharPosition
  else
    Result := 0;
end;
 
end.

Esempio di codice C#.

Di seguito è riportata un'implementazione in C# che realizza la stessa funzionalità dell'esempio Delphi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using PDFLibrary;
 
namespace RtfToPdf
{
    public partial class Form1 : Form
    {
        private PDFLibrary PdfDoc;
 
        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
 
        [StructLayout(LayoutKind.Sequential)]
        private struct CharRange
        {
            public int cpMin;
            public int cpMax;
        }
 
        [StructLayout(LayoutKind.Sequential)]
        private struct FormatRange
        {
            public IntPtr hDc;
            public IntPtr hdcTarget;
            public RECT rc;
            public RECT RcPage;
            public CharRange chrg;
        }
 
        private const int WM_USER = 0x400;
        private const int EM_FORMATRANGE = WM_USER + 57;
 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, ref FormatRange lParam);
 
        public Form1()
        {
            InitializeComponent();
            PdfDoc = new PDFLibrary();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            richTextBox1.SetBounds(0, 0, Convert.ToInt32(ScaleX(210, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)), Convert.ToInt32(ScaleY(297, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)));
            richTextBox1.LoadFile(Application.StartupPath + "\\Test.rtf");
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr Dc;
            int PageNumber = 1;
            int LastChar = 0;
            int PdfDocId;
            do
            {
                Dc = PdfDoc.GetCanvasDC(Convert.ToInt32(ScaleX(210, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)), Convert.ToInt32(ScaleY(297, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)));
                LastChar = PrintRtfBox(Dc, richTextBox1, LastChar);
                PdfDoc.LoadFromCanvasDc(96, 0);
                PdfDocId = PdfDoc.SelectedPdfDocument;
                PdfDoc.SaveToFile(Application.StartupPath + "\\Test" + PageNumber + ".pdf");
                PdfDoc.RemovePdfDocument(PdfDocId);
                PageNumber++;
            } while (LastChar != 0);
            MessageBox.Show("Done");
        }
 
        private int PrintRtfBox(IntPtr hDc, RichTextBox rtfBox, int FirstChar)
        {
            RECT RcDrawTo = new RECT();
            RECT RcPage = new RECT();
            FormatRange Fr = new FormatRange();
 
            RcPage.Left = 0;
            RcPage.Right = rtfBox.Left + rtfBox.Width + 100;
            RcPage.Top = 0;
            RcPage.Bottom = rtfBox.Top + rtfBox.Height + 100;
            RcDrawTo.Left = rtfBox.Left;
            RcDrawTo.Top = rtfBox.Top;
            RcDrawTo.Right = rtfBox.Left + rtfBox.Width;
            RcDrawTo.Bottom = rtfBox.Top + rtfBox.Height;
 
            Fr.hDc = hDc;
            Fr.hdcTarget = hDc;
            Fr.rc = RcDrawTo;
            Fr.RcPage = RcPage;
            Fr.chrg.cpMin = FirstChar;
            Fr.chrg.cpMax = -1;
 
            IntPtr wParam = new IntPtr(1);
            IntPtr NextCharPosition = SendMessage(rtfBox.Handle, EM_FORMATRANGE, wParam, ref Fr);
 
            if (NextCharPosition.ToInt32() < rtfBox.Text.Length)
                return NextCharPosition.ToInt32();
            else
                return 0;
        }
 
        private float ScaleX(float value, GraphicsUnit fromUnit, GraphicsUnit toUnit)
        {
            using (Graphics g = this.CreateGraphics())
            {
                return value * g.DpiX / 96.0f;
            }
        }
 
        private float ScaleY(float value, GraphicsUnit fromUnit, GraphicsUnit toUnit)
        {
            using (Graphics g = this.CreateGraphics())
            {
                return value * g.DpiY / 96.0f;
            }
        }
    }
}

Spiegazione e giustificazione.

  • Inizializzazione: Sia la versione Delphi che la versione C# inizializzano la losLab PDF Library. versione DLL. Il file RTF viene caricato in un controllo di testo ricco (RichEdit in Delphi e RichTextBox in C#).
  • Configurazione del contesto del dispositivo: Il contesto del dispositivo è configurato per simulare una dimensione di pagina A4, garantendo che il contenuto si adatti correttamente durante la visualizzazione.
  • Elaborazione del contenuto: Il PrintRtfBox La funzione (o metodo) formatta il contenuto RTF e lo stampa nel contesto del dispositivo. Questo metodo calcola le dimensioni necessarie e chiama l'API Windows appropriata per gestire la formattazione del testo.
  • Generazione di PDF: Il ciclo in entrambi gli esempi elabora il contenuto RTF pagina per pagina, creando nuovi documenti PDF se necessario. Ogni pagina viene salvata su disco e quindi rimossa dalla memoria per gestire le risorse in modo efficiente.
  • Notifica di completamento: Dopo aver elaborato tutte le pagine, una finestra di messaggio informa l'utente che la conversione è completa.

Seguendo questi passaggi, garantiamo una trasformazione affidabile e precisa dei file RTF in documenti PDF, sfruttando le funzionalità della libreria losLab PDF. Questo approccio garantisce che la formattazione e il layout originali siano preservati, ottenendo risultati PDF di qualità professionale.

Esempio di conversione da RTF a PDF in VisualBasic.Net.

Inoltre, forniamo anche un'implementazione in VB.Net, che ha la stessa funzionalità degli esempi in Delphi e C#:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Imports System.Runtime.InteropServices
Imports PDFlibDLL
 
Public Class Form1
 
    Private PdfDoc As PDFlibrary
 
    <StructLayout(LayoutKind.Sequential)>
    Private Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
    End Structure
 
    <StructLayout(LayoutKind.Sequential)>
    Private Structure CharRange
        Public cpMin As Integer
        Public cpMax As Integer
    End Structure
 
    <StructLayout(LayoutKind.Sequential)>
    Private Structure FormatRange
        Public hDc As IntPtr
        Public hdcTarget As IntPtr
        Public rc As RECT
        Public rcPage As RECT
        Public chrg As CharRange
    End Structure
 
    Private Const WM_USER As Integer = &H400
    Private Const EM_FORMATRANGE As Integer = WM_USER + 57
 
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function SendMessage(hWnd As IntPtr, wMsg As Integer, wParam As IntPtr, ByRef lParam As FormatRange) As IntPtr
    End Function
 
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        PdfDoc = New PDFlibrary()
        RichTextBox1.SetBounds(0, 0, Convert.ToInt32(ScaleX(210, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)), Convert.ToInt32(ScaleY(297, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)))
        RichTextBox1.LoadFile(Application.StartupPath & "\Test.rtf")
    End Sub
 
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim Dc As IntPtr
        Dim PageNumber As Integer = 1
        Dim LastChar As Integer = 0
        Dim PdfDocId As Integer
 
        Do
            Dc = PdfDoc.GetCanvasDC(Convert.ToInt32(ScaleX(210, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)), Convert.ToInt32(ScaleY(297, GraphicsUnit.Millimeter, GraphicsUnit.Pixel)))
            LastChar = PrintRtfBox(Dc, RichTextBox1, LastChar)
            PdfDoc.LoadFromCanvasDc(96, 0)
            PdfDocId = PdfDoc.SelectedPdfDocument
            PdfDoc.SaveToFile(Application.StartupPath & "\Test" & PageNumber & ".pdf")
            PdfDoc.RemovePdfDocument(PdfDocId)
            PageNumber += 1
        Loop While LastChar <> 0
 
        MessageBox.Show("Done")
    End Sub
 
    Private Function PrintRtfBox(hDc As IntPtr, rtfBox As RichTextBox, FirstChar As Integer) As Integer
        Dim RcDrawTo As New RECT()
        Dim RcPage As New RECT()
        Dim Fr As New FormatRange()
 
        RcPage.Left = 0
        RcPage.Right = rtfBox.Left + rtfBox.Width + 100
        RcPage.Top = 0
        RcPage.Bottom = rtfBox.Top + rtfBox.Height + 100
        RcDrawTo.Left = rtfBox.Left
        RcDrawTo.Top = rtfBox.Top
        RcDrawTo.Right = rtfBox.Left + rtfBox.Width
        RcDrawTo.Bottom = rtfBox.Top + rtfBox.Height
 
        Fr.hDc = hDc
        Fr.hdcTarget = hDc
        Fr.rc = RcDrawTo
        Fr.rcPage = RcPage
        Fr.chrg.cpMin = FirstChar
        Fr.chrg.cpMax = -1
 
        Dim wParam As IntPtr = New IntPtr(1)
        Dim NextCharPosition As IntPtr = SendMessage(rtfBox.Handle, EM_FORMATRANGE, wParam, Fr)
 
        If NextCharPosition.ToInt32() < rtfBox.Text.Length Then
            Return NextCharPosition.ToInt32()
        Else
            Return 0
        End If
    End Function
 
    Private Function ScaleX(value As Single, fromUnit As GraphicsUnit, toUnit As GraphicsUnit) As Single
        Using g As Graphics = Me.CreateGraphics()
            Return value * g.DpiX / 96.0F
        End Using
    End Function
 
    Private Function ScaleY(value As Single, fromUnit As GraphicsUnit, toUnit As GraphicsUnit) As Single
        Using g As Graphics = Me.CreateGraphics()
            Return value * g.DpiY / 96.0F
        End Using
    End Function
 
End Class