using IronPdf;
// Disable local disk access or cross-origin requests
Installation.EnableWebSecurity = true;
// Instantiate Renderer
var renderer = new ChromePdfRenderer();
// Create a PDF from a HTML string using C#
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
// Export to a file or Stream
pdf.SaveAs("output.pdf");
// Advanced Example with HTML Assets
// Load external html assets: Images, CSS and JavaScript.
// An optional BasePath 'C:\site\assets\' is set as the file location to load assets from
var myAdvancedPdf = renderer.RenderHtmlAsPdf("<img src='icons/iron.png'>", @"C:\site\assets\");
myAdvancedPdf.SaveAs("html-with-assets.pdf");
Migracja z iText do IronPDF przenosi przepływ pracy PDF .NET z programistycznego API — budowanie Paragraph, Table i Cell obiektów w kodzie — do podejścia HTML-first z obsługą CSS3 i JavaScript. Ten przewodnik oferuje ścieżkę migracji krok po kroku usuwającą narażenie AGPL i potrzebę osobnego dodatku pdfHTML.
Dlaczego warto przejść z iText na IronPDF
Uwagi dotyczące licencji AGPL
iText (należący do iText Group / Apryse Group NV) ma cechy licencyjne, które zespoły komercyjne powinny rozważyć z góry:
AGPL Viral License: Jeśli używasz iText na podstawie jego licencji open-source w aplikacji internetowej, AGPL jest zazwyczaj interpretowane jako wymóg udostępnienia kodu źródłowego aplikacji każdemu, kto z nią współdziała poprzez sieć. Dla zamkniętego oprogramowania komercyjnego oznacza to zwykle zakup komercyjnej licencji.
Licencja komercyjna wyłącznie na subskrypcję: Licencja komercyjna iText jest sprzedawana jako roczna subskrypcja oparta na wolumenie przetwarzania PDF; Opcja wieczysta nie jest reklamowana na publicznej stronie z cenami (warunki OEM są dostępne tylko na zapytanie).
Koszt dodatku pdfHTML: HTML-do-PDF wymaga dodatku itext.pdfhtml (aktualnie 6.3.2), sprzedawanego oddzielnie nad podstawowym pakietem itext (aktualnie 9.6.0).
Kompleksowe audyty licencyjne: Wdrożenia enterprise stają przed złożonością licencyjną i ryzykiem audytu.
API programistyczno-pierwsze: Podstawowy iText tworzy PDF poprzez komponowanie Paragraph, Table i Cell obiektów w kodzie; pdfHTML pozwala na rozpoczęcie od HTML.
Zdefiniowany podzbiór CSS, brak JS w czasie renderowania: pdfHTML obsługuje zdefiniowany podzbiór CSS i nie wykonuje JavaScript podczas konwersji HTML na PDF (akcji formularzy PDF JS jest oddzielną, wspieraną funkcją).
Porównanie iText i IronPDF
Funkcja
iText 9 / iTextSharp 5.x
IronPDF
Licencja
AGPL (wiralna) lub komercyjna roczna subskrypcja
Opcja komercyjna, bezterminowa
HTML do PDF
Oddzielny dodatek itext.pdfhtml (6.3.2)
Wbudowany renderer Chromium
Obsługa CSS
Zdefiniowany podzbiór CSS w pdfHTML
Pełna obsługa CSS3, Flexbox, Grid
JavaScript podczas renderowania
pdfHTML nie uruchamia JS podczas HTML→PDF
Pełne wykonanie JS w czasie renderowania
Paradygmat API
Programowo (akapit, tabela, komórka)
Najpierw HTML, potem CSS
Krzywa uczenia się
Steep (układ współrzędnych PDF)
Przyjazne dla programistów stron internetowych
Ryzyko związane z oprogramowaniem open source
Aplikacje internetowe typu open source muszą być objęte licencją AGPL
Brak wymagań dotyczących wirusowości
Model cenowy
Roczna subskrypcja (oparta na wolumenie) lub na zamówienie OEM
Licencja wieczysta lub subskrypcja
Dla zespołów standaryzujących się na współczesnym .NET, podejście typu HTML-first w IronPDF bazuje na umiejętnościach programowania web, które zespół już posiada.
Ocena złożoności migracji
Szacowany nakład pracy według funkcji
Funkcja
Złożoność migracji
HTML do PDF
Bardzo niski
Łączenie plików PDF
Niski
Tekst i obrazy
Niski
Tabele
Medium
Nagłówki/stopki
Medium
Bezpieczeństwo/Szyfrowanie
Niski
Zmiana paradygmatu
Podstawową zmianą w tej migracji iText jest przejście od programowego tworzenia plików PDF do renderowania opartego na HTML:
Ta zmiana paradygmatu jest wyzwalająca: zamiast uczyć się modelu obiektowego iText, wykorzystujesz umiejętności HTML i CSS, które programiści stron internetowych już posiadają.
// NuGet: Install-Package itext7
using iText.Html2pdf;
using System.IO;
class Program
{
static void Main()
{
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
string outputPath = "output.pdf";
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
HtmlConverter.ConvertToPdf(html, fs);
}
}
}
// NuGet: Install-Package itext7
using iText.Html2pdf;
using System.IO;
class Program
{
static void Main()
{
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
string outputPath = "output.pdf";
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
HtmlConverter.ConvertToPdf(html, fs);
}
}
}
Imports iText.Html2pdf
Imports System.IO
Class Program
Shared Sub Main()
Dim html As String = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
Dim outputPath As String = "output.pdf"
Using fs As FileStream = New FileStream(outputPath, FileMode.Create)
HtmlConverter.ConvertToPdf(html, fs)
End Using
End Sub
End Class
$vbLabelText $csharpLabel
Po (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
$vbLabelText $csharpLabel
Podejście iText wymaga oddzielnego pakietu itext.pdfhtml (dodatku pdfHTML, aktualnie 6.3.2, sprzedawanego oddzielnie nad itext 9.6.0), tworzenia FileStream oraz otaczania wszystkiego w instrukcjach using dla właściwego usunięcia. Metoda HtmlConverter.ConvertToPdf() zapisuje bezpośrednio do strumienia.
Podejście IronPDF jest czystsze: twórz ChromePdfRenderer, wywołaj RenderHtmlAsPdf() z twoim łańcuchem HTML i wywołaj SaveAs() na wynikowym PdfDocument. Brak oddzielnych pakietów, brak zarządzania strumieniami oraz silnik renderujący Chromium zapewniają doskonałą obsługę CSS3 i JavaScript. Dodatkowe opcje renderowania można znaleźć w dokumentacji dotyczącej konwersji HTML do PDF.
Przykład 2: Scałanie wielu plików PDF
Before (iText):
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Kernel.Utils;
using System.IO;
class Program
{
static void Main()
{
string outputPath = "merged.pdf";
string[] inputFiles = { "document1.pdf", "document2.pdf", "document3.pdf" };
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdfDoc = new PdfDocument(writer))
{
PdfMerger merger = new PdfMerger(pdfDoc);
foreach (string file in inputFiles)
{
using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
{
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
}
}
}
}
}
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Kernel.Utils;
using System.IO;
class Program
{
static void Main()
{
string outputPath = "merged.pdf";
string[] inputFiles = { "document1.pdf", "document2.pdf", "document3.pdf" };
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdfDoc = new PdfDocument(writer))
{
PdfMerger merger = new PdfMerger(pdfDoc);
foreach (string file in inputFiles)
{
using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
{
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
}
}
}
}
}
Imports iText.Kernel.Pdf
Imports iText.Kernel.Utils
Imports System.IO
Class Program
Shared Sub Main()
Dim outputPath As String = "merged.pdf"
Dim inputFiles As String() = {"document1.pdf", "document2.pdf", "document3.pdf"}
Using writer As New PdfWriter(outputPath)
Using pdfDoc As New PdfDocument(writer)
Dim merger As New PdfMerger(pdfDoc)
For Each file As String In inputFiles
Using sourcePdf As New PdfDocument(New PdfReader(file))
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages())
End Using
Next
End Using
End Using
End Sub
End Class
$vbLabelText $csharpLabel
Po (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdfDocuments = new List<PdfDocument>
{
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
};
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdfDocuments = new List<PdfDocument>
{
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
};
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
}
}
Imports IronPdf
Imports System.Collections.Generic
Class Program
Shared Sub Main()
Dim pdfDocuments As New List(Of PdfDocument) From {
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
}
Dim merged = PdfDocument.Merge(pdfDocuments)
merged.SaveAs("merged.pdf")
End Sub
End Class
$vbLabelText $csharpLabel
Operacja łączenia iText wymaga znacznego nadmiaru kodu: tworzenia PdfWriter dla wyniku, otaczania go w PdfDocument, tworzenia PdfMerger, następnie iterowania przez pliki źródłowe z zagnieżdżonymi instrukcjami using dla każdego PdfDocument i PdfReader. Należy również określić zakresy stron za pomocą merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages()).
IronPDF redukuje to do trzech kroków: załaduj dokumenty za pomocą PdfDocument.FromFile(), wywołaj statyczną metodę PdfDocument.Merge() z listą i zapisz. Cała operacja scałania staje się czytelna i łatwa w utrzymaniu. Dowiedz się więcej o łączeniu i dzieleniu plików PDF.
Przykład 3: Tworzenie pliku PDF z tekstem i obrazami
Before (iText):
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.IO.Image;
class Program
{
static void Main()
{
string outputPath = "document.pdf";
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdf = new PdfDocument(writer))
using (Document document = new Document(pdf))
{
document.Add(new Paragraph("Sample PDF Document"));
document.Add(new Paragraph("This document contains text and an image."));
Image img = new Image(ImageDataFactory.Create("image.jpg"));
img.SetWidth(200);
document.Add(img);
}
}
}
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.IO.Image;
class Program
{
static void Main()
{
string outputPath = "document.pdf";
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdf = new PdfDocument(writer))
using (Document document = new Document(pdf))
{
document.Add(new Paragraph("Sample PDF Document"));
document.Add(new Paragraph("This document contains text and an image."));
Image img = new Image(ImageDataFactory.Create("image.jpg"));
img.SetWidth(200);
document.Add(img);
}
}
}
Imports iText.Kernel.Pdf
Imports iText.Layout
Imports iText.Layout.Element
Imports iText.IO.Image
Class Program
Shared Sub Main()
Dim outputPath As String = "document.pdf"
Using writer As New PdfWriter(outputPath),
pdf As New PdfDocument(writer),
document As New Document(pdf)
document.Add(New Paragraph("Sample PDF Document"))
document.Add(New Paragraph("This document contains text and an image."))
Dim img As New Image(ImageDataFactory.Create("image.jpg"))
img.SetWidth(200)
document.Add(img)
End Using
End Sub
End Class
$vbLabelText $csharpLabel
Po (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = @"
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("document.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = @"
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("document.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("document.pdf")
End Sub
End Class
$vbLabelText $csharpLabel
Ten przykład najlepiej ilustruje Shift paradygmatu. iText wymaga:
Potrójnie zagnieżdżone instrukcje using (PdfWriter, PdfDocument, Document)
Tworzenie Paragraph obiektów dla każdego elementu tekstowego za pomocą new Paragraph()
Użycie ImageDataFactory.Create() do ładowania obrazów
Tworzenie obiektu Image i wywoływanie SetWidth() oddzielnie
Wywołanie document.Add() dla każdego elementu
IronPDF używa standardowego HTML: dla nagłówków, dla akapitów i dla obrazów z atrybutem width. Programiści stron internetowych mogą od razu wykorzystać swoje dotychczasowe umiejętności, a projektanci mogą stylizować dokumenty przy użyciu znanego im już CSS.
Ważne uwagi dotyczące migracji
Zmiana paradygmatu: od programowania do HTML-First
Najważniejsza zmiana w tej migracji iText ma charakter koncepcyjny. iText tworzy pliki PDF programowo:
// iText approach
document.Add(new Paragraph("Title")
.SetTextAlignment(TextAlignment.CENTER)
.SetFontSize(24)
.SetBold());
var table = new Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth();
table.AddHeaderCell(new Cell().Add(new Paragraph("ID")));
table.AddHeaderCell(new Cell().Add(new Paragraph("Name")));
// ... many more lines
// iText approach
document.Add(new Paragraph("Title")
.SetTextAlignment(TextAlignment.CENTER)
.SetFontSize(24)
.SetBold());
var table = new Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth();
table.AddHeaderCell(new Cell().Add(new Paragraph("ID")));
table.AddHeaderCell(new Cell().Add(new Paragraph("Name")));
// ... many more lines
' iText approach
document.Add(New Paragraph("Title") _
.SetTextAlignment(TextAlignment.CENTER) _
.SetFontSize(24) _
.SetBold())
Dim table = New Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth()
table.AddHeaderCell(New Cell().Add(New Paragraph("ID")))
table.AddHeaderCell(New Cell().Add(New Paragraph("Name")))
' ... many more lines
Imports IronPdf
Dim html As String = "
<style>
h1 { text-align: center; font-size: 24px; font-weight: bold; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #4CAF50; color: white; padding: 8px; }
</style>
<h1>Title</h1>
<table>
<tr><th>ID</th><th>Name</th></tr>
</table>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
$vbLabelText $csharpLabel
Usunięcie narażenia na AGPL
Zgodnie z warunkami AGPL iText, oczekuje się, że aplikacja internetowa korzystająca z iText opublikuję jej kod źródłowy każdemu, kto z nią współdziała poprzez sieć; Licencja komercyjna jest alternatywną ścieżką. Licencja komercyjna IronPDF pozwala na wdrażanie w oprogramowaniu własnościowym bez wymagań dotyczących licencji wirusowej.
Nie jest wymagany dodatek pdfHTML
iText wymaga oddzielnego dodatku itext.pdfhtml (aktualnie 6.3.2) do konwersji HTML-do-PDF, sprzedawanego nad podstawowym pakietem itext.IronPDF zawiera renderowanie HTML oparte na Chromium w podstawowym pakiecie.
Wzorce zastępowania metod
Wzór iText
Zamiennik IronPDF
SetTextAlignment(TextAlignment.CENTER)
CSS text-align: center
SetFontSize(24)
CSS font-size: 24px
SetBold()
CSS font-weight: bold
new Table(3)
HTML
AddHeaderCell(new Cell().Add(new Paragraph()))
HTML
AddCell(new Cell().Add(new Paragraph()))
HTML
Rozwiązywanie problemów
Problem 1: PdfWriter/Wzorzec dokumentu
Problem: Kod używa wzorca zagnieżdżania PdfWriter → PdfDocument → Document.
Rozwiązanie: Zastąp ChromePdfRenderer:
// Delete this iText pattern:
// using (var writer = new PdfWriter(outputPath))
// using (var pdfDoc = new PdfDocument(writer))
// using (var document = new Document(pdfDoc))
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
// Delete this iText pattern:
// using (var writer = new PdfWriter(outputPath))
// using (var pdfDoc = new PdfDocument(writer))
// using (var document = new Document(pdfDoc))
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
$vbLabelText $csharpLabel
Problem 2: Nie znaleziono HtmlConverter
Problem: Kod używa iText.Html2pdf.HtmlConverter, który znajduje się w oddzielnie zakupowanym dodatku itext.pdfhtml.
Rozwiązanie: Wykorzystaj wbudowaną funkcję renderowania HTML w IronPDF:
// iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream);
//IronPDF(built-in)
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
// iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream);
//IronPDF(built-in)
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
' iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream)
' IronPDF(built-in)
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
$vbLabelText $csharpLabel
Problem 3: Złożoność PdfMerger
Problem:PdfMerger iText wymaga zagnieżdżonych czytników i specyfikacji zakresu stron.
Rozwiązanie: Użyj metody statycznego scałania IronPDF:
// iText merger pattern (delete this)
// using (PdfDocument pdfDoc = new PdfDocument(writer))
// {
// PdfMerger merger = new PdfMerger(pdfDoc);
// foreach (string file in inputFiles)
// {
// using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
// {
// merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
// }
// }
// }
//IronPDF(simple)
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
// iText merger pattern (delete this)
// using (PdfDocument pdfDoc = new PdfDocument(writer))
// {
// PdfMerger merger = new PdfMerger(pdfDoc);
// foreach (string file in inputFiles)
// {
// using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
// {
// merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
// }
// }
// }
//IronPDF(simple)
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
Imports System.Collections.Generic
' iText merger pattern (delete this)
' Using pdfDoc As New PdfDocument(writer)
' Dim merger As New PdfMerger(pdfDoc)
' For Each file As String In inputFiles
' Using sourcePdf As New PdfDocument(New PdfReader(file))
' merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages())
' End Using
' Next
' End Using
' IronPDF(simple)
Dim merged = PdfDocument.Merge(pdfDocuments)
merged.SaveAs("merged.pdf")
$vbLabelText $csharpLabel
Lista kontrolna migracji
Przed migracją
Sporządź spis wszystkich wywołań API iText w kodzie źródłowym
Zidentyfikuj programowe wzorce tworzenia plików PDF (akapit, tabela, komórka)
Dokument dotyczący korzystania z HtmlConverter (dodatek pdfHTML)
Ocena ryzyka związanego z zgodnością z licencją AGPL
Uzyskaj klucz licencyjny IronPDF
Migracja kodu
Usuń pakiety NuGet iText: dotnet remove package itext (i przestarzały alias itext7, plus itext.pdfhtml / iTextSharp, jeśli są obecne)
Zaktualizuj importy przestrzeni nazw (using iText.* → using IronPdf)
Zastąp wzorzec Document wzorcem ChromePdfRenderer
Konwertuj Cell na elementy HTML
Zastąp HtmlConverter.ConvertToPdf() przez RenderHtmlAsPdf()
Zaktualizuj operacje scalania do PdfDocument.Merge()
Dodaj inicjalizację klucza licencyjnego podczas uruchamiania
Testowanie
Przetestuj wszystkie ścieżki generowania plików PDF
Sprawdź, czy wygląd końcowy odpowiada oczekiwaniom
Test z wykorzystaniem złożonej treści HTML/CSS
Porównanie wydajności
Po migracji
Usuń pliki licencji i odniesienia do iText
Aktualizacja dokumentacji
Anuluj subskrypcję iText (jeśli dotyczy)
Archiwizacja starszego kodu iText
Zwróć uwagęiText jest zarejestrowanym znakiem towarowym jego właściciela. Ta witryna nie jest powiązana, zatwierdzona ani sponsorowana przez iText Group. 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.
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ę...