>我有很多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.");
代码中存在许多错误:
仅将要返回给浏览器的内容写入响应输出流
您的代码将大量数据写入响应输出流:
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
变量的行,但即使它包含响应输出流,也无需关闭它,因为您已经在servletOutPutStream
变量中关闭了它。
因此,请删除不必要的此类调用。
//假设我们想将一个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);
现在要么你把它保存在这里,要么转换成输入流,如果你愿意的话
ByteArrayInputStream mergedInputStream = new ByteArrayInputStream(baos.toByteArray());