论坛首页 Java企业应用论坛

介绍一个PDF的生成方案

浏览 150990 次
该帖已经被评为良好帖
作者 正文
   发表时间:2009-12-14  
现在的问题是,flying saucer 对于css的有些方法不支持,导致在pdf里面和浏览器里面的表现不一样,我对css也不熟,只能一点点儿改css了
0 请登录后投票
   发表时间:2009-12-14  
downpour 写道
l116116116 写道
最近要做一个 html的PDF打印的工作,看到了这篇文章,一直也在试图用flying saucer 的方案来实现。在整个过程中,遇到了很多困难,感觉flying saucer 本身在服务器端的解析能力,与浏览器通过http协议的解析能力还有很多的不足。 例如, 缩印,再例如,显示背景图片,再例如,对<table><tr><td>的支持,再例如对 <jsp:include/>,frame的支持(试过@include 语法,原来以为支持,结果也不支持。 难道只能渲染现有代码? )。 不知道大家在使用时感觉什么样。 之前我们曾使用过 客户端的小开源软件,pdf creator。 这个对客户端html的PDF解析相当有效。 美中不足的就是依赖于客户端的安装。 好好的瘦客户端变成胖客户端也有点不好。。。 唉~~~~~


我认为你这种试图使用JSP来渲染PDF的方式本身就和flying saucer的初衷不同。

Flying sauser的目标是能够解析基于HTML+CSS的plain text,并将之结构化成iText可识别的API调用。所以,你要做的,是把最终需要展现在PDF中的东西,用HTML+CSS表达出来,而不是传入给Flying sauser一个JSP文件。

所以我的看法是,Freemarker或者Velocity的模板才是使用Flying sauser的最佳实践。


我的表达有点问题,当然不是直接传入JSP,是把html的语言来用xhtml(说到底就是xml)来转化。我说的问题是在转化过程中遇到的问题。html+css 感觉非常适用于网站网页。
0 请登录后投票
   发表时间:2009-12-14  
yye_javaeye 写道
现在的问题是,flying saucer 对于css的有些方法不支持,导致在pdf里面和浏览器里面的表现不一样,我对css也不熟,只能一点点儿改css了



相对于Jasper report,我觉得fly saucer的一大优点就是对css的支持。可能是因为浏览器和FS对css的解析不一样吧。
0 请登录后投票
   发表时间:2009-12-15  
l116116116 写道
downpour 写道
l116116116 写道
最近要做一个 html的PDF打印的工作,看到了这篇文章,一直也在试图用flying saucer 的方案来实现。在整个过程中,遇到了很多困难,感觉flying saucer 本身在服务器端的解析能力,与浏览器通过http协议的解析能力还有很多的不足。 例如, 缩印,再例如,显示背景图片,再例如,对<table><tr><td>的支持,再例如对 <jsp:include/>,frame的支持(试过@include 语法,原来以为支持,结果也不支持。 难道只能渲染现有代码? )。 不知道大家在使用时感觉什么样。 之前我们曾使用过 客户端的小开源软件,pdf creator。 这个对客户端html的PDF解析相当有效。 美中不足的就是依赖于客户端的安装。 好好的瘦客户端变成胖客户端也有点不好。。。 唉~~~~~


我认为你这种试图使用JSP来渲染PDF的方式本身就和flying saucer的初衷不同。

Flying sauser的目标是能够解析基于HTML+CSS的plain text,并将之结构化成iText可识别的API调用。所以,你要做的,是把最终需要展现在PDF中的东西,用HTML+CSS表达出来,而不是传入给Flying sauser一个JSP文件。

所以我的看法是,Freemarker或者Velocity的模板才是使用Flying sauser的最佳实践。


我的表达有点问题,当然不是直接传入JSP,是把html的语言来用xhtml(说到底就是xml)来转化。我说的问题是在转化过程中遇到的问题。html+css 感觉非常适用于网站网页。

转化过程中怎么会跟jsp有关系呢?我用的是freemarker,对于freemarker的处理,在传到fs之前就已经结束了!
0 请登录后投票
   发表时间:2009-12-15  
各位又沒有試過用loadjava 將iText-2.0.8.jar和core-renderer.jar 加載到 oracle 里面呢?
為啥我加載的時候報錯呢?如附件圖片

還有對繁體中文要怎樣設置字體呢?繁體中文出來都是亂碼。
  • 大小: 109.3 KB
0 请登录后投票
   发表时间:2010-01-05  
yye_javaeye 写道
中文换行问题解决了,这东西源码里面是将英文按空格分组,每组判断其位置+长度是否超出边界,超出的话将该组丢到下一行,但是中文里面基本没有空格,所以就无奈了。
将其源码改了改,如果是中文,每字一组,如果是英文,还是按照空格分组,这样大概效率会受一些影响,不过好歹是可以用了,而且一般pdf生成我想应该也不会放在需要大访问量的地方吧。附件是打好包的jar,覆盖就可以了

怎么看不到你的附件了啊?哪位大侠能发我一份么?
0 请登录后投票
   发表时间:2010-01-06  
http://www.iteye.com/topic/509417?page=6#1279762
0 请登录后投票
   发表时间:2010-01-06  
downpour 写道
yye_javaeye 写道
?怎么会?我用的是挺好的啊,效果看附件


帅哥,你不要光给我们一个jar包行吗?告诉我们一下,你改的哪个类,哪个方法,顺便把代码贴一下。谢谢啦。

呵呵,没注意到这个帖子,当时因为项目正着急,忘了贴上来了
修改了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;
    }

}

0 请登录后投票
   发表时间:2010-01-20  
问个问题啊?
有谁在websphere底下使用过flying sauser吗?我在websphere上用的是,发现css效果根本就没有显示出来,但用tomcat是可以准确生成的,哪位大侠知道怎么回事么?

...
title>cover-20091223</title>
<style type="text/css">
<!--

@import "theme/common.css";

...


0 请登录后投票
   发表时间:2010-01-21  
我在用flying saucer的时候,html的空格(&nbsp;)和js代码处理不好,不知道是什么原因~~
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics