`
downpour
  • 浏览: 716099 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
00a07ae5-264f-3774-8903-8ad88ce08cb0
Struts2技术内幕
浏览量:117508
4d8508f2-c0dd-3df8-9483-04cc612afbbc
SpringMVC深度探险...
浏览量:230425
社区版块
存档分类
最新评论

介绍一个PDF的生成方案

    博客分类:
  • Java
阅读更多
在Java世界,要想生成PDF,方案不少。最近一直在和这个东西打交道,所以简单做一个小结吧。

在此之前,先来勾画一下我心中比较理想的一个解决方案。在企业应用中,碰到的比较多的PDF的需求,可能是针对某个比较典型的具备文档特性的内容,导出成为PDF进行存档。由于我们现在往往使用一些开源框架,诸如ssh来构建我们的应用,所以我们相对熟悉的方案是针对具体的业务逻辑设计实体,使用开源框架来实现我们的业务逻辑。而PDF的导出,最好不要破坏现有的程序框架,甚至能复用我们业务逻辑层的代码。因为如果把PDF作为一种特殊的表现形式的话,实际上它有点类似模板。最佳的情况,是我们能够通过编写某种模板,把PDF的大概样子确定下来,然后把数据和模板做一次整合,得到最后的结果

带着这个目标,开始在网上搜索解决方案。也找到了一些方案,下面简单小结一下:

Jasper Report

看到的市面上采用的最多的方案,是Jasper Report。相关的文档也很多,不过很杂,需要完全掌握,我认为还是有些坡度和时间的。这个时间和坡度我认为主要来自于对iReport这个IDE的反复尝试,对里面的每个属性的摸索。

Jasper Report的设计思路,本身是不违反我上面所说的初衷的。因为我们的努力方向是先生成模板,然后得到数据,最后将两者整合得到结果。但是Jasper Report的问题在于,其生成模板的方式过于复杂,即使有IDE的帮助,我们还是需要对其中的众多规则有所了解才行,否则就会给调试带来极大的麻烦。

所以,我认为Jasper Report是一个半调子方案,这种强依赖于IDE进行可视化编辑的方式令我很不爽。同时,由此带来的诸多的限制,相信也让很多使用者颇为头疼。在经历了一番痛苦的挣扎后,决定放弃使用这种方案。

iText

其实Jasper Report是基于iText的。于是有的人会说,那么直接使用iText不是一种倒退么?的确,直接使用iText似乎就需要直接使用原生的API进行编程了。不过幸好iText其实提供了一些方便的API,通过使用这些API,我们可以直接将HTML代码转化成iText可识别的Document对象,从而导出PDF文档。

import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList;

import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.html.simpleparser.StyleSheet;
import com.lowagie.text.pdf.PdfWriter;

public class MainClass {
  public static void main(String[] args) throws Exception {
    Document document = new Document();
    StyleSheet st = new StyleSheet();
    st.loadTagStyle("body", "leading", "16,0");
    PdfWriter.getInstance(document, new FileOutputStream("html2.pdf"));
    document.open();
    ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st);
    for (int k = 0; k < p.size(); ++k)
      document.add((Element) p.get(k));
    document.close();
  }
}


这是从网上找到的一个例子。从代码中,我们可以看到,iText本身提供了一个简单的HTML的解析器,它可以把HTML转化成我们需要的PDF的document。

有了这个东西,基本上我的目标就能达成一大半了。接下来我的任务就是根据实际情况去编写HTML代码,然后扔进这个方法,就OK了。而真正的HTML代码,我们则可以在这里使用真正的模板技术,Freemarker或者Velocity去生成我们所需要的内容。当然,这已经是我们熟门熟路的东西了。

正当我觉得这个方案基本能符合我的要求的时候,我也同样找到了它的很多弱项:

1. 无法识别很多HTML的tag和attribute(应该是iText的HTMLParser不够强大)
2. 无法识别CSS

如果说第一点我还可以勉强接受的话,那么第二点我就完全不能接受了。无法识别简单的CSS,就意味着HTML失去了最基本的活力,也无法根据实际要求调整样式。

所以这种方案也必然无法成为我的方案。

flying sauser

在这种情况下,我几乎已经燃起了自己编写一个支持CSS解析的HTML Parser的想法。幸好,在一个非常偶然的情况下,我在google中搜到了这样一个开源项目,它能够满足我的一切需求。这就是flying sauser,项目主页是:https://xhtmlrenderer.dev.java.net/

项目的首页非常吸引人:An XML/XHTML/CSS 2.1 Renderer。这不正是我要的东西么?

仔细再看里面的文档:

引用
Flying Saucer is an XML/CSS renderer, which means it takes XML files as input, applies formatting and styling using CSS, and generates a rendered representation of that XML as output. The output may go to the screen (in a GUI), to an image, or to a PDF file. Because we believe most people will be interested in re-using their knowledge of web layout, our main target for content is XHTML 1.0 (strict), an XML document format that standardizes HTML.


完美了。这东西能解析HTML和CSS,而且能输出成image,PDF等格式。哇!我们来看看sample代码(代码丑陋,不过已经能说明问题了):

/* 
* ITextRendererTest.java * 
* Copyright 2009 Shanghai TuDou.  
* All rights reserved. 
*/

package itext;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import com.lowagie.text.pdf.BaseFont;

/** 
 * TODO class description * 
 *
 * @author pcwang
 *
 * @version 1.0, 上午11:03:26  create $Id$
 */
public class ITextRendererTest {
	public static void main(String[] args) throws Exception {
		String inputFile = "conf/template/test.html";
        String url = new File(inputFile).toURI().toURL().toString();
        String outputFile = "firstdoc.pdf";
        OutputStream os = new FileOutputStream(outputFile);
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(url);

        // 解决中文支持问题
        ITextFontResolver fontResolver = renderer.getFontResolver();
        fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

        // 解决图片的相对路径问题
        renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");
        
        renderer.layout();
        renderer.createPDF(os);
        
        os.close();
	}
}


运行,成功!实在太简单了!API帮你完成了一切!

有了这个东西,我们就可以将PDF的生成流程变成这样:

1) 编写Freemarker或者Velocity模板,打造HTML,勾画PDF的样式(请任意使用CSS)

2) 在你的业务逻辑层引入Freemarker的引擎或者Velocity的引擎,并将业务逻辑层中可以获取的数据和模板,使用引擎生成最终的内容

3) 将我上面的sample代码做简单封装后,调用,生成PDF

这样,我想作为一个web程序员来说,上面的3点,都不会成为你的绊脚石。你可以轻松驾驭PDF了。

在Flying Saucer的官方文档中,有一些Q&A,可以解决读者们大部分的问题。包括PDF的字体、PDF的格式、Image如何处理等等。大家可以尝试着去阅读。

还有一篇文章,好像是作者写的,非常不错:http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html
分享到:
评论
102 楼 xcloudy 2010-08-12  

非常感谢yye_javaeye中文换行的代码,我参照代码修改后确实有效了。不过在yye_javaeye贴的代码里有一个bug会导致死循环,在110和122行处,应该改成
 int right = getStrRight(currentString, left + 1);

关键是left+1,如果写成left的话会导致永远对同一处的字符进行判断而导致死循环。

yye_javaeye 写道

呵呵,没注意到这个帖子,当时因为项目正着急,忘了贴上来了
修改了org.xhtmlrenderer.layout.Breaker类,添加了2个方法,修改了109行和121行,由原来的按空格分组改为调用getStrRight按新的方式分组来获取字符的右边界值:
/*
 * Breaker.java
 * Copyright (c) 2004, 2005 Torbj�rn Gannholm, 
 * Copyright (c) 2005 Wisconsin Court System
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */
package org.xhtmlrenderer.layout;

import org.xhtmlrenderer.css.constants.IdentValue;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.render.FSFont;

/**
 * A utility class that scans the text of a single inline box, looking for the 
 * next break point.
 * @author Torbj�rn Gannholm
 */
public class Breaker {

    public static void breakFirstLetter(LayoutContext c, LineBreakContext context,
            int avail, CalculatedStyle style) {
        FSFont font = style.getFSFont(c);
        context.setEnd(getFirstLetterEnd(context.getMaster(), context.getStart()));
        context.setWidth(c.getTextRenderer().getWidth(
                c.getFontContext(), font, context.getCalculatedSubstring()));
        
        if (context.getWidth() > avail) {
            context.setNeedsNewLine(true);
            context.setUnbreakable(true);
        }
    }
    
    private static int getFirstLetterEnd(String text, int start) {
        int i = start;
        while (i < text.length()) {
            char c = text.charAt(i);
            int type = Character.getType(c);
            if (type == Character.START_PUNCTUATION || 
                    type == Character.END_PUNCTUATION ||
                    type == Character.INITIAL_QUOTE_PUNCTUATION ||
                    type == Character.FINAL_QUOTE_PUNCTUATION ||
                    type == Character.OTHER_PUNCTUATION) {
                i++;
            } else {
                break;
            }
        }
        if (i < text.length()) {
            i++;
        }
        return i;
    }    
    
    public static void breakText(LayoutContext c, 
            LineBreakContext context, int avail, CalculatedStyle style) {
        FSFont font = style.getFSFont(c);
        IdentValue whitespace = style.getWhitespace();
        
        // ====== handle nowrap
        if (whitespace == IdentValue.NOWRAP) {
        	context.setEnd(context.getLast());
        	context.setWidth(c.getTextRenderer().getWidth(
                    c.getFontContext(), font, context.getCalculatedSubstring()));
            return;
        }

        //check if we should break on the next newline
        if (whitespace == IdentValue.PRE ||
                whitespace == IdentValue.PRE_WRAP ||
                whitespace == IdentValue.PRE_LINE) {
            int n = context.getStartSubstring().indexOf(WhitespaceStripper.EOL);
            if (n > -1) {
                context.setEnd(context.getStart() + n + 1);
                context.setWidth(c.getTextRenderer().getWidth(
                        c.getFontContext(), font, context.getCalculatedSubstring()));
                context.setNeedsNewLine(true);
                context.setEndsOnNL(true);
            } else if (whitespace == IdentValue.PRE) {
            	context.setEnd(context.getLast());
                context.setWidth(c.getTextRenderer().getWidth(
                        c.getFontContext(), font, context.getCalculatedSubstring()));  
            }
        }

        //check if we may wrap
        if (whitespace == IdentValue.PRE || 
                (context.isNeedsNewLine() && context.getWidth() <= avail)) {
            return;
        }
        
        context.setEndsOnNL(false);

        String currentString = context.getStartSubstring();
        int left = 0;
//        int right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1);
        int right = getStrRight(currentString,left);
        int lastWrap = 0;
        int graphicsLength = 0;
        int lastGraphicsLength = 0;

        while (right > 0 && graphicsLength <= avail) {
            lastGraphicsLength = graphicsLength;
            graphicsLength += c.getTextRenderer().getWidth(
                    c.getFontContext(), font, currentString.substring(left, right));
            lastWrap = left;
            left = right;
//            right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1);
            right = getStrRight(currentString,left+1);
        }

        if (graphicsLength <= avail) {
            //try for the last bit too!
            lastWrap = left;
            lastGraphicsLength = graphicsLength;
            graphicsLength += c.getTextRenderer().getWidth(
                    c.getFontContext(), font, currentString.substring(left));
        }

        if (graphicsLength <= avail) {
            context.setWidth(graphicsLength);
            context.setEnd(context.getMaster().length());
            //It fit!
            return;
        }
        
        context.setNeedsNewLine(true);

        if (lastWrap != 0) {//found a place to wrap
            context.setEnd(context.getStart() + lastWrap);
            context.setWidth(lastGraphicsLength);
        } else {//unbreakable string
            if (left == 0) {
                left = currentString.length();
            }
            
            context.setEnd(context.getStart() + left);
            context.setUnbreakable(true);
            
            if (left == currentString.length()) {
                context.setWidth(c.getTextRenderer().getWidth(
                        c.getFontContext(), font, context.getCalculatedSubstring()));
            } else {
                context.setWidth(graphicsLength);
            }
        }
        return;
    }

    private static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
            return true;
        }
        return false;
    }

    private static int getStrRight(String s,int left){
        if(left>=s.length())
            return -1;
        char[] ch = s.toCharArray();
        for(int i = left;i<ch.length;i++){
            if(isChinese(ch[i]) || ' ' == ch[i]){
                return i==0?i+1:i;
            }
        }
        return -1;
    }

}

101 楼 flyslowfood 2010-07-24  
中文好像不能bold, 谁有办法解决一下 ? 谢谢
100 楼 qgm168 2010-07-15  
最新发现!!!
如果修改中文显示问题中文换行就不行了(前提是不设置中文字体)。
try {  
            cb.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), _font.getSize2D()/_dotsPerPoint);  
        } catch (Exception e) {  
            System.out.println("ITextOutputDevice.java drawString方法字体设置错误!");  
            e.printStackTrace();
        }
想换行必须加上这个
ITextFontResolver fontResolver = renderer.getFontResolver();  
fontResolver.addFont("C:\\Windows\\Fonts\\simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);  
99 楼 lance_luo 2010-07-01  
我的pdf文档中有一张表格和其它一些信息,想要的分页效果是,只自适应将表格数据进行分页,其它信息都相同。
98 楼 lance_luo 2010-07-01  
先谢谢各位,这正是我想在寻找的方案,但是在分页的时候我有一个困境,能否提供一个简单分页的例子吗?或者提供一下思路。

另外,提醒一下,如果替换了  yye_javaeye  提供的jar包,还不能实现中文换行,可能是因为项目中存在core-renderer-minimal.jar包冲突,删除它就可以了。
97 楼 lei_huf 2010-05-10  
  不错,正需要这个,谢了
96 楼 java10000 2010-05-01  
楼上那个url带参数的问题解决没??
呵呵
解决的话,能否告诉一下
还有一个问题,不是html页面是jsp页面怎么办?
盼答复,谢谢!
95 楼 zjh0207 2010-04-20  
flying sauser怎么解析页面中带参数的url,如 ?DOWNWJFILE&ID=&WJMC=11;
他会提示The entity name must immediately follow the '&' in the entity reference,他把&后面的当成一个实体了,怎么办?
94 楼 water_mys 2010-03-14  
<p><span style="color: #0000ff; font-size: medium;">大家讨论了这么久怎么没见人问过关于从XHTML转成PDF的目录生成的问题呀?就是类似word的文档目录,一是方便了解各章节的内容,二是点击后可以快速定位到某个章节。因为我们项目需要把客户通过我们web系统在线编辑的内容</span><span style="color: #0000ff; font-size: medium;">生成PDF报告</span><span style="color: #0000ff; font-size: medium;">(</span><span style="color: #0000ff; font-size: medium;">章节结构是</span><span style="color: #0000ff; font-size: medium;">事先定义好的模板,各节的内容通过FCK来编辑),这个报告可能会有几十上百页。</span></p>
<p> </p>
93 楼 zhangqh_zz 2010-02-03  
textarea中的内容需要将\r\n 或\n替换成<br />
但是自动换行的内容在PDF中不能自动换,谁有办法解决一下
92 楼 zhangqh_zz 2010-02-03  
好了,
谢谢 yye_javaeye 

在用textarea的table中加入
style="table-layout:fixed; word-break:break-strict;">  
或在table中加入style="table-layout:fixed“
在textarea中在用style="word-wrap:break-word;“等也可以换行 
关键是table要用样式table-layout:fixed; 然后用强制换行样式
91 楼 zhangqh_zz 2010-02-03  
我用了你的包,有内容在textarea中,也不换行,晕倒
90 楼 yye_javaeye 2010-01-31  
l116116116 写道
使用了 yye_javaeye 兄台的改进包 发现还是中文没有分行的 是不是没有注意到


table width="100%" border="1" cellspacing="0" cellpadding="0" style="table-layout:fixed; word-break:break-strict;">  

很多时候,table里面的东东不换行,最近项目忙,没时间仔细弄了,我现在的报表页面基本都让制作用css写了
89 楼 alin_ass 2010-01-29  
推荐一个方案,当然使用场景比较受限
使用googlecodewiki来编写pdf文档 :
http://www.iteye.com/forums/39/topics/581933
88 楼 raykou 2010-01-29  
lookdd1 写道
yye_javaeye 写道
中文换行问题解决了,这东西源码里面是将英文按空格分组,每组判断其位置+长度是否超出边界,超出的话将该组丢到下一行,但是中文里面基本没有空格,所以就无奈了。
将其源码改了改,如果是中文,每字一组,如果是英文,还是按照空格分组,这样大概效率会受一些影响,不过好歹是可以用了,而且一般pdf生成我想应该也不会放在需要大访问量的地方吧。附件是打好包的jar,覆盖就可以了


我用的你的包,可是不管用啊。全是中文,仍然没有换行。。


有一個workaround可以不用修改jar, 只要在每一個字母之間加入一個<wbr/>就可以斷行
hope this help.
87 楼 l116116116 2010-01-29  
使用了 yye_javaeye 兄台的改进包 发现还是中文没有分行的 是不是没有注意到


table width="100%" border="1" cellspacing="0" cellpadding="0" style="table-layout:fixed; word-break:break-strict;">  
86 楼 l116116116 2010-01-29  
项目接近尾声,再次感谢downpour 和 yye_javaeye  两位兄台。
85 楼 l116116116 2010-01-29  
zjh0207 写道
downpour,你下面代码中的那个url,具体是什么啊?
// 解决图片的相对路径问题  
        renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");  
大家谁有好的方案,解决这带图片的html转pdf的问题


项目过程中使用过以下方法:

1。直接引用一个图片

例如
<img src=\"").append(DBInfo.getWebServerPrefix()).append("/report/U10090A2_H.jpg\" width=\"257\" height=\"37\" />                                                                                                             
2。图片作为背景,利用css分层方法。                                                   
例如
<div style=\"position:relative;left:0px; top:0px; \">
<img src=\"").append(DBInfo.getWebServerPrefix()).append("/pic/coverbg.gif\" alt=\"bg\" width=\"692\" height=\"948\"></img>
<div id=\"Layer1\" style=\"position:absolute; left:255px; top:510px; width:450px; z-index:1;\">
。。。。。。。。。 此处省略

3。还弄过页眉上的图片,利用fs 支持css3,设置page 属性

@top-left {
                content: "sssssss";
                border-bottom: solid 0.01mm #000;
                background:transparent url(images/PartnerMgr.gif) top left no-repeat;    /*add a image at left-top corner*/
              }


不知道对你有没有帮助。
84 楼 l116116116 2010-01-29  
zjh0207 写道
包含有图片的html转pdf会出错
用<img src="">标签或用<input type="image" src="">都不行
控制台提示
“NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist.”


请仔细查看xhtml语言关于 img的语法。
83 楼 l116116116 2010-01-29  
watson1984 写道
我在用flying saucer的时候,html的空格(&nbsp;)和js代码处理不好,不知道是什么原因~~


xhtml的entity
可用  &#160;

可参考
http://www.elizabethcastro.com/html/extras/entities.html

相关推荐

    itext的PDF生成方案

    **iText PDF生成方案** iText是一个开源的Java库,专门用于创建和修改PDF文档。在IT领域,尤其是在文档处理和报告生成方面,iText是一个非常实用的工具。本方案将详细探讨如何利用iText来生成PDF文件,以及相关的...

    QT5生成PDF

    1、 pdfWriter1():使用QpdfWriter和Qpainter进行纯文字版的pdf生成和绘制,并进行了分页显示。 Pdf生成在当前目录下的pdf_test.pdf 2、 pdfWriter2():使用QPdfwriter 和QPainter创建pdf报告,关键是对页面的布局...

    MCU生成PDF文件

    首先,我们需要一个PDF库,它能够运行在资源有限的MCU上。虽然PDF格式复杂,但有一些轻量级的开源库如`PDFGen`可以帮助我们实现这一目标。根据提供的压缩包包名`PDFGen-master`,我们可以假设这是我们要用的库,它...

    java 多个pdf合并,目录生成(支持自定义目录),页码生成(源码)

    本项目提供了一个纯Java实现的解决方案,它能有效地完成多个PDF文件的合并,并且支持自定义目录的生成以及页码的添加。 首先,`PDFUtil.java`是这个项目的核心类,它包含了处理PDF的关键方法。PDFUtil可能包含了...

    pdf生成缩略图

    PDF生成缩略图是将PDF文档中的页面转换成小尺寸的图像表示,通常用于预览、索引或在文件管理器中快速查看PDF内容。在IT领域,这涉及到PDF处理和图像处理技术。以下是一些关于如何在C#中生成PDF缩略图的关键知识点: ...

    自动生成PDF文件,C#源码

    标题“自动生成PDF文件,C#源码”表明我们讨论的是一个使用C#编程语言创建PDF文件的解决方案。这通常涉及到第三方库的使用,如iTextSharp,它是一个强大的PDF处理库,能够帮助开发者在C#环境中方便地生成、编辑和...

    Java将PDF生成图片

    以下是一些关于“Java将PDF生成图片”的核心知识点: 1. **PDF处理库**:在Java中,我们可以使用第三方库如Apache PDFBox、iText和PDF Clown等来处理PDF文档。这些库提供了丰富的API,用于读取、解析和操作PDF文件...

    PDF生成器for win7

    此外,PDF生成器还可能提供一些高级特性,如合并多个文件为一个PDF、添加水印、密码保护等,以满足不同用户的需求。 总的来说,PDF生成器是Windows 7用户便捷创建PDF文档的重要工具。通过理解其工作原理和使用方法...

    多图片生成一PDF工具.zip

    总的来说,这款“多图片生成一PDF工具”提供了一个简单易用且高效的解决方案,帮助用户快速将图片集合整理成PDF文档,特别适合处理jpg、png和bmp格式的图片。同时,其批量处理功能极大地提升了处理大量图片的效率。...

    C#生成pdf文件

    虽然.NET Framework本身并不直接支持PDF生成,但有许多开源和商业库可供选择,如iTextSharp、PDFsharp、Syncfusion Essential PDF等。这些库提供了API,允许开发者创建、编辑和操作PDF文档。 以iTextSharp为例,这...

    PDF生成器包含注册码

    总的来说,这款包含注册码的PDF生成器提供了一个便捷的解决方案,帮助用户轻松创建和管理PDF文档。其小巧的体积、简单的操作以及全面的功能使得它成为处理PDF文件的理想选择。用户在享受这些服务的同时,也无需担心...

    保护数据隐私的深度学习训练数据生成方案.pdf

    本文主要介绍了一种保护数据隐私的深度学习训练数据生成方案,该方案基于条件生成对抗网络(CGAN),能够生成大量与真实数据同分布的对抗样本,满足了生成大量带标签训练数据的需求。同时,该方案还结合数据变形方法...

    php完全生成pdf解决方案

    php生成pdf的完全解决方案,不使用phplib插件,完全脚本化执行,完美解决中文乱码问题,支持以下功能: 1、完美支持中文,php生成的pdf不会出现乱码 2、把SQL查询结构生成为pdf中的表格 3、pdf页眉页脚支持中文及...

    在c#中生成PDF文件

    首先,我们需要一个库来处理PDF生成。一个常用的开源库是iTextSharp,它是一个功能丰富的PDF处理库,支持多种操作,包括创建、编辑和读取PDF文件。要使用iTextSharp,你需要在项目中添加对它的引用。可以通过NuGet包...

    itextpdf.zip(JavaPDF文件生成)

    JavaPDF文件生成是Java开发中一个重要的领域,主要用于创建、编辑和处理PDF文档。iTextPDF是一个流行的开源库,它提供了丰富的API...通过熟练掌握iTextPDF,开发者可以在Java应用程序中实现专业级的PDF生成和处理功能。

    java生成PDF417条码

    4. **集成到应用**:将条码生成功能集成到你的Java应用程序中,可能需要创建一个服务或工具类,提供生成条码的接口。这可能涉及到处理用户输入、验证数据、选择条码格式,以及将生成的条码图像插入到PDF、报告或网页...

    一款很好的PDF组件(ASP生成PDF)

    【ASP PDF组件与PDF生成技术】 在Web开发中,生成PDF文档是一项常见的需求,用于提供打印友好版本或者方便用户下载的格式。ASP(Active Server Pages)是微软开发的一种服务器端脚本环境,常用于构建动态网页。而...

    利用freemarker 模板生成pdf ,利用easypoi 生成excel(带图片,水印,分页)

    在生成PDF时,我们可以借助Flying Saucer库,这是一个能够将HTML转换为PDF的工具。通过将Freemarker模板与Flying Saucer结合,可以方便地将动态数据转换成结构化的PDF文档。例如,你可以创建一个Freemarker模板,...

    freemarker生成doc方案.pdf(内附代码下载地址)

    在当今的信息技术领域,自动化文档生成是一个非常重要的功能,尤其是在企业和监管单位中,自动化的文档生成可以节省大量的人力和时间资源,提高工作效率。为了实现这一目标,使用Freemarker模板引擎结合Office软件...

    简单易用的pdf生成器

    总之,"简单易用的pdf生成器"通过DOPDF提供了一个便捷的解决方案,使得用户能够快速且轻松地将Word文档转换为PDF,确保内容的准确性和安全性。通过掌握这种工具的使用,无论是个人还是专业人士,都能在日常工作中...

Global site tag (gtag.js) - Google Analytics