Объединить PDF без выравнивания, но сохранить поля - PullRequest
0 голосов
/ 13 июня 2018

Я пытаюсь заполнить шаблон PDF и добавить еще один PDF в конце.У меня нет проблем, чтобы добавить страницу в другой файл PDF, но проблема в том, что когда я это делаю, мои поля теряются, даже если я не использую stamper.setFormFlattens (true).

Вот мой код:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;

public class ForStack {

    public static void main(String[] args) throws IOException, DocumentException, ParseException {
        createContractWithMoreFile();
    }

    public static void createContractWithMoreFile()
            throws IOException, DocumentException, ParseException {

        String linkPDF = "resources/pdfs/User.pdf";

        PdfReader reader = new PdfReader(linkPDF);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, baos);

        PdfWriter writer = stamper.getWriter();
        writer.setPdfVersion(PdfWriter.VERSION_1_7);
        AcroFields form = stamper.getAcroFields();

        form.setField("Name", "Jhon");
        stamper.close();
        String out = "results/merged.pdf";

        List<byte[]> listOfPdfFiles = new ArrayList<>();
        listOfPdfFiles.add(baos.toByteArray());

        byte[] informativaPrivacy = getPdfByteArray("resources/pdfs/second.pdf");
        listOfPdfFiles.add(informativaPrivacy);

        concatenatePdfs(listOfPdfFiles, new File(out));

        baos.close();
        reader.close();

    }

    public static byte[] getPdfByteArray(String filePath) {
        File fileP = new File(filePath);
        byte[] result;
        try {
            result = FileUtils.readFileToByteArray(fileP);
            return result;
        } catch (IOException e) {
            return null;
        }
    }

    public static void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
        Document document = new Document();
        FileOutputStream outputStream = new FileOutputStream(outputFile);
        PdfCopy copy = new PdfSmartCopy(document, outputStream);
        document.open();
        for (byte[] inFile : listOfPdfFiles) {
            PdfReader reader = new PdfReader(inFile);
            copy.addDocument(reader);
            reader.close();
        }
        document.close();
    }
}

А вот файл, который я использую

  1. Пользователь

  2. секунда

И выходной файл не тот, который мне нужен: файл результатов

Так почему выходной pdf потерял мое поле?Без конкатенации нет выравнивания .....

Как вы можете видеть в моем файле результатов, нет поля, поэтому, если вы хотите увидеть его снова, я должен использовать Adobe Acrobat, используйте-> Вид (Vista) -> Инструменты (Impostazioni) -> Создать форму (Prepara Modulo).Но если я сделаю это и попытаюсь выйти из pdf, Adobe попросит меня сохранить pdf, который он изменил, и это не то, что мне нужно.

The result

Выходной pdf, который я хочу, находится здесь: Выходной файл, который я хочу С полем, которое потеряно в файле результатов OutputImage

Ответы [ 2 ]

0 голосов
/ 14 июня 2018

В ответе Бруно изначально предполагалось, что вызов stamper.setFormFlattening(true) из исходного кода ОП указывает на то, что форма должна быть сведена.Как оказалось, это не тот случай, поля должны были остаться.

Таким образом, Бруно удалил линию выравнивания формы и указал, что результат теперь редактируемый, то есть поля формы присутствовали.Но ОП по-прежнему настаивал на том, что они ушли.

Как оказалось, оба были правы, каждый по-своему.Разница: поля формы присутствовали в выходных данных в виде аннотаций виджетов на странице , но определение формы AcroForm пропало.

Длясоздать экземпляр iText 5.5.x PdfCopy создать определение формы AcroForm в целевом документе, содержащем объединенные поля формы всех скопированных исходных документов, необходимо активировать mergeFields mode !

Если вам интересно, почему этот режим не активен по умолчанию: у него есть недостаток, все исходные PdfReader объекты должны оставаться открытыми, пока целевой PdfCopy экземпляр не будет закрыт.что может привести к существенно большему объему памяти в коде.

Для работы в режиме mergeFields метод OP concatenatePdfs

void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
    Document document = new Document();
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    PdfCopy copy = new PdfSmartCopy(document, outputStream);
    document.open();
    for (byte[] inFile : listOfPdfFiles) {
        PdfReader reader = new PdfReader(inFile);
        copy.addDocument(reader);
        reader.close();
    }
    document.close();
}

должен быть переписанвот так:

void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
    Document document = new Document();
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    PdfCopy copy = new PdfSmartCopy(document, outputStream);
    copy.setMergeFields();
    document.open();
    List<PdfReader> pdfReaders = new ArrayList<>();
    for (byte[] inFile : listOfPdfFiles) {
        PdfReader reader = new PdfReader(inFile);
        copy.addDocument(reader);
        pdfReaders.add(reader);
    }
    document.close();
    pdfReaders.forEach(r -> r.close());
}

( CopyWithField метод concatenatePdfs)

Как видите, режим mergeFields активируется copy.setMergeFields(), а исходные PdfReader экземпляры не закрываютсяd сразу после добавления к copy, но вместо этого собирается в pdfReaders и закрывается только после закрытия copy (которое неявно закрывается в течение document.close()).

0 голосов
/ 13 июня 2018

В вашем коде было множество ошибок.Например: вам не нужно org.w3c.dom.Document, вам нужно com.itextpdf.text.Document;эта ошибка приводила к тому, что ваш код даже не мог быть скомпилирован.

Я исправил ошибки и в результате получил SSCCE:

package sandbox.merge;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;

public class ForStack {

    public static void main(String[] args) throws IOException, DocumentException, ParseException {
        createContractWithMoreFile();
    }

    public static void createContractWithMoreFile()
            throws IOException, DocumentException, ParseException {

        String linkPDF = "resources/pdfs/User.pdf";

        PdfReader reader = new PdfReader(linkPDF);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, baos);

        PdfWriter writer = stamper.getWriter();
        writer.setPdfVersion(PdfWriter.VERSION_1_7);
        AcroFields form = stamper.getAcroFields();

        form.setField("Name", "Jhon");
        stamper.setFormFlattening(true);
        stamper.close();
        String out = "results/merged.pdf";

        List<byte[]> listOfPdfFiles = new ArrayList<>();
        listOfPdfFiles.add(baos.toByteArray());

        byte[] informativaPrivacy = getPdfByteArray("resources/pdfs/second.pdf");
        listOfPdfFiles.add(informativaPrivacy);

        concatenatePdfs(listOfPdfFiles, new File(out));

        baos.close();
        reader.close();

    }

    public static byte[] getPdfByteArray(String filePath) {
        File fileP = new File(filePath);
        byte[] result;
        try {
            result = FileUtils.readFileToByteArray(fileP);
            return result;
        } catch (IOException e) {
            return null;
        }
    }

    public static void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
        Document document = new Document();
        FileOutputStream outputStream = new FileOutputStream(outputFile);
        PdfCopy copy = new PdfSmartCopy(document, outputStream);
        document.open();
        for (byte[] inFile : listOfPdfFiles) {
            PdfReader reader = new PdfReader(inFile);
            copy.addDocument(reader);
            reader.close();
        }
        document.close();
    }
}

Я мог воспроизвести проблему, о которой вы упоминали, только удаливследующая строка:

stamper.setFormFlattening(true);

Эта строка отсутствует в вашем коде и объясняет, почему форма не сплющена.

Обобщена:

Когда вы расправляете форму, у вас есть это:

enter image description here

Где когда-то было поле "Name", мы видим значение "Jhon", носамо поле пропало: вот в чем заключается уплощение: вы удаляете всю интерактивность.

Когда вы не расплющиваете форму, у вас есть это:

enter image description here

Интерактивное поле все еще там, не разглажено.Он был заполнен значением "Jhon".

Кажется, что OP хочет сгладить форму, как на первом снимке экрана, и в то же время сохранить поле, как на втором снимке экрана.Это противопоказание.ОП должен уточнить, что ожидается, если потребуется ответ.

Версия iText

Кстати: я использовал iText 5.5.13 для проверки этого.Помните, что iText 5 больше не поддерживается, если вы не являетесь платным клиентом.Текущая версия - iText 7.1.2, но в 7.1.2 класс PdfStamper больше не существует.Заполнение форм и объединение документов в iText 7 выполняется по-другому.

...