在Web应用程序Java中合并多个PDF文件为一个PDF文件

3
我有许多PDF文件,需要将它们合并成一个大的PDF文件并在浏览器中显示。我使用的是itext库。使用这个库,我可以将文件合并成一个文件并保存在磁盘上,但无法在浏览器中合并显示,只能显示最后一个PDF文件。。以下是我的代码,请帮忙解决这个问题。
提前感谢您的帮助。
            Document document = new Document();
            List<PdfReader> readers = 
                    new ArrayList<PdfReader>();
            int totalPages = 0;

            ServletOutputStream servletOutPutStream = response.getOutputStream();;
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();;

            InputStream is=null;
            List<InputStream> inputPdfList = new ArrayList<InputStream>();
            System.err.println(imageMap.size());

            for(byte[] imageList:imageMap)
            {
                System.out.println(imageList.toString()+"   "+imageList.length);


                 byteArrayOutputStream.write(imageList);

                 byteArrayOutputStream.writeTo(response.getOutputStream());

                 is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
                 inputPdfList.add(is);

            }
            response.setContentType("application/pdf");
            response.setContentLength(byteArrayOutputStream.size());

            System.out.println(inputPdfList.size()+""+inputPdfList.toString());
            //Create pdf Iterator object using inputPdfList.
            Iterator<InputStream> pdfIterator = 
                    inputPdfList.iterator();

            // Create reader list for the input pdf files.
            while (pdfIterator.hasNext()) {
                    InputStream pdf = pdfIterator.next();
                    PdfReader pdfReader = new PdfReader(pdf);
                    readers.add(pdfReader);
                    totalPages = totalPages + pdfReader.getNumberOfPages();
            }

            // Create writer for the outputStream
            PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());

            //Open document.
            document.open();

            //Contain the pdf data.
            PdfContentByte pageContentByte = writer.getDirectContent();

            PdfImportedPage pdfImportedPage;
            int currentPdfReaderPage = 1;
            Iterator<PdfReader> iteratorPDFReader = readers.iterator();

            // Iterate and process the reader list.
            while (iteratorPDFReader.hasNext()) {
                    PdfReader pdfReader = iteratorPDFReader.next();
                    //Create page and add content.
                    while (currentPdfReaderPage <= pdfReader.getNumberOfPages()) {
                          document.newPage();
                          pdfImportedPage = writer.getImportedPage(
                                  pdfReader,currentPdfReaderPage);
                          pageContentByte.addTemplate(pdfImportedPage, 0, 0);
                          currentPdfReaderPage++;
                    }
                    currentPdfReaderPage = 1;
            }

            //Close document and outputStream.
            servletOutPutStream.flush();
            outputStream.flush();
            document.close();
            outputStream.close();

            servletOutPutStream.close();
            System.out.println("Pdf files merged successfully.");

欢迎来到StackOverflow,请您在提问时附上一些代码。 - isuruAb
1
@IsuruAb 谢谢您,我已经添加了代码片段。 - Janmejaysinh Gohil
2个回答

2

你的代码中存在许多错误:

只向响应输出流写入想要返回给浏览器的内容

你的代码将各种不同的数据写入了响应输出流:

ServletOutputStream servletOutPutStream = response.getOutputStream();;
[...]
for(byte[] imageList:imageMap)
{
     [...]
     byteArrayOutputStream.writeTo(response.getOutputStream());
     [...]
}
[...]
PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
[... merge PDFs into the writer]

servletOutPutStream.flush();
document.close();

servletOutPutStream.close();

这将导致许多imageMap元素的副本被写入那里,合并后的文件只会在此之后添加。

你希望浏览器做什么?忽略所有前面的源PDF副本,直到最终出现合并的PDF吗?

因此,请仅将合并后的PDF写入响应输出流中。

不要编写错误的内容长度

将内容长度写入响应是个好主意...但仅当你使用正确的值时!

在你的代码中,你编写了一个内容长度:

response.setContentLength(byteArrayOutputStream.size());

但是此时的 byteArrayOutputStream 只包含源PDF的混合副本,尚未包含最终合并的PDF。因此,这只会使浏览器更加混乱。

因此,请不要向响应添加错误的头信息。

不要篡改输入数据

在循环中

for(byte[] imageList:imageMap)
{
    System.out.println(imageList.toString()+"   "+imageList.length);

    byteArrayOutputStream.write(imageList);

    byteArrayOutputStream.writeTo(response.getOutputStream());

    is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
    inputPdfList.add(is);
}

您使用byte数组,我假设每个数组都包含单个源PDF,将其混入响应输出流中(如前所述),并创建一组输入流,其中第一个包含第一个源PDF,第二个包含第一个和第二个源PDF的连接,第三个包含前三个源PDF的连接等等...

由于您从未重置或重新实例化byteArrayOutputStream,因此它只会变得越来越大。

因此,请在类似这样的循环开始或结束时重置byteArrayOutputStream

(实际上,您根本不需要那个循环,PdfReader有一个构造函数,可以立即获取byte [],无需将其包装在字节流中。)

不要使用普通的PdfWriter合并PDF,请使用PdfCopy

您使用PdfWriter/getImportedPage/addTemplate方法合并PDF。在stack overflow上有数十个问题和答案(其中许多是由iText开发人员回答的),解释了这通常是一个坏主意,并且应该使用PdfCopy

因此,请利用此主题上已经存在的许多好答案,并使用PdfCopy进行合并。

不要仅仅因为可以而刷新或关闭流

您通过关闭众多流来完成响应输出:

//Close document and outputStream.
servletOutPutStream.flush();
outputStream.flush();
document.close();
outputStream.close();

servletOutPutStream.close();

我没有看到你声明或设置outputStream变量的代码行,但即使它包含响应输出流,也没有必要关闭它,因为你已经在servletOutPutStream变量中关闭了它。
因此,请删除这样不必要的调用。

谢谢您的帮助。我根据您的答案进行了更改,我的问题已经解决了。 - Janmejaysinh Gohil
在Mozilla Firefox浏览器中渲染合并的PDF文件时出现错误。 - Janmejaysinh Gohil
如果你仍然遇到这个问题,请分享一份生成的 PDF 的副本。 - mkl
我已经从itext转换到PDFBox,现在它可以工作了。 - Janmejaysinh Gohil
使用这两个库中的任何一个都可以合并PDF并允许在HTTP响应中返回结果。我假设你使用的pdfbox相关文档和示例比之前使用的itext相关文档更容易理解。 - mkl

0
//假设我们想要将一个pdf与另一个主pdf合并
          InputStream is1 = null;



          if (file1 != null) {

                 FileInputStream fis1 = new FileInputStream(file1);

                 byte[] file1Data = new byte[(int) file1.length()];

                 fis1.read(file1Data);

                 is1 = new java.io.ByteArrayInputStream(file1Data);

          }



          //

          InputStream mainContent = <ur main content>



          org.apache.pdfbox.pdmodel.PDDocument mergedPDF = new org.apache.pdfbox.pdmodel.PDDocument();

          org.apache.pdfbox.pdmodel.PDDocument mainDoc = org.apache.pdfbox.pdmodel.PDDocument.load(mainContent);

          org.apache.pdfbox.multipdf.PDFMergerUtility merger = new org.apache.pdfbox.multipdf.PDFMergerUtility();



          merger.appendDocument(mergedPDF, mainDoc);



          PDDocument doc1 = null;



          if (is1 != null) {

                 doc1 = PDDocument.load(is1);

                 merger.appendDocument(mergedPDF, doc1);

                //1st file appended to main pdf");

          }

         



          ByteArrayOutputStream baos = new ByteArrayOutputStream();

          mergedPDF.save(baos);

//现在你可以在这里保存它,或者如果你想的话将它转换为InputStream

          ByteArrayInputStream mergedInputStream = new ByteArrayInputStream(baos.toByteArray());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接