Skip to content

Commit edac710

Browse files
committed
Experimental purely PDFBox-based rendering engine implementation
1 parent baa144b commit edac710

File tree

5 files changed

+454
-109
lines changed

5 files changed

+454
-109
lines changed

.settings/org.eclipse.jdt.ui.prefs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.ui.javadoc=false
3+
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\n * ${file_name}\n * Copyright (c) ${year} Radek Burget\n *\n * CSSBox is free software\: you can redistribute it and/or modify\n * it under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * CSSBox is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n * \n * You should have received a copy of the GNU Lesser General Public License\n * along with CSSBox. If not, see &lt;http\://www.gnu.org/licenses/&gt;.\n *\n * Created on ${date}, ${time} by ${user}\n */\n</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * @author ${user}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* PDFEngine.java
3+
* Copyright (c) 2019 Radek Burget
4+
*
5+
* CSSBox is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* CSSBox is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with CSSBox. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* Created on 17. 11. 2019, 16:57:03 by burgetr
19+
*/
20+
21+
package org.fit.cssbox.pdf;
22+
23+
import java.io.OutputStream;
24+
import java.net.URL;
25+
26+
import org.apache.pdfbox.pdmodel.PDDocument;
27+
import org.apache.pdfbox.pdmodel.PDPage;
28+
import org.apache.pdfbox.pdmodel.common.PDRectangle;
29+
import org.fit.cssbox.css.DOMAnalyzer;
30+
import org.fit.cssbox.css.FontTable;
31+
import org.fit.cssbox.layout.BrowserConfig;
32+
import org.fit.cssbox.layout.Dimension;
33+
import org.fit.cssbox.layout.Engine;
34+
import org.fit.cssbox.layout.VisualContext;
35+
import org.fit.cssbox.render.BoxRenderer;
36+
import org.w3c.dom.Element;
37+
38+
/**
39+
*
40+
* @author burgetr
41+
*/
42+
public class PDFEngine extends Engine
43+
{
44+
private PDDocument doc;
45+
private PDPage page;
46+
private PDRectangle pageFormat;
47+
48+
49+
public PDFEngine(String pageFormat, Element root, DOMAnalyzer decoder, Dimension dim, URL baseurl)
50+
{
51+
super(root, decoder, dim, baseurl);
52+
initDocument(pageFormat);
53+
}
54+
55+
public PDFEngine(String pageFormat, Element root, DOMAnalyzer decoder, URL baseurl)
56+
{
57+
super(root, decoder, baseurl);
58+
initDocument(pageFormat);
59+
}
60+
61+
public PDDocument getDocument()
62+
{
63+
return doc;
64+
}
65+
66+
public PDPage getPage()
67+
{
68+
return page;
69+
}
70+
71+
public PDRectangle getPageFormat()
72+
{
73+
return pageFormat;
74+
}
75+
76+
@Override
77+
protected VisualContext createVisualContext(BrowserConfig config, FontTable fontTable)
78+
{
79+
return new PDFVisualContext(getDocument(), null, config, fontTable);
80+
}
81+
82+
@Override
83+
public BoxRenderer getRenderer()
84+
{
85+
//obtain the viewport bounds depending on whether we are clipping to viewport size or using the whole page
86+
float w = getViewport().getClippedContentBounds().width;
87+
float h = getViewport().getClippedContentBounds().height;
88+
return new PDFRenderer(w, h, doc);
89+
}
90+
91+
//========================================================================================
92+
93+
protected void initDocument(String format)
94+
{
95+
try
96+
{
97+
pageFormat = decodePageFormat(format);
98+
doc = new PDDocument();
99+
page = new PDPage(pageFormat);
100+
doc.addPage(page);
101+
} catch (Exception e) {
102+
throw new RuntimeException(e);
103+
}
104+
}
105+
106+
/**
107+
* Saves the PDF document to the given output stream.
108+
*/
109+
public void saveDocument(OutputStream out)
110+
{
111+
try
112+
{
113+
doc.save(out);
114+
} catch (Exception e) {
115+
throw new RuntimeException(e);
116+
}
117+
}
118+
119+
/**
120+
* Closes the document.
121+
*/
122+
public void closeDocument()
123+
{
124+
try
125+
{
126+
doc.close();
127+
} catch (Exception e) {
128+
throw new RuntimeException(e);
129+
}
130+
}
131+
132+
133+
protected PDRectangle decodePageFormat(String format)
134+
{
135+
PDRectangle ret;
136+
switch (format)
137+
{
138+
case "A0":
139+
ret = PDRectangle.A0;
140+
break;
141+
case "A1":
142+
ret = PDRectangle.A1;
143+
break;
144+
case "A2":
145+
ret = PDRectangle.A2;
146+
break;
147+
case "A3":
148+
ret = PDRectangle.A3;
149+
break;
150+
case "A4":
151+
ret = PDRectangle.A4;
152+
break;
153+
case "A5":
154+
ret = PDRectangle.A5;
155+
break;
156+
case "A6":
157+
ret = PDRectangle.A6;
158+
break;
159+
case "LETTER":
160+
ret = PDRectangle.LETTER;
161+
break;
162+
default:
163+
ret = PDRectangle.A4;
164+
break;
165+
}
166+
return ret;
167+
}
168+
}

src/main/java/org/fit/cssbox/pdf/PDFRenderer.java

+24-84
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import java.awt.image.BufferedImage;
3030
import java.io.File;
3131
import java.io.IOException;
32-
import java.io.OutputStream;
3332
import java.net.URI;
3433
import java.util.ArrayList;
3534
import java.util.List;
@@ -130,61 +129,17 @@ private class FontTableRecord
130129
};
131130

132131
// other variables
133-
private OutputStream pathToSave;
134132
private float outputTopPadding;
135133
private float outputBottomPadding;
136134

137-
/**
138-
* Constructor
139-
*
140-
* initialize the variables
141-
*/
142-
public PDFRenderer(float rootWidth, float rootHeight, OutputStream out, String pageFormat)
143-
{
144-
this.rootHeight = rootHeight;
145-
this.pathToSave = out;
146-
this.pageCount = 0;
147135

148-
switch (pageFormat)
149-
{
150-
case "A0":
151-
this.pageFormat = PDRectangle.A0;
152-
break;
153-
case "A1":
154-
this.pageFormat = PDRectangle.A1;
155-
break;
156-
case "A2":
157-
this.pageFormat = PDRectangle.A2;
158-
break;
159-
case "A3":
160-
this.pageFormat = PDRectangle.A3;
161-
break;
162-
case "A4":
163-
this.pageFormat = PDRectangle.A4;
164-
break;
165-
case "A5":
166-
this.pageFormat = PDRectangle.A5;
167-
break;
168-
case "A6":
169-
this.pageFormat = PDRectangle.A6;
170-
break;
171-
case "LETTER":
172-
this.pageFormat = PDRectangle.LETTER;
173-
break;
174-
default:
175-
this.pageFormat = PDRectangle.A4;
176-
break;
177-
}
178-
179-
initSettings(rootWidth);
180-
}
181-
182-
public PDFRenderer(float rootWidth, float rootHeight, OutputStream out, PDRectangle pageFormat)
136+
public PDFRenderer(float rootWidth, float rootHeight, PDDocument doc)
183137
{
184138
this.rootHeight = rootHeight;
185-
this.pathToSave = out;
139+
this.doc = doc;
140+
this.page = doc.getPage(0);
141+
this.pageFormat = page.getMediaBox();
186142
this.pageCount = 0;
187-
this.pageFormat = pageFormat;
188143
initSettings(rootWidth);
189144
}
190145

@@ -341,7 +296,6 @@ public void renderReplacedContent(ReplacedBox box)
341296
@Override
342297
public void close()
343298
{
344-
345299
// FINISH STEP B - process the nodesWithoutParent table and insert nodes
346300
// to TREE, if possible
347301
tryToInsertNotInsertedNodes();
@@ -490,19 +444,18 @@ else if (pageEnd > breakTable.get(0)[0] && pageEnd < breakTable.get(0)[1])
490444
*/
491445
private void makePDF()
492446
{
493-
494447
// creates PDF document with first blank page
495-
createDocPDFBox();
448+
initContentStream();
496449

497450
// inserts all needed blank pages to PDF document
498451
insertNPagesPDFBox(pageCount);
499452

500453
// transforms all data from LIST data structure to Apache PDFBox format
501454
// and writes it do PDF document
502455
writeAllElementsToPDF();
503-
504-
// saves current document
505-
saveDocPDFBox();
456+
457+
// close the content stream
458+
closeContentStream();
506459
}
507460

508461
/////////////////////////////////////////////////////////////////////
@@ -2135,7 +2088,7 @@ private int insertText(TextBox text, int i, float plusOffset, float plusHeight)
21352088
return 1;
21362089

21372090
// gets data describing the text
2138-
VisualContext ctx = text.getVisualContext();
2091+
PDFVisualContext ctx = (PDFVisualContext) text.getVisualContext();
21392092
float fontSize = CSSUnits.pixels(ctx.getFontInfo().getSize() * resCoef); //TODO pt vs px
21402093
boolean isBold = ctx.getFontInfo().isBold();
21412094
boolean isItalic = ctx.getFontInfo().isItalic();
@@ -2145,7 +2098,8 @@ private int insertText(TextBox text, int i, float plusOffset, float plusHeight)
21452098

21462099
// if font is not in fontTable we load it
21472100
PDFont font = null;
2148-
for (int iter = 0; iter < fontTable.size(); iter++)
2101+
font = ctx.getFont();
2102+
/*for (int iter = 0; iter < fontTable.size(); iter++)
21492103
{
21502104
21512105
if (fontTable.get(iter).fontName.equalsIgnoreCase(fontFamily) && fontTable.get(iter).isItalic == isItalic
@@ -2156,7 +2110,7 @@ private int insertText(TextBox text, int i, float plusOffset, float plusHeight)
21562110
{
21572111
font = setFont(fontFamily, isItalic, isBold);
21582112
fontTable.add(new FontTableRecord(fontFamily, isBold, isItalic, font));
2159-
}
2113+
}*/
21602114

21612115
// font.setFontEncoding(new PdfDocEncoding()); //TODO is this useful?
21622116
// String textToInsert = filterUnicode(text.getText());
@@ -2192,40 +2146,28 @@ private int insertText(TextBox text, int i, float plusOffset, float plusHeight)
21922146
/////////////////////////////////////////////////////////////////////////
21932147

21942148
/**
2195-
* Saves the PDF document to disk using PDFBox
2149+
* Creates the document content stream.
21962150
*/
2197-
private int saveDocPDFBox()
2151+
private void initContentStream()
21982152
{
21992153
try
22002154
{
2201-
content.close();
2202-
doc.save(pathToSave);
2203-
doc.close();
2204-
} catch (Exception e)
2205-
{
2206-
e.printStackTrace();
2207-
return -1;
2155+
content = new PDPageContentStream(doc, page);
2156+
} catch (IOException e) {
2157+
throw new RuntimeException(e);
22082158
}
2209-
return 0;
22102159
}
2211-
2160+
22122161
/**
2213-
* Creates document witch first page in it using PDFBox
2162+
* Closes the document content stream.
22142163
*/
2215-
private int createDocPDFBox()
2164+
private void closeContentStream()
22162165
{
2217-
try
2218-
{
2219-
doc = new PDDocument();
2220-
page = new PDPage(pageFormat);
2221-
doc.addPage(page);
2222-
content = new PDPageContentStream(doc, page);
2223-
} catch (Exception e)
2224-
{
2225-
e.printStackTrace();
2226-
return -1;
2166+
try {
2167+
content.close();
2168+
} catch (IOException e) {
2169+
throw new RuntimeException(e);
22272170
}
2228-
return 0;
22292171
}
22302172

22312173
/**
@@ -2265,7 +2207,6 @@ private int changeCurrentPageToPDFBox(int i)
22652207
*/
22662208
private int drawBgToWholePagePDFBox(Color bgColor)
22672209
{
2268-
22692210
try
22702211
{
22712212
content.setNonStrokingColor(toPDColor(bgColor));
@@ -2290,7 +2231,6 @@ private int drawRectanglePDFBox(float lineWidth, PDColor bgColor, float x, float
22902231
{
22912232
content.setLineWidth(lineWidth);
22922233
content.setNonStrokingColor(bgColor);
2293-
22942234
content.addRect(x, y, width, height);
22952235
content.fill();
22962236
} catch (IOException e)

0 commit comments

Comments
 (0)