Как разобрать несколько файлов HTML в один PDF?

Я хочу использовать iText для преобразования серии HTML-файлов в PDF.

Например: если есть эти файлы:

  • page1.html
  • page2.html
  • page3.html
  • ...

Теперь я хочу создать один PDF-файл, где page1.html - первая страница, page2.html - вторая страница и т. Д.

Я знаю, как преобразовать один файл HTML в PDF, но я не знаю, как объединить эти различные PDF-файлы, полученные в результате этой операции, в один PDF-файл.

1 ответ

Решение

Прежде чем мы начнем: я не разработчик C#, поэтому я не могу привести вам пример на C#. Все примеры iText, которые я пишу, написаны на Java. К счастью, iText и iTextSharp всегда синхронизированы. В контексте этого вопроса вы можете быть уверены, что все, что работает для iText, будет работать и для iTextSharp, но вам придется внести небольшие изменения, специфичные для C#. Из того, что я слышал от разработчиков на C#, этого обычно нетрудно достичь.

Что касается ответа: есть два ответа, и ответ № 2, как правило, лучше, чем ответ № 1, но я даю оба варианта, потому что могут быть конкретные случаи, когда ответ № 1 лучше.

Тестовые данные: я создал 3 простых HTML-файла, каждый из которых содержит некоторую информацию о штате в США:

Мы будем использовать XML Worker для анализа этих трех файлов, и в результате мы хотим получить один файл PDF.

Ответ № 1: см. ParseMultipleHtmlFiles1 для полного примера кода и множественный_html_pages1.pdf для получающегося PDF.

Вы говорите, что вам уже удалось преобразовать один HTML-файл в один PDF-файл. Предполагается, что вы сделали это так:

public byte[] parseHtml(String html) throws DocumentException, IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // step 1
    Document document = new Document();
    // step 2
    PdfWriter writer = PdfWriter.getInstance(document, baos);
    // step 3
    document.open();
    // step 4
    XMLWorkerHelper.getInstance().parseXHtml(writer, document,
            new FileInputStream(html));
    // step 5
    document.close();
    // return the bytes of the PDF
    return baos.toByteArray();
}

Это не самый эффективный способ анализа HTML-файла (есть другие примеры на веб-сайте), но это самый простой способ.

Как видите, этот метод анализирует HTML-файл в PDF-файле и возвращает этот PDF-файл в виде byte[], Поскольку мы хотим создать один PDF, мы можем передать этот байтовый массив в PdfCopy экземпляр, так что мы можем объединить несколько документов.

Предположим, что у нас есть три документа:

public static final String[] HTML = {
    "resources/xml/page1.html",
    "resources/xml/page2.html",
    "resources/xml/page3.html"
};

Мы можем зациклить эти три документа, проанализировать их один за другим byte[], создать PdfReader экземпляр с байтами PDF, и добавьте документ в PdfCopy экземпляр, использующий addDocument() метод:

public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfCopy copy = new PdfCopy(document, new FileOutputStream(file));
    document.open();
    PdfReader reader;
    for (String html : HTML) {
        reader = new PdfReader(parseHtml(html));
        copy.addDocument(reader);
        reader.close();
    }
    document.close();
} 

Это решает вашу проблему, но почему я думаю, что это не оптимальное решение?

Предположим, вам нужно использовать специальный шрифт, который нужно встроить. В этом случае каждый отдельный файл PDF будет содержать подмножество этого шрифта. Для разных файлов потребуются разные наборы шрифтов, и PdfCopy (ни PdfSmartCopy в этом отношении) может объединять подмножества шрифтов. Это может привести к раздутому файлу PDF со слишком большим количеством подмножеств шрифта одного и того же шрифта.

Как мы решаем это? Это объясняется в ответе № 2.

Ответ № 2: См. ParseMultipleHtmlFiles2 для полного примера кода и множественный_html_pages2.pdf для получающегося PDF. Вы уже видите разницу в размере файла: 4,61 КБ против 5,05 КБ (и мы даже не ввели встроенные шрифты).

В этом случае мы не анализируем HTML-файл PDF, как мы это делали в parseHtml() Метод из ответа № 1. Вместо этого мы анализируем HTML в iText ElementList с использованием parseToElementList() метод. Этот метод требует двух Strings. Один содержит код HTML, другой содержит значения CSS.

Мы используем служебный метод для чтения файла HTML в String, Что касается значения CSS, мы могли бы передать null в parseToElementList(), но в этом случае стили по умолчанию будут игнорироваться. Вы заметите, что <h1> тег, который мы ввели в наш HTML, будет выглядеть совершенно иначе, если вы не передадите default.css поставляется с XML Worker.

Короче говоря, это код:

public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();
    String css = readCSS();
    for (String htmlfile : HTML) {
        String html = Utilities.readFileToString(htmlfile);
        ElementList list = XMLWorkerHelper.parseToElementList(html, css);
        for (Element e : list) {
            document.add(e);
        }
        document.newPage();
    }
    document.close();
}

Мы создаем единый Document и один PdfWriter пример. Мы анализируем различные HTML-файлы в ElementListодин за другим, и мы добавляем все элементы в Document,

Как вы хотите новую страницу, каждый раз, когда новый файл HTML анализируется, я представил document.newPage(), Если вы удалите эту строку, вы можете добавить три HTML-страницы на одной странице (что было бы невозможно, если бы вы выбрали ответ №1).

Другие вопросы по тегам