Skip to content

Commit

Permalink
For #23 - Initial prototype of SVG support in PDFs
Browse files Browse the repository at this point in the history
This is a very early prototype using Batik to draw inline SVG graphics
in a PDF document. Still to do are images and text in the SVG. Also to
do is support for Java 2D.
  • Loading branch information
danfickle committed Jun 11, 2016
1 parent 1e5d831 commit 467855c
Show file tree
Hide file tree
Showing 13 changed files with 728 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
*/
package com.openhtmltopdf.extend;

import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.RenderingHints.Key;
import java.awt.geom.AffineTransform;

import com.openhtmltopdf.css.parser.FSColor;
import com.openhtmltopdf.css.style.CalculatedStyle;
Expand All @@ -37,6 +39,24 @@
import com.openhtmltopdf.render.TextDecoration;

public interface OutputDevice {

// Required for SVG output.
public void drawText(RenderingContext c, String text, float x, float y);

public void saveState();
public void restoreState();

public void setTransform(AffineTransform transform);
public AffineTransform getTransform();

public void setPaint(Paint paint);
public void setAlpha(int alpha);

public void setRawClip(Shape s);
public void rawClip(Shape s);
public Shape getRawClip();

// And the rest.
public void drawText(RenderingContext c, InlineText inlineText);
public void drawSelection(RenderingContext c, InlineText inlineText);

Expand Down Expand Up @@ -91,4 +111,7 @@ public void paintBackground(
public boolean isSupportsSelection();

public boolean isSupportsCMYKColors();



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.openhtmltopdf.extend;

import org.w3c.dom.Element;

import com.openhtmltopdf.render.RenderingContext;

public interface SVGDrawer {
public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.RenderingHints.Key;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

Expand All @@ -41,7 +43,6 @@
import com.openhtmltopdf.extend.ReplacedElement;
import com.openhtmltopdf.render.AbstractOutputDevice;
import com.openhtmltopdf.render.BlockBox;
import com.openhtmltopdf.render.BorderPainter;
import com.openhtmltopdf.render.FSFont;
import com.openhtmltopdf.render.InlineLayoutBox;
import com.openhtmltopdf.render.InlineText;
Expand Down Expand Up @@ -289,4 +290,64 @@ public boolean isSupportsSelection() {
public boolean isSupportsCMYKColors() {
return true;
}

@Override
public void drawText(RenderingContext c, String text, float x, float y) {
// TODO Auto-generated method stub

}

@Override
public void saveState() {
// TODO Auto-generated method stub

}

@Override
public void restoreState() {
// TODO Auto-generated method stub

}

@Override
public void setTransform(AffineTransform transform) {
// TODO Auto-generated method stub

}

@Override
public AffineTransform getTransform() {
// TODO
return null;
}

@Override
public void setPaint(Paint paint) {
// TODO Auto-generated method stub

}

@Override
public void setAlpha(int alpha) {
// TODO Auto-generated method stub

}

@Override
public void setRawClip(Shape s) {
// TODO Auto-generated method stub

}

@Override
public void rawClip(Shape s) {
// TODO Auto-generated method stub

}

@Override
public Shape getRawClip() {
// TODO Auto-generated method stub
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Point;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
Expand All @@ -32,49 +32,30 @@
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Float;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import org.apache.pdfbox.contentstream.PDContentStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitHeightDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
Expand All @@ -85,22 +66,18 @@

import com.openhtmltopdf.bidi.BidiReorderer;
import com.openhtmltopdf.bidi.SimpleBidiReorderer;
import com.openhtmltopdf.css.constants.IdentValue;
import com.openhtmltopdf.css.parser.FSCMYKColor;
import com.openhtmltopdf.css.parser.FSColor;
import com.openhtmltopdf.css.parser.FSRGBColor;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.css.style.CssContext;
import com.openhtmltopdf.css.value.FontSpecification;
import com.openhtmltopdf.extend.FSImage;
import com.openhtmltopdf.extend.NamespaceHandler;
import com.openhtmltopdf.extend.OutputDevice;
import com.openhtmltopdf.layout.SharedContext;
import com.openhtmltopdf.pdfboxout.PdfBoxFontResolver.FontDescription;
import com.openhtmltopdf.pdfboxout.PdfBoxTextRenderer.ReplacementChar;
import com.openhtmltopdf.render.AbstractOutputDevice;
import com.openhtmltopdf.render.BlockBox;
import com.openhtmltopdf.render.BorderPainter;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.FSFont;
import com.openhtmltopdf.render.InlineLayoutBox;
Expand All @@ -110,7 +87,6 @@
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.util.Configuration;
import com.openhtmltopdf.util.XRLog;
import com.openhtmltopdf.util.XRRuntimeException;

public class PdfBoxOutputDevice extends AbstractOutputDevice implements OutputDevice {
private static final int FILL = 1;
Expand Down Expand Up @@ -545,7 +521,7 @@ private PdfTextArray makeJustificationArray(String s, JustificationInfo info) {
return array;
}
*/
private AffineTransform getTransform() {
public AffineTransform getTransform() {
return _transform;
}

Expand Down Expand Up @@ -1280,4 +1256,62 @@ public void setRenderingContext(RenderingContext result) {
public void setBidiReorderer(BidiReorderer reorderer) {
_reorderer = reorderer;
}

@Override
public void drawText(RenderingContext c, String text, float x, float y) {
// TODO Auto-generated method stub

}

@Override
public void saveState() {
_cp.saveGraphics();
}

@Override
public void restoreState() {
_cp.restoreGraphics();
}

@Override
public void setTransform(AffineTransform transform) {
_transform = transform;

}

@Override
public void setPaint(Paint paint) {
if (paint instanceof Color) {
Color c = (Color) paint;
this.setColor(new FSRGBColor(c.getRed(), c.getGreen(), c.getBlue()));
}
else {
XRLog.render(Level.WARNING, "Unknown paint");
}
}

@Override
public void setAlpha(int alpha) {

}

@Override
public void setRawClip(Shape s) {
_clip = new Area(s);
followPath(s, CLIP);
}

@Override
public void rawClip(Shape s) {
if (_clip == null)
_clip = new Area(s);
else
_clip.intersect(new Area(s));
followPath(s, CLIP);
}

@Override
public Shape getRawClip() {
return _clip;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import com.openhtmltopdf.extend.FSUriResolver;
import com.openhtmltopdf.extend.HttpStreamFactory;
import com.openhtmltopdf.extend.NamespaceHandler;
import com.openhtmltopdf.extend.SVGDrawer;
import com.openhtmltopdf.extend.UserInterface;
import com.openhtmltopdf.layout.BoxBuilder;
import com.openhtmltopdf.layout.Layer;
Expand Down Expand Up @@ -103,10 +104,10 @@ public class PdfBoxRenderer {
private OutputStream _os;

public PdfBoxRenderer(boolean testMode) {
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL, true, testMode, null, null, null);
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL, true, testMode, null, null, null, null);
}

public PdfBoxRenderer(float dotsPerPoint, int dotsPerPixel, boolean useSubsets, boolean testMode, HttpStreamFactory factory, FSUriResolver _resolver, FSCache _cache) {
public PdfBoxRenderer(float dotsPerPoint, int dotsPerPixel, boolean useSubsets, boolean testMode, HttpStreamFactory factory, FSUriResolver _resolver, FSCache _cache, SVGDrawer svgImpl) {
_pdfDoc = new PDDocument();

_dotsPerPoint = dotsPerPoint;
Expand Down Expand Up @@ -137,7 +138,7 @@ public PdfBoxRenderer(float dotsPerPoint, int dotsPerPixel, boolean useSubsets,
PdfBoxFontResolver fontResolver = new PdfBoxFontResolver(_sharedContext, _pdfDoc, useSubsets);
_sharedContext.setFontResolver(fontResolver);

PdfBoxReplacedElementFactory replacedElementFactory = new PdfBoxReplacedElementFactory(_outputDevice);
PdfBoxReplacedElementFactory replacedElementFactory = new PdfBoxReplacedElementFactory(_outputDevice, svgImpl);
_sharedContext.setReplacedElementFactory(replacedElementFactory);

_sharedContext.setTextRenderer(new PdfBoxTextRenderer());
Expand All @@ -151,8 +152,8 @@ public PdfBoxRenderer(boolean textDirection, boolean testMode,
boolean useSubsets, HttpStreamFactory httpStreamFactory,
BidiSplitterFactory splitterFactory, BidiReorderer reorderer, String html,
Document document, String baseUri, String uri, File file,
OutputStream os, FSUriResolver _resolver, FSCache _cache) {
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL, useSubsets, testMode, httpStreamFactory, _resolver, _cache);
OutputStream os, FSUriResolver _resolver, FSCache _cache, SVGDrawer svgImpl) {
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL, useSubsets, testMode, httpStreamFactory, _resolver, _cache, svgImpl);

if (splitterFactory != null) {
this.setBidiSplitter(splitterFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@
import com.openhtmltopdf.extend.FSImage;
import com.openhtmltopdf.extend.ReplacedElement;
import com.openhtmltopdf.extend.ReplacedElementFactory;
import com.openhtmltopdf.extend.SVGDrawer;
import com.openhtmltopdf.extend.UserAgentCallback;
import com.openhtmltopdf.layout.LayoutContext;
import com.openhtmltopdf.render.BlockBox;
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.simple.extend.FormSubmissionListener;

public class PdfBoxReplacedElementFactory implements ReplacedElementFactory {
private PdfBoxOutputDevice _outputDevice;
private final PdfBoxOutputDevice _outputDevice;
private final SVGDrawer _svgImpl;

public PdfBoxReplacedElementFactory(PdfBoxOutputDevice outputDevice) {
public PdfBoxReplacedElementFactory(PdfBoxOutputDevice outputDevice, SVGDrawer svgImpl) {
_outputDevice = outputDevice;
_svgImpl = svgImpl;
}

public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box,
Expand All @@ -44,7 +48,13 @@ public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box,
}

String nodeName = e.getNodeName();
if (nodeName.equals("img")) {

if (nodeName.equals("svg") &&
_svgImpl != null) {
// TODO: Correct width and height
return new PdfBoxSVGReplacedElement(e, _svgImpl, cssWidth, cssHeight);
}
else if (nodeName.equals("img")) {
String srcAttr = e.getAttribute("src");
if (srcAttr != null && srcAttr.length() > 0) {
FSImage fsImage = uac.getImageResource(srcAttr).getImage();
Expand Down
Loading

0 comments on commit 467855c

Please sign in to comment.