1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.seasar.tuigwaa.cms.core.pdf;
17
18 import java.awt.Color;
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.io.StringReader;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Properties;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import com.lowagie.text.Chunk;
32 import com.lowagie.text.DocumentException;
33 import com.lowagie.text.Element;
34 import com.lowagie.text.ElementTags;
35 import com.lowagie.text.Font;
36 import com.lowagie.text.ListItem;
37 import com.lowagie.text.PageSize;
38 import com.lowagie.text.Paragraph;
39 import com.lowagie.text.Phrase;
40 import com.lowagie.text.Rectangle;
41 import com.lowagie.text.html.simpleparser.StyleSheet;
42 import com.lowagie.text.pdf.BaseFont;
43 import com.lowagie.text.pdf.PdfPTable;
44
45 /***
46 * <p>
47 * KNOWN ISSUE 1. Japanese character is unavailable in PdfPTable During parsing,
48 * HTMLWorker uses FactoryProperties static methods. It will create the font
49 * object by FactoryProperties#getFont, and we can specify fontname as "face"
50 * style, though the encoding is fixed to "BaseFont.WINANSI", that is CP1252,
51 * Latin1. Thus, at least, we could not get the objects which can display
52 * Japanese character soon after parsing phase even if Japanese fonts are
53 * registered by FontFactory#register and its name are given to "face" style. To
54 * make matters complicated, HTMLWorker uses PdfPTable to convert <table>
55 * and wrapper class IncTable for PdfPTable, and IncCell for PdfPCell. In
56 * IncCell, it adds Element by PdfPCell#addElement methods. PdfPCell#addElement
57 * methods doesn't keep Phrase or Chunk object in its instances but directly
58 * calles ColumnText#addElement. ColumnText#addElement adds element into its
59 * protected LinkedList and it seems to be no way provided to change that added
60 * element property. => This solved by to create extended class CJKHTMLWorker
61 * and CJKFactoryProperties for HTMLWorker and FactoryProperties.
62 * </p>
63 *
64 * @author someda
65 */
66 public class PdfUtils {
67
68
69 public static Font FONT_JA_GOTHIC;
70 private static final String FONTNAME_JA_GOTHIC = "HeiseiKakuGo-W5";
71 private static final String FONTNAME_JA_GOTHIC_ENCODING = "UniJIS-UCS2-H";
72
73
74 public static Font FONT_JA_MINCHO;
75 private static final String FONTNAME_JA_MINCHO = "HeiseiMin-W3";
76 private static final String FONTNAME_JA_MINCHO_ENCODING = "UniJIS-UCS2-HW-H";
77
78 public static Font FONT_ERROR;
79
80 public static BaseFont BASEFONT_GOTHIC;
81 public static BaseFont BASEFONT_MINCHO;
82
83 public static final String DEFAULT_PDF_PAGESTYLE = "v-n-A4";
84
85 private static final String COLOR_BLACK_HEX = "000000";
86
87 private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<//w+.*>");
88
89 private static Log log_ = LogFactory.getLog(PdfUtils.class);
90
91 static{
92 try{
93 BASEFONT_GOTHIC = BaseFont.createFont(FONTNAME_JA_GOTHIC,FONTNAME_JA_GOTHIC_ENCODING,BaseFont.NOT_EMBEDDED);
94 BASEFONT_MINCHO = BaseFont.createFont(FONTNAME_JA_MINCHO,FONTNAME_JA_MINCHO_ENCODING,BaseFont.NOT_EMBEDDED);
95 FONT_JA_GOTHIC = new Font(BASEFONT_GOTHIC, 12,Font.NORMAL);
96 FONT_JA_MINCHO = new Font(BASEFONT_MINCHO,12,Font.NORMAL);
97 FONT_ERROR = new Font(BASEFONT_GOTHIC,12,Font.BOLD,Color.RED);
98 }catch(IOException ioe){
99 ioe.printStackTrace();
100 }catch(DocumentException de){
101 de.printStackTrace();
102 }
103 }
104
105 public static Properties getDefaultfontProperties(Font defaultFont){
106
107 Properties props = new Properties();
108 props.setProperty(ElementTags.FONT,defaultFont.getFamilyname());
109
110
111
112 if(defaultFont.equals(FONT_JA_GOTHIC)){
113 props.setProperty(ElementTags.ENCODING,FONTNAME_JA_GOTHIC_ENCODING);
114 }else if(defaultFont.equals(FONT_JA_MINCHO)){
115 props.setProperty(ElementTags.ENCODING,FONTNAME_JA_MINCHO_ENCODING);
116 }
117 props.setProperty(ElementTags.EMBEDDED,String.valueOf(defaultFont.getBaseFont().isEmbedded()));
118 props.setProperty(ElementTags.STYLE,String.valueOf(defaultFont.style()));
119 props.setProperty(ElementTags.SIZE,String.valueOf(defaultFont.size()));
120 props.setProperty(ElementTags.COLOR,COLOR_BLACK_HEX);
121
122 return props;
123 }
124
125 public static Properties getChapterfontProperties(Font defaultFont) {
126 Properties props = getDefaultfontProperties(defaultFont);
127 props.setProperty(ElementTags.SIZE, String.valueOf(18));
128 return props;
129 }
130
131 public static Properties getSectionfontProperties(Font defaultFont, int depth){
132 Properties props = getDefaultfontProperties(defaultFont);
133 if(depth > 2){
134 props.setProperty(ElementTags.SIZE,String.valueOf(14));
135 }else{
136 props.setProperty(ElementTags.SIZE,String.valueOf(16));
137 }
138 return props;
139 }
140
141
142 public static Object convertHTMLtoPDF(String s){
143
144 if(s != null){
145 Matcher m = HTML_TAG_PATTERN.matcher(s);
146 if(m.find()){
147 return parseHTMLtoPDF(s);
148 }else{
149 return new Chunk(s,FONT_JA_GOTHIC);
150 }
151 }
152 return null;
153 }
154
155 public static Object parseHTMLtoPDF(String s) {
156 Reader reader = new StringReader(s);
157 try{
158 return parseHTMLtoPDF(reader);
159 }finally{
160 if (reader != null) {
161 try {
162 reader.close();
163 } catch (IOException ioe) {
164 log_.error("failed to close reader object");
165 }
166 }
167 }
168 }
169
170 public static Object parseHTMLtoPDF(Reader reader) {
171
172 List list = null;
173 float leading = FONT_JA_GOTHIC.size() + 3;
174 float listspacing = 2;
175 try {
176 list = CJKHTMLWorker.parseToList(reader, getCJKStyleSheet());
177 for (Iterator i = list.iterator(); i.hasNext();) {
178 Element e = (Element) i.next();
179
180 List chunks;
181 if ((chunks = e.getChunks()) != null) {
182 for (Iterator j = chunks.iterator(); j.hasNext();) {
183 Chunk c = (Chunk) j.next();
184 c.setFont(FONT_JA_GOTHIC);
185 }
186 }
187 if (e instanceof Paragraph) {
188 ((Paragraph) e).setLeading(leading);
189 } else if (e instanceof PdfPTable) {
190 ((PdfPTable) e).setSpacingBefore(leading);
191 } else if (e instanceof com.lowagie.text.List) {
192 com.lowagie.text.List l = (com.lowagie.text.List) e;
193 for (Iterator j = l.getItems().iterator(); j.hasNext();) {
194 Object listItem = j.next();
195 if(listItem instanceof ListItem){
196 ListItem li = (ListItem) listItem;
197 li.setSpacingBefore(listspacing);
198 }
199 }
200 }
201 }
202 } catch (IOException ioe) {
203 log_.error("failed to parse HTML object");
204 }
205 return list;
206 }
207
208
209
210 public static String getStringResult(Object obj){
211
212 String ret = null;
213 if(obj instanceof String){
214 ret = (String)obj;
215 }else if(obj instanceof Chunk){
216 Chunk c = (Chunk)obj;
217 ret = c.content();
218 }else if(obj instanceof Phrase){
219 StringBuffer buf = new StringBuffer();
220 Phrase p = (Phrase) obj;
221 for(int i=0;i<p.size();i++){
222 Chunk c = (Chunk)p.get(i);
223 buf.append(c.content());
224 }
225 ret = buf.toString();
226 }
227 return ret;
228 }
229
230
231
232
233
234
235
236
237
238
239
240
241 public static Rectangle getRectangle(String style){
242
243 Rectangle rec = PageSize.A4;
244 if(style.endsWith("B5")){
245 rec = PageSize.B5;
246 }
247 return (style.startsWith("h-"))? rec.rotate() : rec;
248 }
249
250 public static boolean isSimpleStyle(String style){
251 return style.indexOf("-s-") != -1;
252 }
253
254
255
256 private static StyleSheet getCJKStyleSheet(){
257 StyleSheet cjkstyle = new StyleSheet();
258
259 cjkstyle.loadTagStyle("table", "border", "0.5");
260 cjkstyle.loadTagStyle("table", "face", FONTNAME_JA_GOTHIC);
261
262
263 cjkstyle.loadTagStyle("table", "cjk_encoding", FONTNAME_JA_GOTHIC_ENCODING);
264 cjkstyle.loadTagStyle("table", "cjk_embeded", "false");
265
266 cjkstyle.loadTagStyle("th", "bgcolor", "silver");
267 cjkstyle.loadTagStyle("th", "font", "bold");
268
269 return cjkstyle;
270 }
271
272 }