将许多pdf文件合并到Web应用程序java中的一个pdf文件中

时间:2017-05-30 06:11:43

标签: java spring-mvc pdf merge

我有很多pdf文件,我必须将所有pdf合并到一个大的pdf文件中并将其渲染到浏览器中。我使用的是itext。使用这个,我能够将pdf文件合并到一个文件到磁盘但我无法合并到浏览器中,浏览器中只有最后一个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.");

1 个答案:

答案 0 :(得分: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。关于堆栈溢出有很多问题和答案(其中很多都是由iText开发人员回答的)解释说这通常是一个坏主意,你应该使用PdfCopy

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

请勿仅因为您

而刷新或关闭流

通过关闭众多流来最终确定响应输出:

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

servletOutPutStream.close();

我没有看到你声明或设置outputStream变量的行,但即使它包含响应输出流,也没有必要关闭它,因为你已经在{{1变量。

因此,请删除此类不必要的电话。