【问题标题】:iText – HTML to PDF - Image is not displayed in PDFiText – HTML 到 PDF – 图像不显示在 PDF 中
【发布时间】:2013-02-22 19:31:06
【问题描述】:

我有一个包含文本、图像的 html 页面,我正在将 HTML 内容解析为 iText 以生成 PDF。在生成的 PDF 中,未显示包含的图像,并且仅显示文本。

如果我通过像 D:/Deiva/CRs/HTMLPage/article-101-horz.jpg 这样的绝对路径,则图像将被打印。但是,如果我尝试从服务器打印图像,例如

http://localhost:8085/content/dam/article-101-h1.jpg or http://www.google.co.in/intl/en_ALL/images/logos/images_logo_lg.gif

那么它不会在 PDF 中打印出来。

注意:我正在使用 itextpdf-5.2.1.jar 来生成 PDF。

我的 HTML 代码(Article.html):

<html>
   <head>
   </head>
   <body>   
     <p>Generate PDF with image using iText.</p>
     <img src="http://localhost:8085/content/dam/article-10-h1.jpg"></img>
     <img src="http://www.google.co.in/intl/en_ALL/images/logos/imgs_logo_lg.gif"></img>
     <img class="right horz" src="D:/Deiva/CRs/HTMLPage/article-101-horz.jpg"></img>
   </body>
</html>

我正在使用以下 java 代码生成 PDF:

private void createPDF (){

  String path = "D:/Deiva/Test.pdf";
  PdfWriter pdfWriter = null;

  //create a new document
  Document document = new Document();

  try {

   //get Instance of the PDFWriter
   pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(path));

   //document header attributes
   document.addAuthor("betterThanZero");
   document.addCreationDate();
   document.addProducer();
   document.addCreator("MySampleCode.com");
   document.addTitle("Demo for iText XMLWorker");
   document.setPageSize(PageSize.LETTER);

   //open document
   document.open();
   InputStream is = new             FileInputStream("D:/Deiva/CRs/Oncology/Phase5/CR1/HTMLPage/Article.html");

   // create new input stream reader
   InputStreamReader isr = new InputStreamReader(is);

   //get the XMLWorkerHelper Instance
   XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
   //convert to PDF
   worker.parseXHtml(pdfWriter, document, isr);

   //close the document
   document.close();
   //close the writer
   pdfWriter.close();

  } catch (Exception e) {
      e.printStackTrace();
  }

 }

请提出以 PDF 格式显示图像的解决方案。

提前致谢。

天神

【问题讨论】:

    标签: java itextsharp itext relative-path html-to-pdf


    【解决方案1】:

    这里有一些例子:https://developers.itextpdf.com/examples/xml-worker-itext5/html-images

    htmlContext.setImageProvider(new AbstractImageProvider() {
        public String getImageRootPath() { return "src/main/resources/html/"; }
    }); 
    

    如果您正在解析的 HTML 文件存储在与工作目录不同的目录中,iText 将无法创建 Image 对象。我们必须提供一个 ImageProvider 接口的实现,告诉 iText 如果遇到 img 标签该怎么做。该接口有以下方法:

    Image retrieve(final String src);
    String getImageRootPath();
    void store(String src, Image img);
    void reset();
    

    您可以编写自己的类来实现这四个方法,也可以将 AbstractImageProvider 子类化。最好采用后者。 XML Worker 将使用 AbstractImageProvider 类的 store() 方法来缓存 Map 中遇到的所有 Image 对象。当为具有相同 src 的图像调用 retrieve() 方法时,这些对象将被重用。如果您不缓存图像,您的 PDF 将变得臃肿。相同的图像位和字节将多次写入 PDF。 reset() 方法清除缓存;它在 ImageProvider 被克隆时使用。最后,没有实现 getImageRootPath() 方法。

    如果您正在解析的 HTML 文件存储在与工作目录不同的目录中,iText 将无法创建 Image 对象。我们必须提供一个 ImageProvider 接口的实现,告诉 iText 如果遇到 img 标签该怎么做。该接口有以下方法:

    您可以编写自己的类来实现这四个方法,也可以将 AbstractImageProvider 子类化。最好采用后者。 XML Worker 将使用 AbstractImageProvider 类的 store() 方法来缓存 Map 中遇到的所有 Image 对象。当为具有相同 src 的图像调用 retrieve() 方法时,这些对象将被重用。如果您不缓存图像,您的 PDF 将变得臃肿。相同的图像位和字节将多次写入 PDF。 reset() 方法清除缓存;它在 ImageProvider 被克隆时使用。最后,没有实现 getImageRootPath() 方法。您必须自己实现它,就像在下面的 sn-p 中所做的那样:

    【讨论】:

    • htmlContext.setImageProvider(new AbstractImageProvider() { public String getImageRootPath() { return "src/main/resources/html/"; } });
    【解决方案2】:

    要使用 Itext 显示图像,您必须更改有关 Image Provider 的默认配置 Like it : 我是从http://demo.itextsupport.com/xmlworker/itextdoc/flatsite.html做的

    public class HtmlToPDF1 {
      public static void main(String ... args ) throws DocumentException, IOException {    
    
          FontFactory.registerDirectories();
          Document document = new Document();
          PdfWriter writer = PdfWriter.getInstance(document,
              new FileOutputStream("src/test/ressources/mypdf.pdf"));
          document.open(); HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
          htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
          htmlContext.setImageProvider(new AbstractImageProvider() {
              public String getImageRootPath() {
                  return "/home/fallphenix/workspace/JAVA/JEE/testHTMLtoPDF/src/test/ressources/";
              }
          }); CSSResolver cssResolver =
                XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
            Pipeline<?> pipeline =
                new CssResolverPipeline(cssResolver,
                        new HtmlPipeline(htmlContext,
                            new PdfWriterPipeline(document, writer)));
            XMLWorker worker = new XMLWorker(pipeline, true);
            XMLParser p = new XMLParser(worker);
            p.parse(new FileInputStream("src/test/ressources/other.html"));
            document.close();
              System.out.println("Done.");        
        }}
    

    【讨论】:

    • 我使用 maven 项目。像这样的导入文件
    【解决方案3】:

    我也遇到了同样的问题..

    但它正在使用图像绝对路径。它似乎不适用于远程路径。 id在这里所做的是将图像保存在文件系统的临时位置并生成pdf,最后从临时位置删除图像文件。

    <img src="/home/jboss/temp/imgs/img.png"/>
    

    【讨论】:

      【解决方案4】:

      尝试将图像放入内存或字节流对象,然后将该图像对象转换为 itextsharp 图像。

      探索iTextSharp.text.Image的重载

      编辑:

      虽然代码是用 C# 编写的,但它可能会对您有所帮助。

      从本地驱动器获取图像:

      Bitmap image1;
      image1 = new Bitmap(@"C:\Documents and Settings\All Users\" 
                  + @"Documents\My Music\music.jpeg", true);
      

      注意::如果您的应用程序文件夹中有图像,那么我们有一些函数可以在 C# 中获取它们的本地文件路径。不知道Java。来自外部网站的图片可以下载为

      System.Net.WebClient client = new WebClient();
      client.DownloadFile(imageURL, localPathname);   // look into java to get local path
      

      现在将此字节流转换为图像对象

      MemoryStream imgMemoryStream = new MemoryStream(imgByteArray);
      Image myImage = Drawing.Image.FromStream(imgMemoryStream);
      

      现在从它创建一个 iTextSharp 图像对象并将其添加到您的文档中

      iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(myImage, System.Drawing.Imaging.ImageFormat.Jpeg);
      document.Add(pic);
      

      希望对你有所帮助。

      【讨论】:

      • 嗨 Saksham,感谢您的回复,您有 java 中的示例代码吗?如果你有那么请分享代码。它将帮助我尽快完成这项任务。
      • @Deiva 希望对您有所帮助。
      【解决方案5】:

      我认为您可以轻松地使用 Servlet 来查看图像。如何为此编写一个 servlet 是 here

      这是为您准备的示例调度程序。只需根据需要编辑所需的位置

      @Controller
      public class ImageController extends DispatcherServlet {
      
      
      
          private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
      
          // Properties ---------------------------------------------------------------------------------
      
          private String imagePath;
      
         @RequestMapping(value="images/{imageId:.+}", method = RequestMethod.GET)
         public @ResponseBody void getImage(@PathVariable String imageId,HttpServletRequest request, HttpServletResponse response){
              String requestedImage = request.getPathInfo();
               this.imagePath ="image path in server here";
      
               if (requestedImage == null) {
                   // Do your thing if the image is not supplied to the request URI.
                   // Throw an exception, or send 404, or show default/warning image, or just ignore it.
                   try {
                      response.sendError(HttpServletResponse.SC_NOT_FOUND);
                   }catch(IOException ioException){
                      logger.error("error image path incorrect:{}", ioException);
      
                  } // 404.
                   return;
               }
      
               File image=null;
              try {
                  image = new File(imagePath, URLDecoder.decode(imageId, "UTF-8"));
              } catch (UnsupportedEncodingException unsupportedEncodingException) {
                  logger.error("error image can not decode:{}", unsupportedEncodingException);
      
              }
      
               // Check if file actually exists in filesystem.
               if (!image.exists()) {
                   // Do your thing if the file appears to be non-existing.
                   // Throw an exception, or send 404, or show default/warning image, or just ignore it.
                   try {
                      response.sendError(HttpServletResponse.SC_NOT_FOUND);
                   }catch(IOException ioException){
                      logger.error("error image does not exists:{}", ioException);
      
                  } // 404.
                   return;
               }
      
               // Get content type by filename.
               String contentType = "jpeg";
               contentType="image/"+contentType;
      
               // Init servlet response.
               response.reset();
               response.setBufferSize(DEFAULT_BUFFER_SIZE);
               response.setContentType(contentType);
               response.setHeader("Content-Length", String.valueOf(image.length()));
               response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
      
               // Prepare streams.
               BufferedInputStream input = null;
               BufferedOutputStream output = null;
      
               try {
                   // Open streams.
                   try {
                      input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
                  } catch (FileNotFoundException e) {
      
                      logger.error("error creating file input stream to the image file :{}", e);
      
      
                  }
                   try {
      
                       output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
      
                  } catch (IOException e) {
      
      
                      logger.error("error creating output stream to the http response :{}", e);
      
                  }
      
                   // Write file contents to response.
                   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
                   int length;
                   try {
                      while ((length = input.read(buffer)) > 0) {
                           output.write(buffer, 0, length);
                       }
                  } catch (IOException e) {
      
                      logger.error("error writing the image file to outputstream :{}", e);
      
                  }
               } finally {
                   // Gently close streams.
                   close(output);
                   close(input);
               }
           }
      
           // Helpers (can be refactored to public utility class) ----------------------------------------
      
      
      
      
      private  void close(Closeable resource) {
          if (resource != null) {
              try {
                  resource.close();
              } catch (IOException e) {
                  // Do your thing with the exception. Print it, log it or mail it.
                  logger.error("error closing resources:{}", e);
              }
          }
      }
      
      
      
      
      }
      

      【讨论】:

      • 这甚至不是一个可行的答案!来吧,例如,参考等! :D
      • @Chris :我遇到了同样的问题并以这种方式实现了它。只是认为它会帮助他,:)
      • 同意,但我设置了赏金,因为这是一个在这里基本上没有得到解答的问题,如果你想要赏金,你能更详细地展示它吗?
      • 嗨@SanjayaLiyanage 你能为我的问题提供代码吗?我的图像标记将是 &lt;img alt="" src="/testing/Image?imageId=9"/&gt; 其中 /testing/Image 是我的 servlet 映射 URL。我应该如何重写@RequestMapping(value="images/{imageId:.+} 这里的 imageId 值会发生变化。我使用了上面的代码,但它不起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多