Hello,
I was using iText to convert a JTable to a PDF. This was consuming a
large amount of memory and taking a long time, so I did some memory
profiling and have attached a patch that significantly improves
performance for us. The following describes what I found, and what the
patch does:
When printing a JTable, you have to construct a lot of child
PdfGraphics2D objects. For each child, the following happens:
1. A BufferedImage is created just so that we can get a regular
Graphics2D. This Graphics2D object may never be used, so I
patched PdfGraphics2D to construct it only if needed.
2. Two arrays of PdfGState are created, but are then replaced
with the parent's arrays. I patched PdfGraphics2D to create
these arrays in the non-private constructor. You might want to
consider using the clone() method instead of keeping that
private constructor around. The normal .clone() behaviour is
very similar to what you have done manually in the .create()
method.
Finally, I noticed that the AWT PathIterator.currentSegment(float[])
method creates a double[] internally. That is because the
float[]-based method just passes through to the double[]-based
method. I modified your use of the PathIterator to take this into
account.
Can this patch be included in the next release?
Also, I am working on a commercial product. Can you clarify for me
whether or not iText PDF can be included as a .jar in our commercial
(non-open-source) product? I cannot remember whether "using a .jar" is
considered a derivative work or not. If we're allowed to use it, then I
will probably do a little more work on improving performance of iText
and will send that on.
Thanks,
Peter.
Index: src/core/com/itextpdf/text/pdf/PdfGraphics2D.java
===================================================================
--- src/core/com/itextpdf/text/pdf/PdfGraphics2D.java (revision 4347)
+++ src/core/com/itextpdf/text/pdf/PdfGraphics2D.java (working copy)
@@ -149,7 +149,7 @@
private boolean kid = false;
- private Graphics2D dg2 = new BufferedImage(2, 2,
BufferedImage.TYPE_INT_RGB).createGraphics();
+ private Graphics2D dg2;
private boolean onlyShapes = false;
@@ -162,8 +162,8 @@
// Added by Jurij Bilas
protected boolean underline; // indicates if the font style is
underlined
- protected PdfGState fillGState[] = new PdfGState[256];
- protected PdfGState strokeGState[] = new PdfGState[256];
+ protected PdfGState fillGState[];
+ protected PdfGState strokeGState[];
protected int currentFillGState = 255;
protected int currentStrokeGState = 255;
@@ -180,11 +180,18 @@
// Added by Alexej Suchov
private Paint realPaint;
+
+ private Graphics2D getDG2() {
+ if (dg2 == null) {
+ dg2 = new BufferedImage(2, 2,
BufferedImage.TYPE_INT_RGB).createGraphics();
+ dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ setRenderingHint(HyperLinkKey.KEY_INSTANCE,
HyperLinkKey.VALUE_HYPERLINKKEY_OFF);
+ }
+ return dg2;
+ }
private PdfGraphics2D() {
- dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- setRenderingHint(HyperLinkKey.KEY_INSTANCE,
HyperLinkKey.VALUE_HYPERLINKKEY_OFF);
}
/**
@@ -193,9 +200,8 @@
*/
PdfGraphics2D(PdfContentByte cb, float width, float height, FontMapper
fontMapper, boolean onlyShapes, boolean convertImagesToJPEG, float quality) {
super();
- dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- setRenderingHint(HyperLinkKey.KEY_INSTANCE,
HyperLinkKey.VALUE_HYPERLINKKEY_OFF);
+ this.fillGState = new PdfGState[256];
+ this.strokeGState = new PdfGState[256];
this.convertImagesToJPEG = convertImagesToJPEG;
this.jpegQuality = quality;
this.onlyShapes = onlyShapes;
@@ -589,7 +595,7 @@
*/
@Override
public GraphicsConfiguration getDeviceConfiguration() {
- return dg2.getDeviceConfiguration();
+ return getDG2().getDeviceConfiguration();
}
/**
@@ -1058,7 +1064,7 @@
*/
@Override
public FontMetrics getFontMetrics(Font f) {
- return dg2.getFontMetrics(f);
+ return getDG2().getFontMetrics(f);
}
/**
@@ -1356,7 +1362,8 @@
disposeCalled = true;
cb.restoreState();
cb.restoreState();
- dg2.dispose();
+ if (dg2 != null)
+ dg2.dispose();
dg2 = null;
if (kids != null) {
ByteBuffer buf = new ByteBuffer();
@@ -1379,7 +1386,8 @@
g2.cb.restoreState();
g2.cb.restoreState();
buf.append(buf2.getBuffer(), last, pos - last);
- g2.dg2.dispose();
+ if (g2.dg2 != null)
+ g2.dg2.dispose();
g2.dg2 = null;
g2.internalDispose(buf);
last = pos;
@@ -1419,9 +1427,17 @@
else
points = s.getPathIterator(transform);
float[] coords = new float[6];
+ double dcoords[] = new double[6];
while(!points.isDone()) {
++traces;
- int segtype = points.currentSegment(coords);
+ int segtype = points.currentSegment(dcoords);
+ int numpoints = (segtype == PathIterator.SEG_CLOSE ? 0
+ : (segtype == PathIterator.SEG_QUADTO ? 2
+ : (segtype == PathIterator.SEG_CUBICTO ? 3
+ : 1)));
+ for (int i = 0; i < numpoints * 2; i++) {
+ coords[i] = (float) dcoords[i];
+ }
normalizeY(coords);
switch(segtype) {
case PathIterator.SEG_CLOSE:
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
iText-questions mailing list
iText-questions@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/itext-questions
Buy the iText book: http://www.1t3xt.com/docs/book.php
Check the site with examples before you ask questions:
http://www.1t3xt.info/examples/
You can also search the keywords list: http://1t3xt.info/tutorials/keywords/