iText - HTML转PDF - 图片在PDF中未显示。

21

我有一个包含文本和图片的 HTML 页面,并将 HTML 内容解析为 iText 以生成 PDF。在生成的 PDF 中,包含的图片无法显示,只显示文本。

如果我传递绝对路径,例如 D:/Deiva/CRs/HTMLPage/article-101-horz.jpg,则可以打印出图片。但是,如果我尝试从服务器打印图像,例如:

http://localhost:8085/content/dam/article-101-h1.jpg 或 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中显示图像的解决方案。
谢谢提前。
Deiva
6个回答

4
以下是一些例子:https://developers.itextpdf.com/examples/xml-worker-itext5/html-images
htmlContext.setImageProvider(new AbstractImageProvider() {
    public String getImageRootPath() { return "src/main/resources/html/"; }
}); 

如果您要解析的HTML文件存储在与工作目录不同的目录中,iText 将无法创建图像对象。我们必须提供 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()方法未被实现。您必须自己实现它,就像下面的代码片段中所做的那样:

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

4

我认为您可以使用Servlet轻松查看图像。如何编写此Servlet,请在此处了解。

这里是一个样例调度程序供您参考。只需根据需要编辑必要的位置即可。

@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 - christopher
@Chris:我曾经遇到同样的问题,我是这样解决的。只是觉得这可能会对他有所帮助,:) - Sanjaya Liyanage
同意,但我设置了悬赏是因为这是一个在这里大多数人无法回答的问题,如果你想要这个悬赏,能否详细展示一下。 - christopher
嗨@SanjayaLiyanage,你能给我提供解决问题的代码吗?我的图像标签将是<img alt="" src="/testing/Image?imageId=9"/>,其中/testing/Image是我的servlet映射URL。我应该如何重新编写@RequestMapping(value="images/{imageId:.+}?这里的imageId值将会改变。我使用了上面的代码,但它不起作用。 - Sathesh S

3

要使用Itext显示图像,您需要更改有关图像提供程序的默认配置,如下所示: 我是从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项目。导入文件如下: - Abdourahmane FALL

1
尝试将图像放入内存或字节流对象中,然后将该图像对象转换为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

1
我也遇到了同样的问题,但是使用图片的绝对路径可以解决。似乎远程路径不起作用。我在文件系统的临时位置保存图像并生成PDF,最后从临时位置删除图像文件。
<img src="/home/jboss/temp/imgs/img.png"/>

0

我正在寻找相同的要求,以下是对我有效的内容:

        HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
        htmlContext.setImageProvider(new AbstractImageProvider() {
        public String getImageRootPath() {
            return null;
        }

        @Override
        public Image retrieve(String src) {
            try {
                Image img = com.itextpdf.text.Image.getInstance(new URL(src));
                return Image.getInstance(img);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    });

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