当前位置: 首页 > 知识库问答 >
问题:

使用iText将超文本标记语言转换为PDF

亢雅懿
2023-03-14

我之所以发布这个问题,是因为许多开发人员或多或少地以不同的形式问同一个问题。我会自己回答这个问题(我是iText Group的创始人/首席技术官),这样它就可以成为“维基答案”如果堆栈溢出的“文档”特性仍然存在,那么这将是文档主题的一个很好的候选者。

我正在尝试将以下HTML文件转换为PDF:

<html>
    <head>
        <title>Colossal (movie)</title>
        <style>
            .poster { width: 120px;float: right; }
            .director { font-style: italic; }
            .description { font-family: serif; }
            .imdb { font-size: 0.8em; }
            a { color: red; }
        </style>
    </head>
    <body>
        <img src="img/colossal.jpg" class="poster" />
        <h1>Colossal (2016)</h1>
        <div class="director">Directed by Nacho Vigalondo</div>
        <div class="description">Gloria is an out-of-work party girl
            forced to leave her life in New York City, and move back home.
            When reports surface that a giant creature is destroying Seoul,
            she gradually comes to the realization that she is somehow connected
            to this phenomenon.
        </div>
        <div class="imdb">Read more about this movie on
            <a href="www.imdb.com/title/tt4680182">IMDB</a>
        </div>
    </body>
</html>

在浏览器中,这种超文本标记语言如下所示:

HTMLWorker根本不考虑CSS

当我使用HTMLWorker时,我需要创建一个ImageProvider,以避免一个错误通知我找不到图像。我还需要创建一个样式表实例来更改一些样式:

public static class MyImageFactory implements ImageProvider {
    public Image getImage(String src, Map<String, String> h,
            ChainedProperties cprops, DocListener doc) {
        try {
            return Image.getInstance(
                String.format("resources/html/img/%s",
                    src.substring(src.lastIndexOf("/") + 1)));
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }    
}

public static void main(String[] args) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream("results/htmlworker.pdf"));
    document.open();
    StyleSheet styles = new StyleSheet();   
    styles.loadStyle("imdb", "size", "-3");
    HTMLWorker htmlWorker = new HTMLWorker(document, null, styles);
    HashMap<String,Object> providers = new HashMap<String, Object>();
    providers.put(HTMLWorker.IMG_PROVIDER, new MyImageFactory());
    htmlWorker.setProviders(providers);
    htmlWorker.parse(new FileReader("resources/html/sample.html"));
    document.close();   
}

结果如下:

出于某种原因,HTMLWorker也会显示

当我看我的代码时,我发现我使用的很多对象和方法都被弃用了:

所以我决定升级到使用XML Worker。

使用XML Worker时找不到图像

我尝试了以下代码:

public static final String DEST = "results/xmlworker1.pdf";
public static final String HTML = "resources/html/sample.html";
public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();
    XMLWorkerHelper.getInstance().parseXHtml(writer, document,
            new FileInputStream(HTML));
    document.close();
}

由此产生了以下PDF文件:

使用默认字体Helvetica而不是Times Roman;这是iText的典型情况(我应该在HTML中明确定义字体)。否则,CSS似乎受到尊重,但图像丢失,我没有收到错误消息。

使用HTMLWorker,引发了一个异常,我可以通过引入一个ImageProvider来解决这个问题。让我们看看这是否适用于XML Worker。

XML Worker并不支持所有CSS样式

我修改了我的代码如下:

public static final String DEST = "results/xmlworker2.pdf";
public static final String HTML = "resources/html/sample.html";
public static final String IMG_PATH = "resources/html/";
public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();

    CSSResolver cssResolver =
            XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
    HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
    htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
    htmlContext.setImageProvider(new AbstractImageProvider() {
        public String getImageRootPath() {
            return IMG_PATH;
        }
    });

    PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
    HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
    CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

    XMLWorker worker = new XMLWorker(css, true);
    XMLParser p = new XMLParser(worker);
    p.parse(new FileInputStream(HTML));

    document.close();
}

我的代码要长得多,但现在图像呈现:

图像比我使用HTMLWorker渲染时大,这告诉我poster类的CSS属性width已被考虑,但float属性被忽略。我该怎么解决这个问题?

所以问题归结为:我有一个特定的HTML文件,我试图转换成PDF。我已经做了很多工作,解决了一个又一个问题,但有一个具体的问题我无法解决:如何使iText尊重定义元素位置的CSS,例如float:right

当我的HTML包含表单元素时(例如


共有3个答案

潘学民
2023-03-14

转换静态超文本标记语言页面,也可使用任何CSS样式:

 HtmlConverter.convertToPdf(new File("./pdf-input.html"),new File("demo-html.pdf"));

对于spring Boot用户:使用SpringBoot和Thymeleaf转换动态HTML页面:

    @RequestMapping(path = "/pdf")
    public ResponseEntity<?> getPDF(HttpServletRequest request, HttpServletResponse response) throws IOException {
    /* Do Business Logic*/

    Order order = OrderHelper.getOrder();

    /* Create HTML using Thymeleaf template Engine */

    WebContext context = new WebContext(request, response, servletContext);
    context.setVariable("orderEntry", order);
    String orderHtml = templateEngine.process("order", context);

    /* Setup Source and target I/O streams */

    ByteArrayOutputStream target = new ByteArrayOutputStream();
    ConverterProperties converterProperties = new ConverterProperties();
    converterProperties.setBaseUri("http://localhost:8080");
    /* Call convert method */
    HtmlConverter.convertToPdf(orderHtml, target, converterProperties);

    /* extract output as bytes */
    byte[] bytes = target.toByteArray();


    /* Send the response as downloadable PDF */

    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=order.pdf")
            .contentType(MediaType.APPLICATION_PDF)
            .body(bytes);

}
祁承嗣
2023-03-14

使用iText 7和以下代码:

public void generatePDF(String htmlFile) {
    try {

        //HTML String
        String htmlString = htmlFile;
        //Setting destination 
        FileOutputStream fileOutputStream = new FileOutputStream(new File(dirPath + "/USER-16-PF-Report.pdf"));
        
        PdfWriter pdfWriter = new PdfWriter(fileOutputStream);
        ConverterProperties converterProperties = new ConverterProperties();
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);

        //For setting the PAGE SIZE
        pdfDocument.setDefaultPageSize(new PageSize(PageSize.A3));
        
        Document document = HtmlConverter.convertToDocument(htmlFile, pdfDocument, converterProperties);
        document.close();
    } 
    catch (Exception e) {
         e.printStackTrace();
    }
}
栾鸣
2023-03-14

正如在超文本标记语言到PDF教程的介绍中所解释的,HTMLWorker多年前就被弃用了。它不打算转换完整的超文本标记语言页面。它不知道超文本标记语言页面有一个

然后是XML工作者。XML Worker是用来解析XML的通用框架。作为概念证明,我们决定编写一些XHTML到PDF的功能,但我们不支持所有的HTML标记。例如:表单根本不受支持,而且很难支持用于定位内容的CSS。HTML格式的表单与PDF格式的表单非常不同。iText架构和HTML CSS架构之间也存在不匹配。渐渐地,我们扩展了XML Worker,主要是基于客户的请求,但XML Worker变成了一个有很多触角的怪物。

最终,我们决定从头开始重写iText,同时考虑到超文本标记语言CSS转换的要求。这导致了iText 7。在iText 7的基础上,我们创建了几个附加组件,在这个上下文中最重要的是pdfHTML。

使用最新版本的iText(iText 7.1.0 pdfHTML 2.0.0)将超文本标记语言从问题转换为PDF的代码简化为以下片段:

public static final String SRC = "src/main/resources/html/sample.html";
public static final String DEST = "target/results/sample.pdf";
public void createPdf(String src, String dest) throws IOException {
    HtmlConverter.convertToPdf(new File(src), new File(dest));
}

结果如下:

正如你所看到的,这几乎是你所期望的结果。由于iText 7.1.0/PDFHTML2.0.0,默认字体为Times Roman。CSS受到尊重:图像现在漂浮在右侧。

当我建议升级到iText 7/pdfHTML 2时,开发人员通常会反对升级到更新的iText版本。请允许我回答我听到的前三个论点:

我需要使用免费的iText,而iText 7不是免费的/pdfHTML插件是封闭源代码的。

iText 7是使用AGPL发布的,就像iText 5和XML Worker一样。AGPL允许在开源项目中免费使用。如果您正在分发封闭源代码/专有产品(例如,您在SaaS环境中使用iText),则不能免费使用iText;在这种情况下,你必须购买商业许可证。iText 5已经是这样了;对于iText 7来说仍然如此。至于iText 5之前的版本:你根本不应该使用这些。关于pdfHTML:第一个版本实际上只作为封闭源代码软件提供。我们在iText Group内部进行了激烈的讨论:一方面,有些人希望避免公司大规模滥用资源,因为当这些开发人员告诉他们,开源与免费不一样时,他们不听开发人员的话。开发商告诉我们,他们的老板强迫他们做错事,他们无法说服老板购买商业许可证。另一方面,有人认为我们不应该因为开发人员的老板的错误行为而惩罚他们。最终,支持开源pdfHTML的人,即iText的开发者赢得了这场辩论。请证明他们没有错,并正确使用iText:如果您免费使用iText,请尊重AGPL;如果您在封闭源代码环境中使用iText,请确保您的老板购买了商业许可证。

我需要维护一个遗留系统,我必须使用旧的iText版本。

认真地维护还包括应用升级和迁移到正在使用的软件的新版本。如您所见,使用iText 7和pdfHTML时所需的代码非常简单,并且比以前所需的代码更不容易出错。迁移项目不应该花费太长时间。

我才刚刚开始,不知道iText 7;我是在完成我的项目后才发现的。

这就是为什么我要发布这个问题和答案。把你自己想象成一个极限程序员。扔掉你所有的代码,重新开始。你会注意到它没有你想象的那么多工作,你会睡得更好,因为你已经让你的项目经得起未来的考验,因为iText 5正在被淘汰。我们仍然为付费客户提供支持,但最终,我们将完全停止支持iText 5。

 类似资料:
  • 我将html表格从网页复制到excel,并尝试使用下面的代码,但没有结果。请就如何解决这个问题提出建议。我做了所有的实验,但没有得到正确的结果。

  • 我正在尝试使用BeautifulSoup转换HTML文本块。以下是一个示例: 我试着做了这样的事情: ...但是这样我的span元素总是在新行上。这当然是一个简单的例子。有没有办法在超文本标记语言页面中获取文本,就像它在浏览器中呈现的方式一样(不需要css规则,只是div、spans、li等元素呈现的常规方式)在Python中?

  • 旧标题:iTextSharp将HTML转换为PDF“文档没有页面” 我正在使用iTextSharp和xmlworker在ASP中将html从视图转换为PDF。净核心2.1 我尝试了网上找到的许多代码片段,但都生成了一个异常:“文档没有页面。” 以下是我目前的代码: 更新1 多亏了@Bruno Lowagie的建议,我升级到了iText7和pdfHTML,但我找不到太多关于它的教程。 我试过这个代码

  • 我正在开发一个asp。net mvc项目,我正在使用一个html模板生成一个带有动态数据的发票文档,由于Handlebar,我填充了这些数据。生成的html通过使用iText 7转换为PDF,因为这是公司使用to所需的工具,但是我在将其转换为PDF时遇到了一个问题,因为html表显示数据,有时有足够的数据只适合一个页面,但在其他情况下,有许多行在分页符中相交,跨两个页面打印数据。每当数据不适合一页

  • 对于上面的html内容,我如何使用Jsoup解析并获取文本 当我使用 我得到了这样的东西

  • 我是新来的。我想解析html,但问题是我们必须在中指定的URL,我将在运行时从其他页面响应此URL。有没有办法将收到的网址传递到中?我读过这样的东西: 但是我不知道如何使用它。我很想知道是否有其他方法比jsoup更好。