Przejdź do treści stopki
PORóWNANIA PRODUKTóW

Nagłówki i stopki w plikach PDF: porównanie IronPDF i iTextSharp

Full Comparison

Looking for a detailed feature-by-feature breakdown? See how IronPDF stacks up against Itext on pricing, HTML support, and licensing.

View Full Comparison

IronPDF upraszcza tworzenie nagłówków i stopek w plikach PDF dzięki konfiguracji opartej na właściwościach i natywnej obsłudze HTML, podczas gdy iTextSharp wymaga implementacji PdfPageEventHelper z ręcznymi obliczeniami współrzędnych w celu precyzyjnego pozycjonowania.

Podczas tworzenia profesjonalnych dokumentów PDF — raportów biznesowych, faktur, dokumentacji technicznej — spójne nagłówki i stopki świadczą o jakości i wzmacniają wizerunek marki. Programiści, którzy pracowali z iTextSharp, znają to wyzwanie: dodawanie nagłówków i stopek oznacza pisanie procedur obsługi zdarzeń strony, obliczanie współrzędnych i zarządzanie czcionkami na niskim poziomie. IronPDF stosuje zasadniczo inne podejście, pozwalając opisać to, co chcesz, zamiast określać każdy piksel. W niniejszym przewodniku omówiono obie biblioteki, aby umożliwić podjęcie świadomej decyzji dotyczącej kolejnego projektu.

Jak zainstalować IronPDF?

Zanim przejdziemy do porównań, oto jak dodać IronPDF do projektu .NET 10. Użyj interfejsu CLI platformy .NET lub konsoli menedżera pakietów NuGet w programie Visual Studio:

dotnet add package IronPdf
# Or in the NuGet Package Manager Console:
# Install-Package IronPdf
dotnet add package IronPdf
# Or in the NuGet Package Manager Console:
# Install-Package IronPdf
SHELL

Po instalacji dodaj jednorazowe wywołanie klucza licencyjnego podczas uruchamiania aplikacji:

IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY-HERE"
$vbLabelText   $csharpLabel

Pakiet IronPDF NuGet jest przeznaczony dla platformy .NET 8+ i zawiera wbudowany silnik Chromium, dzięki czemu nie są wymagane żadne dodatkowe zależności środowiskowe. Dostępna jest bezpłatna licencja próbna, dzięki czemu można przetestować IronPDF w swoim środowisku przed podjęciem ostatecznej decyzji.

Jakie wyzwania wiążą się z implementacją nagłówków i stopek w iTextSharp?

Praca z iTextSharp wymaga zaimplementowania klasy PdfPageEventHelper oraz nadpisania metody OnEndPage w celu dodania nagłówków i stopek. Podejście to obejmuje bezpośrednią manipulację obiektem PdfContentByte oraz precyzyjne obliczenia współrzędnych. W przeciwieństwie do nowoczesnych rozwiązań do konwersji HTML na PDF, architektura iTextSharp oparta na zdarzeniach wymaga dogłębnego zrozumienia struktury plików PDF i układów współrzędnych.

Układ współrzędnych zaczyna się od lewego dolnego rogu strony, co jest sprzeczne z tym, jak większość programistów postrzega układy stron. Jest to bezpośrednia konsekwencja sposobu, w jaki specyfikacja PDF definiuje przestrzeń współrzędnych strony. Za każdym razem, gdy zmienia się rozmiar strony — na przykład przy przejściu z formatu A4 na Letter — konieczne jest ponowne obliczenie każdej wartości współrzędnych. Dodanie podkreślenia pod nagłówkiem, wyśrodkowanie tekstu lub wyrównanie stopki do prawego marginesu wymaga podania konkretnych wartości liczbowych.

public class HeaderFooterEvent : PdfPageEventHelper
{
    private readonly Font headerFont = new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD);
    private readonly Font footerFont = new Font(Font.FontFamily.HELVETICA, 10);

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        PdfContentByte cb = writer.DirectContent;

        // Add header text -- requires precise Y coordinate calculation
        float headerY = document.PageSize.Height - 30;
        ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER,
            new Phrase("Company Report", headerFont),
            document.PageSize.Width / 2, headerY, 0);

        // Draw underline manually
        cb.MoveTo(40, headerY - 5);
        cb.LineTo(document.PageSize.Width - 40, headerY - 5);
        cb.Stroke();

        // Add footer with page number
        string footerText = $"Page {writer.PageNumber}";
        ColumnText.ShowTextAligned(cb, Element.ALIGN_RIGHT,
            new Phrase(footerText, footerFont),
            document.PageSize.Width - 40, 30, 0);

        // Add date on left side
        ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT,
            new Phrase(DateTime.Now.ToString("MM/dd/yyyy"), footerFont),
            40, 30, 0);
    }
}

// Usage
PdfWriter writer = PdfWriter.GetInstance(document, stream);
writer.PageEvent = new HeaderFooterEvent();
public class HeaderFooterEvent : PdfPageEventHelper
{
    private readonly Font headerFont = new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD);
    private readonly Font footerFont = new Font(Font.FontFamily.HELVETICA, 10);

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        PdfContentByte cb = writer.DirectContent;

        // Add header text -- requires precise Y coordinate calculation
        float headerY = document.PageSize.Height - 30;
        ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER,
            new Phrase("Company Report", headerFont),
            document.PageSize.Width / 2, headerY, 0);

        // Draw underline manually
        cb.MoveTo(40, headerY - 5);
        cb.LineTo(document.PageSize.Width - 40, headerY - 5);
        cb.Stroke();

        // Add footer with page number
        string footerText = $"Page {writer.PageNumber}";
        ColumnText.ShowTextAligned(cb, Element.ALIGN_RIGHT,
            new Phrase(footerText, footerFont),
            document.PageSize.Width - 40, 30, 0);

        // Add date on left side
        ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT,
            new Phrase(DateTime.Now.ToString("MM/dd/yyyy"), footerFont),
            40, 30, 0);
    }
}

// Usage
PdfWriter writer = PdfWriter.GetInstance(document, stream);
writer.PageEvent = new HeaderFooterEvent();
Imports iTextSharp.text
Imports iTextSharp.text.pdf

Public Class HeaderFooterEvent
    Inherits PdfPageEventHelper

    Private ReadOnly headerFont As Font = New Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)
    Private ReadOnly footerFont As Font = New Font(Font.FontFamily.HELVETICA, 10)

    Public Overrides Sub OnEndPage(writer As PdfWriter, document As Document)
        Dim cb As PdfContentByte = writer.DirectContent

        ' Add header text -- requires precise Y coordinate calculation
        Dim headerY As Single = document.PageSize.Height - 30
        ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, 
            New Phrase("Company Report", headerFont), 
            document.PageSize.Width / 2, headerY, 0)

        ' Draw underline manually
        cb.MoveTo(40, headerY - 5)
        cb.LineTo(document.PageSize.Width - 40, headerY - 5)
        cb.Stroke()

        ' Add footer with page number
        Dim footerText As String = $"Page {writer.PageNumber}"
        ColumnText.ShowTextAligned(cb, Element.ALIGN_RIGHT, 
            New Phrase(footerText, footerFont), 
            document.PageSize.Width - 40, 30, 0)

        ' Add date on left side
        ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT, 
            New Phrase(DateTime.Now.ToString("MM/dd/yyyy"), footerFont), 
            40, 30, 0)
    End Sub
End Class

' Usage
Dim writer As PdfWriter = PdfWriter.GetInstance(document, stream)
writer.PageEvent = New HeaderFooterEvent()
$vbLabelText   $csharpLabel

To ręczne pozycjonowanie staje się bardziej skomplikowane w przypadku różnych orientacji stron, niestandardowych rozmiarów papieru lub różnych wymagań dotyczących marginesów. W przypadku systemów produkcyjnych wymagających zgodności z PDF/A lub podpisów cyfrowych podejście ręczne powoduje znaczne obciążenie związane z utrzymaniem.

Jak wygląda wynik z podstawowymi nagłówkami?

Dokument PDF przedstawiający raport firmy z nagłówkiem zawierającym tytuł oraz stopką z numeracją stron, ilustrujący podstawowe zastosowanie nagłówków i stopek podczas generowania plików PDF

Powyższy kod pokazuje, jak wygląda ta ręczna praca — trzeba obliczyć dokładne współrzędne, osobno zarządzać czcionkami i zająć się renderowaniem za pomocą DirectContent. Każda zmiana projektu oznacza edycję stałych liczbowych rozrzuconych po całym procedurze obsługi zdarzeń.

Dlaczego układ oparty na współrzędnych powoduje problemy z konserwacją?

Kiedy pojawia się zmiana w projekcie — przesunięcie logo, dostosowanie rozmiaru czcionki, przesunięcie daty do środka — programista musi prześledzić przesunięcia pikseli, aby zrozumieć, co należy zmienić. Nie ma warstwy wizualnej; sam kod jest jedyną specyfikacją układu. To sprawia, że przekazywanie zadań między programistami jest podatne na błędy i wydłuża czas potrzebny na wprowadzenie nawet drobnych zmian wizualnych.

W jaki sposób IronPDF ułatwia tworzenie nagłówków i stopek?

IronPDF zmienia proces tworzenia nagłówków i stopek dzięki intuicyjnemu API. Zamiast wdrażać procedury obsługi zdarzeń, nagłówki i stopki konfiguruje się poprzez proste ustawienia właściwości w ChromePdfRenderer. Takie podejście jest zgodne z nowoczesnymi praktykami programistycznymi w środowisku .NET i znacznie skraca czas potrzebny na opanowanie nowych umiejętności.

using IronPdf;

var renderer = new ChromePdfRenderer();

// Configure text header with multiple properties
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    CenterText = "Company Report",
    LeftText = "CONFIDENTIAL",
    RightText = DateTime.Now.ToString("MMMM yyyy"),
    DrawDividerLine = true,
    FontSize = 12,
    FontFamily = "Arial",
    Spacing = 5
};

// Configure text footer with dynamic placeholders
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    LeftText = "{date} {time}",
    CenterText = "© 2024 Company Name",
    RightText = "Page {page} of {total-pages}",
    DrawDividerLine = true,
    FontSize = 10,
    Spacing = 10
};

// Set margins to ensure proper spacing
renderer.RenderingOptions.MarginTop = 30;
renderer.RenderingOptions.MarginBottom = 25;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

// Configure text header with multiple properties
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    CenterText = "Company Report",
    LeftText = "CONFIDENTIAL",
    RightText = DateTime.Now.ToString("MMMM yyyy"),
    DrawDividerLine = true,
    FontSize = 12,
    FontFamily = "Arial",
    Spacing = 5
};

// Configure text footer with dynamic placeholders
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    LeftText = "{date} {time}",
    CenterText = "© 2024 Company Name",
    RightText = "Page {page} of {total-pages}",
    DrawDividerLine = true,
    FontSize = 10,
    Spacing = 10
};

// Set margins to ensure proper spacing
renderer.RenderingOptions.MarginTop = 30;
renderer.RenderingOptions.MarginBottom = 25;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

' Configure text header with multiple properties
renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
    .CenterText = "Company Report",
    .LeftText = "CONFIDENTIAL",
    .RightText = DateTime.Now.ToString("MMMM yyyy"),
    .DrawDividerLine = True,
    .FontSize = 12,
    .FontFamily = "Arial",
    .Spacing = 5
}

' Configure text footer with dynamic placeholders
renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
    .LeftText = "{date} {time}",
    .CenterText = "© 2024 Company Name",
    .RightText = "Page {page} of {total-pages}",
    .DrawDividerLine = True,
    .FontSize = 10,
    .Spacing = 10
}

' Set margins to ensure proper spacing
renderer.RenderingOptions.MarginTop = 30
renderer.RenderingOptions.MarginBottom = 25

Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("report.pdf")
$vbLabelText   $csharpLabel

Opcje renderowania w IronPDF zapewniają precyzyjną kontrolę nad generowaniem plików PDF, zachowując jednocześnie czytelność kodu. To podejście oparte na właściwościach ułatwia utrzymywanie i modyfikowanie nagłówków oraz stopek bez konieczności zagłębiania się w niskopoziomową manipulację plikami PDF.

W jaki sposób IronPDF radzi sobie z profesjonalnym formatowaniem?

Dwustronicowy dokument PDF pokazujący możliwości IronPDF w zakresie nagłówków i stopek z brandingiem firmy, numerami stron i znacznikami czasu na wielu stronach o spójnym formatowaniu

Różnica jest od razu widoczna — IronPDF automatycznie obsługuje pozycjonowanie, marginesy i renderowanie, zapewniając jednocześnie wbudowane symbole zastępcze dla treści dynamicznych. Silnik renderujący biblioteki w przeglądarce Chrome zapewnia idealną jakość obrazu, która odpowiada podglądowi HTML.

Które funkcje mają największe znaczenie dla systemów produkcyjnych?

Porównanie funkcji: iTextSharp vs IronPDF w zakresie nagłówków i stopek
Funkcja iTextSharp IronPDF
Metoda realizacji Klasa PdfPageEventHelper Właściwości RenderingOptions
Złożoność kodu Ręczne obliczenia współrzędnych Proste przypisywanie właściwości
Numery stron Ręczne śledzenie za pomocą writer.PageNumber Wbudowany symbol zastępczy {page}
Obsługa HTML Ograniczone, wymaga XMLWorker Wbudowana obsługa nagłówków HTML
Zarządzanie marginesami Obliczenia ręczne Automatyczne dostosowanie
Treści dynamiczne Wymagana niestandardowa implementacja Wstępnie zdefiniowane symbole zastępcze
Pierwsza strona inna Złożona logika warunkowa Właściwość FirstPageNumber
Krzywa uczenia się Steep Stopniowe

Jak dodać nagłówki i stopki z numerami stron?

Numeracja stron jest standardowym wymogiem dla dokumentów PDF. W przypadku iTextSharp należy ręcznie śledzić numer bieżącej strony i całkowitą liczbę stron, co często wymaga dwuetapowego podejścia w celu uzyskania dokładnej liczby stron:

// iTextSharp approach with complete page numbering
public class CompleteHeaderFooterEvent : PdfPageEventHelper
{
    private readonly PdfTemplate totalPageCount;
    private readonly Font normalFont = new Font(Font.FontFamily.HELVETICA, 10);

    public CompleteHeaderFooterEvent(PdfWriter writer)
    {
        // Create placeholder for total page count
        totalPageCount = writer.DirectContent.CreateTemplate(30, 16);
    }

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        PdfPTable footerTable = new PdfPTable(3);
        footerTable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin;
        footerTable.SetWidths(new float[] { 1, 1, 1 });

        PdfPCell leftCell = new PdfPCell(new Phrase(DateTime.Now.ToString("dd/MM/yyyy"), normalFont));
        leftCell.Border = Rectangle.NO_BORDER;
        leftCell.HorizontalAlignment = Element.ALIGN_LEFT;

        PdfPCell centerCell = new PdfPCell(new Phrase("Confidential", normalFont));
        centerCell.Border = Rectangle.NO_BORDER;
        centerCell.HorizontalAlignment = Element.ALIGN_CENTER;

        PdfPCell rightCell = new PdfPCell();
        rightCell.Border = Rectangle.NO_BORDER;
        rightCell.HorizontalAlignment = Element.ALIGN_RIGHT;

        Chunk pageNum = new Chunk($"Page {writer.PageNumber} of ", normalFont);
        rightCell.AddElement(pageNum);
        rightCell.AddElement(Image.GetInstance(totalPageCount));

        footerTable.AddCell(leftCell);
        footerTable.AddCell(centerCell);
        footerTable.AddCell(rightCell);

        footerTable.WriteSelectedRows(0, -1, document.LeftMargin,
            document.PageSize.GetBottom(document.BottomMargin), writer.DirectContent);
    }

    public override void OnCloseDocument(PdfWriter writer, Document document)
    {
        ColumnText.ShowTextAligned(totalPageCount, Element.ALIGN_LEFT,
            new Phrase(writer.PageNumber.ToString(), normalFont), 0, 0, 0);
    }
}
// iTextSharp approach with complete page numbering
public class CompleteHeaderFooterEvent : PdfPageEventHelper
{
    private readonly PdfTemplate totalPageCount;
    private readonly Font normalFont = new Font(Font.FontFamily.HELVETICA, 10);

    public CompleteHeaderFooterEvent(PdfWriter writer)
    {
        // Create placeholder for total page count
        totalPageCount = writer.DirectContent.CreateTemplate(30, 16);
    }

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        PdfPTable footerTable = new PdfPTable(3);
        footerTable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin;
        footerTable.SetWidths(new float[] { 1, 1, 1 });

        PdfPCell leftCell = new PdfPCell(new Phrase(DateTime.Now.ToString("dd/MM/yyyy"), normalFont));
        leftCell.Border = Rectangle.NO_BORDER;
        leftCell.HorizontalAlignment = Element.ALIGN_LEFT;

        PdfPCell centerCell = new PdfPCell(new Phrase("Confidential", normalFont));
        centerCell.Border = Rectangle.NO_BORDER;
        centerCell.HorizontalAlignment = Element.ALIGN_CENTER;

        PdfPCell rightCell = new PdfPCell();
        rightCell.Border = Rectangle.NO_BORDER;
        rightCell.HorizontalAlignment = Element.ALIGN_RIGHT;

        Chunk pageNum = new Chunk($"Page {writer.PageNumber} of ", normalFont);
        rightCell.AddElement(pageNum);
        rightCell.AddElement(Image.GetInstance(totalPageCount));

        footerTable.AddCell(leftCell);
        footerTable.AddCell(centerCell);
        footerTable.AddCell(rightCell);

        footerTable.WriteSelectedRows(0, -1, document.LeftMargin,
            document.PageSize.GetBottom(document.BottomMargin), writer.DirectContent);
    }

    public override void OnCloseDocument(PdfWriter writer, Document document)
    {
        ColumnText.ShowTextAligned(totalPageCount, Element.ALIGN_LEFT,
            new Phrase(writer.PageNumber.ToString(), normalFont), 0, 0, 0);
    }
}
Imports System
Imports iTextSharp.text
Imports iTextSharp.text.pdf

' iTextSharp approach with complete page numbering
Public Class CompleteHeaderFooterEvent
    Inherits PdfPageEventHelper

    Private ReadOnly totalPageCount As PdfTemplate
    Private ReadOnly normalFont As Font = New Font(Font.FontFamily.HELVETICA, 10)

    Public Sub New(writer As PdfWriter)
        ' Create placeholder for total page count
        totalPageCount = writer.DirectContent.CreateTemplate(30, 16)
    End Sub

    Public Overrides Sub OnEndPage(writer As PdfWriter, document As Document)
        Dim footerTable As New PdfPTable(3)
        footerTable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin
        footerTable.SetWidths(New Single() {1, 1, 1})

        Dim leftCell As New PdfPCell(New Phrase(DateTime.Now.ToString("dd/MM/yyyy"), normalFont))
        leftCell.Border = Rectangle.NO_BORDER
        leftCell.HorizontalAlignment = Element.ALIGN_LEFT

        Dim centerCell As New PdfPCell(New Phrase("Confidential", normalFont))
        centerCell.Border = Rectangle.NO_BORDER
        centerCell.HorizontalAlignment = Element.ALIGN_CENTER

        Dim rightCell As New PdfPCell()
        rightCell.Border = Rectangle.NO_BORDER
        rightCell.HorizontalAlignment = Element.ALIGN_RIGHT

        Dim pageNum As New Chunk($"Page {writer.PageNumber} of ", normalFont)
        rightCell.AddElement(pageNum)
        rightCell.AddElement(Image.GetInstance(totalPageCount))

        footerTable.AddCell(leftCell)
        footerTable.AddCell(centerCell)
        footerTable.AddCell(rightCell)

        footerTable.WriteSelectedRows(0, -1, document.LeftMargin, document.PageSize.GetBottom(document.BottomMargin), writer.DirectContent)
    End Sub

    Public Overrides Sub OnCloseDocument(writer As PdfWriter, document As Document)
        ColumnText.ShowTextAligned(totalPageCount, Element.ALIGN_LEFT, New Phrase(writer.PageNumber.ToString(), normalFont), 0, 0, 0)
    End Sub
End Class
$vbLabelText   $csharpLabel

Ten wzorzec wymaga utworzenia obiektu szablonu PDF jako symbolu zastępczego, a następnie uzupełnienia całkowitej liczby stron po zamknięciu dokumentu. Charakter operacji dwuetapowej nie jest oczywisty dla osób niezaznajomionych z wewnętrznym działaniem iTextSharp, a popełnienie błędu powoduje nieprawidłową liczbę stron w końcowym pliku PDF.

Dlaczego podejście IronPDF jest łatwiejsze w utrzymaniu?

IronPDF obsługuje numerację stron dzięki wbudowanym symbolom zastępczym i automatycznej obsłudze numerów stron:

using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    LeftText = "{date} {time}",
    CenterText = "Confidential -- Internal Use Only",
    RightText = "Page {page} of {total-pages}",
    DrawDividerLine = true,
    FontSize = 10,
    FontFamily = "Calibri",
    Spacing = 8
};

// Skip numbering on cover page
renderer.RenderingOptions.FirstPageNumber = 0;

renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginTop = 30;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    LeftText = "{date} {time}",
    CenterText = "Confidential -- Internal Use Only",
    RightText = "Page {page} of {total-pages}",
    DrawDividerLine = true,
    FontSize = 10,
    FontFamily = "Calibri",
    Spacing = 8
};

// Skip numbering on cover page
renderer.RenderingOptions.FirstPageNumber = 0;

renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginTop = 30;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
    .LeftText = "{date} {time}",
    .CenterText = "Confidential -- Internal Use Only",
    .RightText = "Page {page} of {total-pages}",
    .DrawDividerLine = True,
    .FontSize = 10,
    .FontFamily = "Calibri",
    .Spacing = 8
}

' Skip numbering on cover page
renderer.RenderingOptions.FirstPageNumber = 0

renderer.RenderingOptions.MarginBottom = 25
renderer.RenderingOptions.MarginTop = 30

Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
$vbLabelText   $csharpLabel

Wbudowane symbole zastępcze obsługują {page}, {total-pages}, {date}, {time}, {html-title}, {pdf-title} oraz {url}. Nie ma potrzeby stosowania skomplikowanej obróbki końcowej ani renderowania dwuetapowego. Biblioteka oblicza wewnętrzną liczbę stron i automatycznie wstawia ją w każdym miejscu zastępczym.

Czy można tworzyć nagłówki HTML z dynamiczną treścią?

W przypadku układów zawierających logo firmowe, stylizowaną typografię lub uporządkowane tabele nagłówki HTML zapewniają znacznie większą elastyczność niż nagłówki tekstowe. IronPDF wyróżnia się tutaj dzięki natywnej obsłudze nagłówków i stopek HTML:

using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px 0;'>
            <img src='logo.png' style='height: 40px;'>
            <div style='text-align: center;'>
                <h2 style='margin: 0; color: #2c3e50;'>Annual Report 2024</h2>
                <p style='margin: 0; font-size: 12px; color: #7f8c8d;'>Financial Performance &amp; Strategic Overview</p>
            </div>
            <div style='text-align: right; font-size: 11px; color: #95a5a6;'>
                Document ID: AR-2024-001<br>
                Classification: Public
            </div>
        </div>",
    MaxHeight = 80,
    DrawDividerLine = true,
    BaseUrl = new Uri(System.IO.Path.GetFullPath("assets/")).AbsoluteUri
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <table style='width: 100%; font-size: 10px; color: #34495e;'>
            <tr>
                <td style='width: 33%; text-align: left;'>Generated: {date} at {time}</td>
                <td style='width: 34%; text-align: center;'>Page {page} of {total-pages}</td>
                <td style='width: 33%; text-align: right;'>Annual Report 2024</td>
            </tr>
        </table>",
    MaxHeight = 30,
    DrawDividerLine = true
};

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("annual-report.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px 0;'>
            <img src='logo.png' style='height: 40px;'>
            <div style='text-align: center;'>
                <h2 style='margin: 0; color: #2c3e50;'>Annual Report 2024</h2>
                <p style='margin: 0; font-size: 12px; color: #7f8c8d;'>Financial Performance &amp; Strategic Overview</p>
            </div>
            <div style='text-align: right; font-size: 11px; color: #95a5a6;'>
                Document ID: AR-2024-001<br>
                Classification: Public
            </div>
        </div>",
    MaxHeight = 80,
    DrawDividerLine = true,
    BaseUrl = new Uri(System.IO.Path.GetFullPath("assets/")).AbsoluteUri
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <table style='width: 100%; font-size: 10px; color: #34495e;'>
            <tr>
                <td style='width: 33%; text-align: left;'>Generated: {date} at {time}</td>
                <td style='width: 34%; text-align: center;'>Page {page} of {total-pages}</td>
                <td style='width: 33%; text-align: right;'>Annual Report 2024</td>
            </tr>
        </table>",
    MaxHeight = 30,
    DrawDividerLine = true
};

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("annual-report.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
    .HtmlFragment = "
        <div style='width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px 0;'>
            <img src='logo.png' style='height: 40px;'>
            <div style='text-align: center;'>
                <h2 style='margin: 0; color: #2c3e50;'>Annual Report 2024</h2>
                <p style='margin: 0; font-size: 12px; color: #7f8c8d;'>Financial Performance &amp; Strategic Overview</p>
            </div>
            <div style='text-align: right; font-size: 11px; color: #95a5a6;'>
                Document ID: AR-2024-001<br>
                Classification: Public
            </div>
        </div>",
    .MaxHeight = 80,
    .DrawDividerLine = True,
    .BaseUrl = New Uri(System.IO.Path.GetFullPath("assets/")).AbsoluteUri
}

renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
    .HtmlFragment = "
        <table style='width: 100%; font-size: 10px; color: #34495e;'>
            <tr>
                <td style='width: 33%; text-align: left;'>Generated: {date} at {time}</td>
                <td style='width: 34%; text-align: center;'>Page {page} of {total-pages}</td>
                <td style='width: 33%; text-align: right;'>Annual Report 2024</td>
            </tr>
        </table>",
    .MaxHeight = 30,
    .DrawDividerLine = True
}

Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("annual-report.pdf")
$vbLabelText   $csharpLabel

Jak w praktyce renderują się złożone nagłówki?

Dokument PDF z profesjonalnym nagłówkiem zawierającym logo firmy i branding raportu rocznego, demonstrujący zaawansowane możliwości renderowania nagłówków HTML przez IronPDF przy zachowaniu spójnego formatowania wielostronicowego

W przypadku iTextSharp uzyskanie nagłówków HTML wymaga dodania rozszerzenia XMLWorker i napisania złożonego kodu parsującego. Ograniczona obsługa CSS przez bibliotekę utrudnia tworzenie nowoczesnych układów, które działają niezawodnie na różnych formatach papieru. Obrazy, układy elastyczne i czcionki internetowe wymagają rozwiązań, które znacznie zwiększają złożoność kodu.

W jaki sposób inaczej traktuje się nagłówki na pierwszej stronie?

Wiele profesjonalnych dokumentów wymaga innego nagłówka na stronie tytułowej — dużego logo na stronie tytułowej, a następnie kompaktowego nagłówka na kolejnych stronach. IronPDF obsługuje ten wzorzec poprzez warunkowy kod HTML i CSS:

using IronPdf;

var renderer = new ChromePdfRenderer();

string firstPageHeader = @"
    <div style='text-align: center; padding: 20px 0;'>
        <img src='logo-large.png' style='height: 80px; margin-bottom: 10px;'>
        <h1 style='margin: 0; color: #2c3e50;'>2024 Annual Report</h1>
        <h3 style='margin: 5px 0; color: #7f8c8d;'>Fiscal Year Ending December 31, 2024</h3>
    </div>";

string subsequentPageHeader = @"
    <div style='display: flex; justify-content: space-between; align-items: center;'>
        <img src='logo-small.png' style='height: 30px;'>
        <span>Annual Report 2024</span>
        <span>Page {page}</span>
    </div>";

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = $@"
        <style>
            .first-page {{ display: none; }}
            .other-pages {{ display: block; }}
            @page:first {{
                .first-page {{ display: block; }}
                .other-pages {{ display: none; }}
            }}
        </style>
        <div class='first-page'>{firstPageHeader}</div>
        <div class='other-pages'>{subsequentPageHeader}</div>",
    MaxHeight = 100
};

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report-with-cover.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

string firstPageHeader = @"
    <div style='text-align: center; padding: 20px 0;'>
        <img src='logo-large.png' style='height: 80px; margin-bottom: 10px;'>
        <h1 style='margin: 0; color: #2c3e50;'>2024 Annual Report</h1>
        <h3 style='margin: 5px 0; color: #7f8c8d;'>Fiscal Year Ending December 31, 2024</h3>
    </div>";

string subsequentPageHeader = @"
    <div style='display: flex; justify-content: space-between; align-items: center;'>
        <img src='logo-small.png' style='height: 30px;'>
        <span>Annual Report 2024</span>
        <span>Page {page}</span>
    </div>";

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = $@"
        <style>
            .first-page {{ display: none; }}
            .other-pages {{ display: block; }}
            @page:first {{
                .first-page {{ display: block; }}
                .other-pages {{ display: none; }}
            }}
        </style>
        <div class='first-page'>{firstPageHeader}</div>
        <div class='other-pages'>{subsequentPageHeader}</div>",
    MaxHeight = 100
};

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report-with-cover.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

Dim firstPageHeader As String = "
    <div style='text-align: center; padding: 20px 0;'>
        <img src='logo-large.png' style='height: 80px; margin-bottom: 10px;'>
        <h1 style='margin: 0; color: #2c3e50;'>2024 Annual Report</h1>
        <h3 style='margin: 5px 0; color: #7f8c8d;'>Fiscal Year Ending December 31, 2024</h3>
    </div>"

Dim subsequentPageHeader As String = "
    <div style='display: flex; justify-content: space-between; align-items: center;'>
        <img src='logo-small.png' style='height: 30px;'>
        <span>Annual Report 2024</span>
        <span>Page {page}</span>
    </div>"

renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
    .HtmlFragment = $"
        <style>
            .first-page {{ display: none; }}
            .other-pages {{ display: block; }}
            @page:first {{
                .first-page {{ display: block; }}
                .other-pages {{ display: none; }}
            }}
        </style>
        <div class='first-page'>{firstPageHeader}</div>
        <div class='other-pages'>{subsequentPageHeader}</div>",
    .MaxHeight = 100
}

Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("report-with-cover.pdf")
$vbLabelText   $csharpLabel

Takie podejście pozwala zachować definicję nagłówka w jednym miejscu, co ułatwia jednoczesną aktualizację zarówno okładki, jak i nagłówków wewnątrz publikacji. Można również zapoznać się z asynchronicznym renderowaniem plików PDF w scenariuszach wymagających dużej przepustowości.

Które podejście zapewnia lepszą wydajność i elastyczność?

Wydajność ma kluczowe znaczenie podczas generowania dużych dokumentów lub jednoczesnego przetwarzania wielu plików PDF. Silnik renderujący IronPDF dla przeglądarki Chrome zapewnia kilka korzyści w przypadku obciążeń produkcyjnych:

  1. Wydajność renderowania: IronPDF buforuje renderowane nagłówki i stopki, poprawiając przepustowość w przypadku dokumentów wielostronicowych
  2. Efektywność pamięci: Biblioteka automatycznie zarządza pamięcią, unikając wycieków, które mogą wystąpić przy ręcznej manipulacji PdfContentByte
  3. Przetwarzanie równoległe: Obsługa operacji asynchronicznych umożliwia wydajne generowanie partii przy użyciu wzorców Task.WhenAll
using IronPdf;

public async Task GenerateReportsAsync(List<ReportData> reports)
{
    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.TextHeader = new TextHeaderFooter
    {
        CenterText = "Monthly Report",
        DrawDividerLine = true
    };

    renderer.RenderingOptions.TextFooter = new TextHeaderFooter
    {
        RightText = "Page {page} of {total-pages}",
        DrawDividerLine = true
    };

    // Disable JavaScript if not required for faster rendering
    renderer.RenderingOptions.EnableJavaScript = false;
    renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

    var tasks = reports.Select(async report =>
    {
        string html = await GenerateHtmlAsync(report);
        return await renderer.RenderHtmlAsPdfAsync(html);
    });

    PdfDocument[] pdfs = await Task.WhenAll(tasks);
}
using IronPdf;

public async Task GenerateReportsAsync(List<ReportData> reports)
{
    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.TextHeader = new TextHeaderFooter
    {
        CenterText = "Monthly Report",
        DrawDividerLine = true
    };

    renderer.RenderingOptions.TextFooter = new TextHeaderFooter
    {
        RightText = "Page {page} of {total-pages}",
        DrawDividerLine = true
    };

    // Disable JavaScript if not required for faster rendering
    renderer.RenderingOptions.EnableJavaScript = false;
    renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

    var tasks = reports.Select(async report =>
    {
        string html = await GenerateHtmlAsync(report);
        return await renderer.RenderHtmlAsPdfAsync(html);
    });

    PdfDocument[] pdfs = await Task.WhenAll(tasks);
}
Imports IronPdf

Public Async Function GenerateReportsAsync(reports As List(Of ReportData)) As Task
    Dim renderer As New ChromePdfRenderer()

    renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
        .CenterText = "Monthly Report",
        .DrawDividerLine = True
    }

    renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
        .RightText = "Page {page} of {total-pages}",
        .DrawDividerLine = True
    }

    ' Disable JavaScript if not required for faster rendering
    renderer.RenderingOptions.EnableJavaScript = False
    renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print

    Dim tasks = reports.Select(Async Function(report)
                                   Dim html As String = Await GenerateHtmlAsync(report)
                                   Return Await renderer.RenderHtmlAsPdfAsync(html)
                               End Function)

    Dim pdfs As PdfDocument() = Await Task.WhenAll(tasks)
End Function
$vbLabelText   $csharpLabel

A co z kwestiami licencyjnymi dotyczącymi użytkowania produkcyjnego?

Model licencyjny IronPDF oferuje warunki przyjazne dla użytkowników komercyjnych w porównaniu z licencją AGPL iTextSharp, która wymaga udostępnienia kodu aplikacji na zasadach open source, chyba że zakupisz oddzielną komercyjną licencję iText. W przypadku systemów produkcyjnych IronPDF zapewnia:

  • Licencje wieczyste bez opłat cyklicznych
  • Obsługa wdrażania w systemach Windows, Linux, macOS i Azure
  • Wsparcie dla licencjonowanych użytkowników
  • Brak znaków wodnych w wydrukach produkcyjnych

Jak stroma jest krzywa uczenia się dla zespołów?

Dla programistów zaznajomionych z systemem zdarzeń stron iTextSharp istnieje pewien okres adaptacji, ale dokumentacja i przykłady IronPDF sprawiają, że jest to łatwe do opanowania. Możliwość użycia CSS do stylizacji i HTML do tworzenia układu otwiera możliwości, które w iTextSharp wymagałyby rozbudowanego kodu niestandardowego. Dokumentacja zawiera:

Czym różnią się obliczenia marginesów i odstępów?

Professional dokument layout requires precise margin control. IronPDF upraszcza to dzięki pomiarom w milimetrach — naturalnej jednostce dla układów drukarskich:

using IronPdf;

var renderer = new ChromePdfRenderer();

// Set margins in millimeters
renderer.RenderingOptions.MarginTop = 25.4;    // 1 inch
renderer.RenderingOptions.MarginBottom = 25.4;
renderer.RenderingOptions.MarginLeft = 19.05;  // 0.75 inch
renderer.RenderingOptions.MarginRight = 19.05;

renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    CenterText = "Internal Report",
    DrawDividerLine = true,
    Spacing = 5
};

// Use print CSS media type for accurate page layout
// See MDN reference: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/print
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("margin-report.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

// Set margins in millimeters
renderer.RenderingOptions.MarginTop = 25.4;    // 1 inch
renderer.RenderingOptions.MarginBottom = 25.4;
renderer.RenderingOptions.MarginLeft = 19.05;  // 0.75 inch
renderer.RenderingOptions.MarginRight = 19.05;

renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    CenterText = "Internal Report",
    DrawDividerLine = true,
    Spacing = 5
};

// Use print CSS media type for accurate page layout
// See MDN reference: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/print
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("margin-report.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

' Set margins in millimeters
renderer.RenderingOptions.MarginTop = 25.4 ' 1 inch
renderer.RenderingOptions.MarginBottom = 25.4
renderer.RenderingOptions.MarginLeft = 19.05 ' 0.75 inch
renderer.RenderingOptions.MarginRight = 19.05

renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
    .CenterText = "Internal Report",
    .DrawDividerLine = True,
    .Spacing = 5
}

' Use print CSS media type for accurate page layout
' See MDN reference: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/print
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print

Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("margin-report.pdf")
$vbLabelText   $csharpLabel

Porównaj to z podejściem opartym na współrzędnych stosowanym w iTextSharp, gdzie musisz obliczać pozycje względem granic strony i ręcznie sprawdzać, czy treść nie nakłada się na nagłówki lub stopki.

Jakie są Twoje kolejne kroki?

Dodawanie nagłówków i stopek do dokumentów PDF nie musi wiązać się ze skomplikowaną obsługą zdarzeń i obliczeniami współrzędnych. Podczas gdy podejście iTextSharp oferuje szczegółową kontrolę poprzez zdarzenia stron i bezpośrednią manipulację treścią, IronPDF zapewnia bardziej intuicyjne rozwiązanie z konfiguracją opartą na właściwościach i natywną obsługą HTML.

Wybór staje się oczywisty, gdy weźmie się pod uwagę szybkość tworzenia oprogramowania, łatwość konserwacji oraz prostotę tworzenia profesjonalnie wyglądających dokumentów. Podejście IronPDF do nagłówków i stopek stanowi przykład nowoczesnego tworzenia plików PDF — wydajnego, a jednocześnie przystępnego. Dla zespołów, które stawiają na czystą architekturę i łatwy w utrzymaniu kod, API IronPDF dobrze wpisuje się w praktyki programistyczne .NET.

Główne zalety dla systemów produkcyjnych obejmują:

  • Skrócony czas tworzenia oprogramowania: konfiguracja oparta na właściwościach a złożone procedury obsługi zdarzeń
  • Łatwiejsza konserwacja: HTML/CSS do tworzenia układów zamiast obliczeń współrzędnych
  • Zwiększona elastyczność: natywna obsługa responsywnych projektów i czcionek internetowych
  • Najwyższa wydajność: zoptymalizowane renderowanie z obsługą buforowania i przetwarzania równoległego
  • Professional wyniki: idealnie dopasowany do pikseli wynik zgodny z nowoczesnymi standardami internetowymi

Zacznij od zainstalowania IronPDF za pośrednictwem NuGet, a następnie skorzystaj z przewodnika szybkiego startu, aby w ciągu kilku minut stworzyć swój pierwszy nagłówek i stopkę. Kiedy będziesz gotowy do przejścia do środowiska produkcyjnego, zapoznaj się z opcjami licencyjnymi, aby znaleźć plan odpowiadający Twoim wymaganiom wdrożeniowym. Jeśli napotkasz jakiekolwiek trudności podczas integracji, zespół wsparcia technicznego służy pomocą.

Zwróć uwagęiTextSharp jest zarejestrowanym znakiem towarowym odpowiedniego właściciela. Ta strona nie jest powiązana z iTextSharp, nie jest przez nią promowana ani sponsorowana. Wszystkie nazwy produktów, logo i marki są własnością ich odpowiednich właścicieli. Porównania mają charakter wyłącznie informacyjny i odzwierciedlają informacje dostępne publicznie w momencie pisania.

Często Zadawane Pytania

Jakie są główne różnice między IronPDF a iTextSharp w zakresie dodawania nagłówków i stopek?

IronPDF wykorzystuje API oparte na właściwościach z natywną obsługą HTML, podczas gdy iTextSharp wymaga implementacji PdfPageEventHelper z ręcznymi obliczeniami współrzędnych. IronPDF zapewnia również wbudowane symbole zastępcze dla numerów stron, dat i adresów URL.

W jaki sposób IronPDF ułatwia dodawanie nagłówków stron?

IronPDF umożliwia konfigurację nagłówków za pomocą właściwości TextHeaderFooter lub HtmlHeaderFooter w ChromePdfRenderer.RenderingOptions, eliminując konieczność obsługi zdarzeń stron lub obliczania pozycji pikseli.

Czy w IronPDF można używać HTML do dostosowywania nagłówków?

Tak, IronPDF obsługuje nagłówki i stopki oparte na HTML poprzez klasę HtmlHeaderFooter, umożliwiając pełne stylizowanie CSS, obrazy oraz dynamiczne symbole zastępcze, takie jak {page} i {total-pages}.

Jakie są zalety korzystania z IronPDF do tworzenia raportów biznesowych?

IronPDF skraca czas wdrożenia dzięki konfiguracji opartej na właściwościach, obsługuje dynamiczne symbole zastępcze dla numerów stron i dat oraz renderuje nagłówki z pikselową dokładnością przy użyciu silnika Chromium.

Czy IronPDF obsługuje numerację stron w nagłówkach i stopkach?

Tak, IronPDF automatycznie obsługuje numerację stron za pomocą wbudowanych symboli zastępczych, takich jak {page} i {total-pages}, bez konieczności renderowania w dwóch etapach.

Jak IronPDF wypada na tle iTextSharp pod względem łatwości użytkowania?

IronPDF jest ogólnie łatwiejszy w użyciu, ponieważ zastępuje niskopoziomowe procedury obsługi zdarzeń oparte na współrzędnych deklaratywnym interfejsem API właściwości i obsługuje HTML/CSS do tworzenia układu.

Czy IronPDF obsługuje treści dynamiczne w nagłówkach?

Tak, IronPDF obsługuje treści dynamiczne poprzez wbudowane symbole zastępcze ({page}, {total-pages}, {date}, {time}, {html-title}, {url}) zarówno w nagłówkach tekstowych, jak i HTML.

Co sprawia, że IronPDF jest bardziej odpowiedni do projektów dokumentacyjnych?

Obsługa nagłówków HTML przez IronPDF sprawia, że idealnie nadaje się on do dokumentacji, w której ważna jest spójna stylistyka, branding firmy i łatwość aktualizacji. Zmiany wymagają edycji kodu HTML, a nie stałych współrzędnych numerycznych.

Czy mogę używać IronPDF do faktur z niestandardowymi nagłówkami?

Tak, IronPDF obsługuje niestandardowe nagłówki HTML z logo, formatowanym tekstem i polami dynamicznymi, dzięki czemu doskonale nadaje się do generowania faktur.

Curtis Chau
Autor tekstów technicznych

Curtis Chau posiada tytuł licencjata z informatyki (Uniwersytet Carleton) i specjalizuje się w front-endowym rozwoju, z ekspertką w Node.js, TypeScript, JavaScript i React. Pasjonuje się tworzeniem intuicyjnych i estetycznie przyjemnych interfejsów użytkownika, Curtis cieszy się pracą z nowoczesnymi frameworkami i tworzeniem dobrze zorganizowanych, atrakcyjnych wizualnie podrę...

Czytaj więcej

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie