我在java中使用Itext API创建了一个PDF文件并已下载。当我试图查看它时,它给了我
当我尝试插入任何图像时,我收到此错误。如果我的PDF中没有图像,则打开正常。而且,如果我将pdf写入我的本地系统,那么它也可以正常工作。
仅当pdf包含图像并且已下载时才会出现此问题。
以下是我用于在pdf中设置图片的代码
Document doc = new Document();
File file = new File(new Random().nextInt(10000)+"_orders.pdf");
PdfWriter docWriter = PdfWriter.getInstance(doc, new FileOutputStream(file));
doc.open();
Image companyLogo = Image.getInstance("http://www.quicklyjava.com/wp-content/themes/hybrid-news/images/sitelogo.png");
companyLogo.setAbsolutePosition(20, 720);
companyLogo.scalePercent(50);
doc.add(companyLogo);
doc.close();
return file;
任何人都可以帮我解决这个问题。
添加一些信息:下载后在浏览器中打开正常。在Adobe Reader中打开时出现问题。
答案 0 :(得分:4)
您说您的代码适用于您的本地计算机。这太棒了:你已经确定问题与iText没有关系,因此问题必然是由别的东西引起的。
查看您的代码示例,最可能的罪魁祸首是http://www.quicklyjava.com/wp-content/themes/hybrid-news/images/sitelogo.png
。
您的图片存储在外部网站上。
通常使用Image
类从网站获取图像永远不是一个好主意,因为Image
类尝试多次读取图像的字节。至少读一次第一个字节以便检测图像类型(这将决定iText需要使用哪个图像类);至少一次加载特定图像类中的所有字节。
您的代码在本地计算机上而不是在您的服务器上运行的事实导致您认为您的本地计算机可以访问该站点,而您的服务器上可能存在限制。也许您的服务器无法访问您的图片所在的网站。在这种情况下,会抛出异常,这可能会导致PDF格式损坏。
或者可能只有部分图像是由必须处理PNG文件的特定图像类下载的。
如何解决这个问题?
将徽标放入罐子中并从该罐子中加载徽标。或者将徽标放在服务器上的文件系统上,然后从文件系统中读取它。或者首先在byte[]
中加载徽标,检查该字节数组是否实际包含有效图像,如果没有,则抛出异常并通知用户出现问题。
在评论中,您写道:当我通过main方法运行我的代码并在某个位置编写PDF时,一切正常。但是当我尝试通过在tomcat中运行我的代码来使用servlet下载文件时。它给了我错误。
正如mkl在对此评论的回复中所写,您应该更新您的问题。您问题中的示例代码看起来就像在磁盘上创建文件一样。编写Web应用程序时,这不是自定义的。在Web上下文中,您通常会在内存中生成PDF,然后按照问题How can I serve a PDF to a browser without storing a file on the server side?
的答案中的说明将其提供给浏览器请注意,此答案提供了一个简短的代码示例和一个长代码示例。也许您已经尝试过短代码示例,也许您已经遇到过问题,因为虽然简短示例中的代码应该可行,但并非所有浏览器都接受它。长版本适用于一些已知的浏览器问题:
public class PdfServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// Get the text that will be added to the PDF
String text = request.getParameter("text");
if (text == null || text.trim().length() == 0) {
text = "You didn't enter any text.";
}
// step 1
Document document = new Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos);
// step 3
document.open();
// step 4
document.add(new Paragraph(String.format(
"You have submitted the following text using the %s method:",
request.getMethod())));
document.add(new Paragraph(text));
// step 5
document.close();
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
}
catch(DocumentException e) {
throw new IOException(e.getMessage());
}
}
}
如果这不能回答您的问题,您必须提供更多信息。
我不知道你为什么要在浏览器上提供PDF服务时创建文件的原因,但如果是故意选择,我会使用这个:
File file = new File(new Random().nextInt(10000)+"_orders.pdf");
通过使用nextInt()
,我认为理论上可能两个不同的用户同时归属于同一个号码。这会引起问题。如果您想创建一个唯一的文件名,请不要使用Random
,但要创建一个唯一的文件名,如问题What is the best way to generate a unique and short file name in Java中所述
File file = File.createTempFile("order", ".pdf", new File("/user/vijay"));
当你在浏览器中正常下载时,我写下时,我真的不明白你的意思。但在Adobe Reader中打开时会出现问题。听起来好像PDF有一些被一些PDF查看器忽略的缺陷(如Firefox中的pdf.js,Chrome中的Chrome PDF Viewer,Safari中的预览,... )但这会在Adobe Reader中导致错误消息。您是否有机会使用古老的iText版本?您使用了哪个iText版本?