Jak scalic pliki PDF w jeden PDF za pomocą Node.js

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF pozwala łączyć wiele plików PDF w jeden dokument w Node.js za pomocą zaledwie kilku linijek kodu. Załadować każdy plik używając PdfDocument.fromFile(), przekazać tablicę do PdfDocument.merge(), i zapisać wynik za pomocą toFile().

Szybki start: Łączenie plików PDF

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/quickstart-merge.js
// Install: npm install ironpdf
const IronPdf = require('ironpdf');

async function quickMerge() {
  const docs = await Promise.all([
    IronPdf.PdfDocument.fromFile('doc1.pdf'),
    IronPdf.PdfDocument.fromFile('doc2.pdf'),
    IronPdf.PdfDocument.fromFile('doc3.pdf'),
  ]);
  const merged = await IronPdf.PdfDocument.merge(docs);
  await merged.toFile('merged-output.pdf');
}

quickMerge();
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/quickstart-merge.js
// Install: npm install ironpdf
const IronPdf = require('ironpdf');

async function quickMerge() {
  const docs = await Promise.all([
    IronPdf.PdfDocument.fromFile('doc1.pdf'),
    IronPdf.PdfDocument.fromFile('doc2.pdf'),
    IronPdf.PdfDocument.fromFile('doc3.pdf'),
  ]);
  const merged = await IronPdf.PdfDocument.merge(docs);
  await merged.toFile('merged-output.pdf');
}

quickMerge();
JAVASCRIPT

IronPDF to biblioteka do manipulacji PDF dla Node.js, która obsługuje konwersję HTML do PDF, montaż dokumentów i modyfikację PDF bez potrzeby użycia jakichkolwiek systemowych narzędzi PDF. Podczas łączenia dokumentów zachowuje czcionki, obrazy, osadzone formularze i układ stron z każdego pliku źródłowego.

Przed wdrożeniem do produkcji, skonfiguruj swój klucz licencyjny IronPDF, aby usunąć znak wodny wersji próbnej i umożliwić pełny wynik. Aby skonfigurować silnik renderowania dla swojego systemu operacyjnego, postępuj zgodnie z przewodnikiem konfiguracji IronPdfEngine.


Jak połączyć wiele plików PDF w Node.js?

PdfDocument.merge() akceptuje tablicę obiektów PdfDocument i zwraca nowy dokument zawierający każdą stronę w kolejności, w jakiej pojawiają się źródłowe dokumenty w tablicy. Operacja jest bezdestrukcyjna; oryginalne obiekty plików nie są modyfikowane.

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-pdfs.js
const IronPdf = require('ironpdf');

async function mergePdfs(outputFilePath, inputFiles) {
  // Load all source documents in parallel
  const pdfDocs = await Promise.all(
    inputFiles.map(file => IronPdf.PdfDocument.fromFile(file))
  );

  // Combine into one document, preserving page order
  const mergedPdf = await IronPdf.PdfDocument.merge(pdfDocs);

  // Write the result to disk
  await mergedPdf.toFile(outputFilePath);
  console.log(`Merged PDF saved to ${outputFilePath}`);
}

(async () => {
  const inputFiles = ['report-jan.pdf', 'report-feb.pdf', 'report-mar.pdf'];
  await mergePdfs('quarterly-report.pdf', inputFiles);
})();
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-pdfs.js
const IronPdf = require('ironpdf');

async function mergePdfs(outputFilePath, inputFiles) {
  // Load all source documents in parallel
  const pdfDocs = await Promise.all(
    inputFiles.map(file => IronPdf.PdfDocument.fromFile(file))
  );

  // Combine into one document, preserving page order
  const mergedPdf = await IronPdf.PdfDocument.merge(pdfDocs);

  // Write the result to disk
  await mergedPdf.toFile(outputFilePath);
  console.log(`Merged PDF saved to ${outputFilePath}`);
}

(async () => {
  const inputFiles = ['report-jan.pdf', 'report-feb.pdf', 'report-mar.pdf'];
  await mergePdfs('quarterly-report.pdf', inputFiles);
})();
JAVASCRIPT

Promise.all() ładuje pliki źródłowe równolegle, a nie jeden po drugim, co ma znaczenie przy przetwarzaniu większych kolekcji. Wywołanie merge() konkatenuje dokumenty w kolejności tablicy, więc umieść pliki w tablicy w sekwencji, w jakiej chcesz, aby pojawiły się w wyniku.

PoradyPrzekaż ścieżki plików jako ścieżki bezwzględne lub ścieżki względne względem katalogu roboczego procesu Node.js. Metoda fromFile() nie rozwiązuje ścieżek względem samego pliku skryptu.

Jakie funkcje pełni każda część kodu?

  • PdfDocument.fromFile(): Odczytuje PDF z dysku i zwraca obiekt PdfDocument. Aby zapoznać się z pełnymi sygnaturami metod, zobacz dokumentację API IronPDF dla Node.js.
  • Promise.all(): Wysyła wszystkie operacje ładowania plików jednocześnie, zmniejszając całkowity czas ładowania dla łączenia wielu dokumentów. Ten wzorzec pasuje także do scenariuszy generowania PDF w wielu wątkach i jednoczesnych wątkach.
  • PdfDocument.merge(): Konkatenuje tablicę załadowanych dokumentów w jeden PdfDocument, zachowując formatowanie, obrazy i wbudowane treści z każdego źródła.
  • toFile(): Zapisuje scalony dokument pod określonym ścieżką. Połącz to z kompresją PDF, aby zmniejszyć rozmiar pliku wynikowego, jeśli to konieczne.

Jak połączyć wybrane strony z każdego PDF?

Przekazywanie każdej strony z każdego dokumentu źródłowego nie zawsze jest celem. Aby scalić wybiórcze zakresy stron z każdego pliku wejściowego, wyodrębnij pożądane strony przed przekazaniem dokumentów do merge().

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-specific-pages.js
const IronPdf = require('ironpdf');

// Each entry specifies a file and the range of pages to include (zero-indexed)
const pageRanges = [
  { file: 'contract.pdf',  startPage: 0, endPage: 2 },
  { file: 'appendix.pdf',  startPage: 0, endPage: 0 },
  { file: 'signature.pdf', startPage: 0, endPage: 0 },
];

async function mergeSpecificPages(outputFile, ranges) {
  const pdfsToMerge = [];

  for (const range of ranges) {
    const pdf = await IronPdf.PdfDocument.fromFile(range.file);
    // extractPages returns a new PdfDocument with only the specified page range
    const pages = pdf.extractPages(range.startPage, range.endPage);
    pdfsToMerge.push(pages);
  }

  const merged = await IronPdf.PdfDocument.merge(pdfsToMerge);
  await merged.toFile(outputFile);
}

mergeSpecificPages('assembled-contract.pdf', pageRanges);
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-specific-pages.js
const IronPdf = require('ironpdf');

// Each entry specifies a file and the range of pages to include (zero-indexed)
const pageRanges = [
  { file: 'contract.pdf',  startPage: 0, endPage: 2 },
  { file: 'appendix.pdf',  startPage: 0, endPage: 0 },
  { file: 'signature.pdf', startPage: 0, endPage: 0 },
];

async function mergeSpecificPages(outputFile, ranges) {
  const pdfsToMerge = [];

  for (const range of ranges) {
    const pdf = await IronPdf.PdfDocument.fromFile(range.file);
    // extractPages returns a new PdfDocument with only the specified page range
    const pages = pdf.extractPages(range.startPage, range.endPage);
    pdfsToMerge.push(pages);
  }

  const merged = await IronPdf.PdfDocument.merge(pdfsToMerge);
  await merged.toFile(outputFile);
}

mergeSpecificPages('assembled-contract.pdf', pageRanges);
JAVASCRIPT

extractPages(startPage, endPage) akceptuje indeksy stron zaczynające się od zera. Przekazanie 0, 0 wyodrębnia tylko pierwszą stronę, podczas gdy 0, 2 wyodrębnia pierwsze trzy strony. Pętla tworzy tablicę dokumentów zakresów stron w kolejności, w jakiej pojawiają się w ranges, następnie merge() konkatenuje je w finalny wynik.

Ten wzorzec jest przydatny podczas montażu umów z strony podpisu, dodatku i arkusza okładkowego przechowywanego w oddzielnych plikach. Możesz zebrać dokładnie te strony, które mają znaczenie z każdego źródła, bez powielania plików na dysku.

Zwróć uwagęIndeksy stron w IronPDF zaczynają się od zera. Strona 1 dokumentu to indeks 0, strona 2 to indeks 1 i tak dalej.


Icon Quote related to Jak połączyć wybrane strony z każdego PDF?

Moją ulubioną biblioteką tego typu jest IronPDF. Umożliwia ona szybkie i efektywne manipulowanie plikami PDF. Posiada także wiele cennych funkcji, takich jak eksport do formatu PDF/A i cyfrowe podpisywanie dokumentów PDF.

Milan Jovanovic related to Jak połączyć wybrane strony z każdego PDF?

Milan Jovanovic

Microsoft MVP

Zobacz studium przypadku
Icon Quote related to Jak połączyć wybrane strony z każdego PDF?

IronOCR pozwala nam oszczędzić 40 000 USD rocznie na ręcznym przetwarzaniu, jednocześnie zwiększając produktywność i uwalniając zasoby do zadań o wysokim wpływie. Gorąco polecam.

Brent Matzelle related to Jak połączyć wybrane strony z każdego PDF?

Brent Matzelle

Dyrektor technologiczny, OPYN

Zobacz studium przypadku
Icon Quote related to Jak połączyć wybrane strony z każdego PDF?

IronSuite odgrywa kluczową rolę w naszej działalności. Są to narzędzia zwiększające wydajność w całej firmie, w tym tworzenie planów pięter i poprawa zarządzania zapasami.

David Jones related to Jak połączyć wybrane strony z każdego PDF?

David Jones

Główny inżynier oprogramowania, Agorus Build

Zobacz studium przypadku

Jak dodać nagłówki i stopki do połączonego PDF?

Po połączeniu, wywołaj addHtmlHeader() i addHtmlFooter() na wynikowym dokumencie, aby zastosować spójne nagłówki i stopki na wszystkich stronach. Te metody przyjmują ciąg HTML i obiekt opcji.

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-headers-footers.js
const IronPdf = require('ironpdf');

async function mergeWithHeadersFooters(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Apply a styled header to every page
  await mergedPdf.addHtmlHeader('<h3 style="color:#333;">Quarterly Report</h3>', {
    height: 25,
    drawDividerLine: true,
  });

  // Apply a page-numbering footer
  await mergedPdf.addHtmlFooter('<p style="font-size:10px;">Page {page} of {total-pages}</p>', {
    height: 20,
    drawDividerLine: true,
  });

  await mergedPdf.toFile(outputFile);
}

mergeWithHeadersFooters(['q1.pdf', 'q2.pdf', 'q3.pdf'], 'annual-report.pdf');
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-headers-footers.js
const IronPdf = require('ironpdf');

async function mergeWithHeadersFooters(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Apply a styled header to every page
  await mergedPdf.addHtmlHeader('<h3 style="color:#333;">Quarterly Report</h3>', {
    height: 25,
    drawDividerLine: true,
  });

  // Apply a page-numbering footer
  await mergedPdf.addHtmlFooter('<p style="font-size:10px;">Page {page} of {total-pages}</p>', {
    height: 20,
    drawDividerLine: true,
  });

  await mergedPdf.toFile(outputFile);
}

mergeWithHeadersFooters(['q1.pdf', 'q2.pdf', 'q3.pdf'], 'annual-report.pdf');
JAVASCRIPT

Zmienne {page} i {total-pages} są rozwiązywane podczas renderowania w odniesieniu do liczby stron scalonego dokumentu. Użyj drawDividerLine: true, aby wizualnie oddzielić nagłówek lub stopkę od treści strony.

Stosowanie nagłówków i stopek po połączeniu oznacza, że każda strona w połączonym dokumencie otrzymuje to samo traktowanie, niezależnie od tego, z którego pliku źródłowego pochodzi. Aby uzyskać pełne opcje konfiguracji nagłówków i stopek, zobacz przykłady HTML nagłówków i stopek.


Jak zabezpieczyć połączony PDF hasłem?

Zastosować ochronę hasłem i restrykcje uprawnień po łączeniu, wywołując saveAs() z obiektem opcji zabezpieczeń. To zapobiega nieautoryzowanemu dostępowi do połączonego dokumentu.

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-security.js
const IronPdf = require('ironpdf');

async function mergeWithSecurity(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Restrict the merged document to print-only access
  await mergedPdf.saveAs(outputFile, {
    userPassword: 'viewerpass',
    ownerPassword: 'adminpass',
    allowUserAnnotations: false,
    allowUserCopyPasteContent: false,
    allowUserFormData: false,
    allowUserPrinting: true,
  });
}

mergeWithSecurity(['invoice-1.pdf', 'invoice-2.pdf'], 'secured-invoices.pdf');
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-security.js
const IronPdf = require('ironpdf');

async function mergeWithSecurity(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Restrict the merged document to print-only access
  await mergedPdf.saveAs(outputFile, {
    userPassword: 'viewerpass',
    ownerPassword: 'adminpass',
    allowUserAnnotations: false,
    allowUserCopyPasteContent: false,
    allowUserFormData: false,
    allowUserPrinting: true,
  });
}

mergeWithSecurity(['invoice-1.pdf', 'invoice-2.pdf'], 'secured-invoices.pdf');
JAVASCRIPT

Do dokumentu wymagane jest userPassword; ownerPassword kontroluje same ustawienia uprawnień. Ustawienie allowUserPrinting: true przy jednoczesnym wyłączeniu innych flag uprawnień pozwala odbiorcom drukować dokument, ale zapobiega edycji, kopiowaniu i adnotacjom. Dla pełnej listy dostępnych flag uprawnień, zapoznaj się z dokumentacją API IronPDF Node.js.

WażneJeśli źródłowe PDFy są już chronione hasłem, dostarcz hasło dekryptujące do każdego dokumentu podczas ładowania z fromFile(). Próba połączenia zaszyfrowanego dokumentu bez podania hasła zakończy się błędem.


Jak połączyć PDF i dodać podpis cyfrowy?

Łączenie PDF, a następnie natychmiastowe podpisywanie wyników, tworzy pojedynczy podpisany dokument, który obejmuje całą treść źródłową. Zastosować applySignature() po merge(), aby dołączyć certyfikat cyfrowy do połączonego rezultatu.

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-signature.js
const IronPdf = require('ironpdf');

async function mergeAndSign(inputFiles, outputFile, pfxPath, pfxPassword) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Attach a digital signature using a PFX certificate
  await mergedPdf.applySignature(pfxPath, pfxPassword);
  await mergedPdf.toFile(outputFile);
}

mergeAndSign(
  ['section-a.pdf', 'section-b.pdf'],
  'signed-report.pdf',
  'certificate.pfx',
  'certpass'
);
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-signature.js
const IronPdf = require('ironpdf');

async function mergeAndSign(inputFiles, outputFile, pfxPath, pfxPassword) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Attach a digital signature using a PFX certificate
  await mergedPdf.applySignature(pfxPath, pfxPassword);
  await mergedPdf.toFile(outputFile);
}

mergeAndSign(
  ['section-a.pdf', 'section-b.pdf'],
  'signed-report.pdf',
  'certificate.pfx',
  'certpass'
);
JAVASCRIPT

Metoda applySignature() osadza certyfikat w metadanych PDF, aby czytelnicy mogli zweryfikować integralność dokumentu. Ten przepływ pracy jest powszechny w procesach składania umów, gdzie łączone są różne sekcje, a następnie współpodpisane przed dystrybucją. Aby uzyskać pełny przewodnik po podpisywaniu na certyfikatach, zobacz przykłady podpisów cyfrowych.

PoradyPodpisz połączony dokument zamiast poszczególnych plików źródłowych, gdy potrzebujesz jednego certyfikatu, który potwierdza cały połączony dokument.


Jak rozwiązywać najczęstsze błędy łączenia PDF?

Większość błędów podczas łączenia podzielona jest na cztery kategorie: brakujące pliki, wyczerpanie pamięci, uszkodzone wejścia i problemy z uprawnieniami. Poniższa tabela wymienia najczęstsze przyczyny i sposoby rozwiązania ich.

Najczęstsze błędy łączenia PDF i ich rozwiązania
BłądPrawdopodobna przyczynaRozwiązanie
Plik nie znalezionyNieprawidłowa ścieżka lub niezgodność katalogów roboczychUżyj ścieżek bezwzględnych lub zweryfikuj katalog roboczy procesu
Przepaść pamięci stosu JavaScriptJednoczesne ładowanie wielu dużych plików PDFZwiększ pamięć w Node.js: node --max-old-space-size=4096 script.js
Nieprawidłowy lub uszkodzony PDFPlik źródłowy jest uszkodzony lub nie jest prawidłowym PDFSprawdź pliki źródłowe za pomocą czytnika PDF przed przetworzeniem
Odmowa dostępuBrak dostępu do odczytu na wejściu lub brak dostępu do zapisu w katalogu wyjściowymSprawdź uprawnienia plików i katalogów w systemie operacyjnym
Zaszyfrowany źródłowy PDFWejściowy PDF wymaga hasła do otwarciaPodaj hasło jako drugi argument do fromFile()

Dla problemów z konfiguracją specyficznego dla środowiska, changelog IronPDF dokumentuje znane problemy i ich naprawy. Jeśli problemy będą się utrzymywać po sprawdzeniu tabeli powyżej, opakuj wywołanie łączenia w blok try-catch, aby przedstawić pełną wiadomość błędu z biblioteki.

UwagaZawsze sprawdzać, czy każda ścieżka pliku w twojej tablicy wejściowej istnieje, przed wywołaniem fromFile(). Pojedynczy brakujący plik powoduje, że całe wywołanie Promise.all() odrzuca, anulując łączenie.

Node.js sam dostarcza przydatne narzędzia do walidacji ścieżki przed startem. Metoda Node.js fs.promises.access pozwala sprawdzić, czy plik jest czytelny przed przekazaniem go do IronPDF. W przypadku pytań o to, jak społeczność programistów radzi sobie z podobnymi scenariuszami błędów łączenia, wątek Stack Overflow o łączeniu PDF w Node.js dostarcza dodatkowego kontekstu.


Jakie są kolejne kroki w łączeniu PDF w Node.js?

Powyższe przykłady obejmują najczęstsze scenariusze łączenia: podstawowe połączenie plików, wybór zakresu stron, wprowadzenie nagłówków i stopek, ochrona hasłem i podpisy cyfrowe. IronPDF obsługuje również zarządzanie formularzami PDF na połączonych stronach, stemplowanie nowej zawartości na połączonym dokumencie i tworzenie rastrowych obrazów z końcowego wyniku dla generacji podglądu.

Rozpocznij bezpłatny 30-dniowy okres próbny, aby przetestować łączenie bez znaku wodnego, lub zobacz opcje licencjonowania, jeśli jesteś gotów do wdrożenia.

Gotowy, aby zobaczyć, co jeszcze potrafi IronPDF? Odwiedź dokumentację IronPDF dla Node.js dla pełnego przeglądu API i dodatkowych przewodników "jak-to-zrobić".

Często Zadawane Pytania

Jak złączyć wiele plików PDF w jeden w Node.js?

Załaduj każdy plik za pomocą PdfDocument.fromFile(), zbierz wyniki w tablicy, przekaż tablicę do PdfDocument.merge() i zapisz wynik za pomocą toFile(). Użyj Promise.all(), aby ładować pliki równolegle podczas scalania trzech lub więcej dokumentów.

Czy IronPDF zachowuje formatowanie podczas scalania PDFów?

Tak. IronPDF zachowuje czcionki, obrazy, osadzone formularze i geometrię stron z każdego źródłowego dokumentu. Scalane wyjście utrzymuje oryginalny układ każdej strony zgodnie z kolejnością plików źródłowych w tablicy wejściowej.

Jak złączyć tylko określone strony z każdego PDF?

Wywołaj extractPages(startPage, endPage) na każdym załadowanym dokumencie przed przekazaniem go do PdfDocument.merge(). Indeksy stron zaczynają się od zera, więc pierwsza strona ma indeks 0. Zwracany dokument zawiera tylko określony zakres.

Czy mogę dodać nagłówki i stopki do połączonego PDF?

Tak. Po scaleniu wywołaj addHtmlHeader() i addHtmlFooter() na wynikowym dokumencie. Obie metody akceptują ciąg HTML i obiekt z opcjami. Użyj zastępczych wartości {page} i {total-pages} dla automatycznego numerowania stron.

Jak chronić hasłem połączony PDF w Node.js?

Wywołaj saveAs() z obiektem opcji bezpieczeństwa określającym userPassword, ownerPassword i flagi uprawnień, takie jak allowUserPrinting. userPassword jest wymagane do otwarcia dokumentu; ownerPassword kontroluje ustawienia uprawnień.

Co zrobić, jeśli scalanie zakończy się niepowodzeniem z błędem braku pliku?

Sprawdź, czy wszystkie ścieżki do plików wejściowych są poprawne względem katalogu roboczego procesu Node.js lub przejdź do ścieżek absolutnych. Użyj fs.promises.access(), aby potwierdzić, że każdy plik można odczytać przed wywołaniem PdfDocument.fromFile().

Co się dzieje, jeśli jeden z plików źródłowych PDF jest zaszyfrowany?

Próba załadowania zaszyfrowanego PDF bez podania jego hasła spowoduje błąd i odrzuci całe wywołanie Promise.all(). Podaj hasło dokumentu jako drugi argument do fromFile() przed scaleniem.

Czy potrzebuję klucza licencyjnego, aby scalić PDFy z IronPDF?

IronPDF działa bez klucza licencyjnego podczas rozwoju, ale dokumenty wyjściowe mają znak wodny w wersji próbnej. Skonfiguruj ważny klucz licencyjny przed wdrożeniem do produkcji, aby usunąć znak wodny i włączyć pełną funkcjonalność.

Darrius Serrant
Inżynier oprogramowania Full Stack (WebOps)

Darrius Serrant posiada tytuł licencjata z informatyki z Uniwersytetu Miami i pracuje jako Full Stack WebOps Marketing Engineer w Iron Software. Już od młodych lat zainteresował się kodowaniem, postrzegając informatykę jako zarówno tajemniczą, jak i dostępną, co czyni ją doskonałym medium dla kreatywności ...

Czytaj więcej
Gotowy, aby rozpocząć?
Wersja: 2026.6 właśnie wydany
Still Scrolling Icon

Wciąż przewijasz?

Czy chcesz szybko dowodu?
Uruchom przykład i zobacz, jak Twój kod HTML zamienia się w plik PDF.