try {
// Have to do this so we can resolve data URIs
StreamSource src = new StreamSource(resourceResolver.getResource(uri));
- src.setSystemId(uri);
+ src.setSystemId(getResourceResolver().getBaseURI().toASCIIString());
return src;
} catch (URISyntaxException use) {
return null;
*/
public FopConfParser(File fopConfFile, ResourceResolver resourceResolver)
throws SAXException, IOException {
- this(new FileInputStream(fopConfFile), fopConfFile.toURI(), resourceResolver);
+ this(new FileInputStream(fopConfFile), fopConfFile.getParentFile().toURI(), resourceResolver);
}
public FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro)
log.debug(tableTag + " lang sys default: " + dt);
}
}
- seScripts.put(scriptTag, new Object[] { dt, ll, seLanguages });
+ if (seLanguages != null) {
+ seScripts.put(scriptTag, new Object[]{dt, ll, seLanguages});
+ }
seLanguages = null;
}
import java.util.Set;
import org.apache.fop.apps.io.InternalResourceResolver;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
/**
private boolean useKerning = true;
/** the character map, mapping Unicode ranges to glyph indices. */
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>();
+ protected Map<Integer, SVGGlyphData> svgs;
private boolean useAdvanced = true;
private boolean simulateStyle;
protected List<SimpleSingleByteEncoding> additionalEncodings;
}
return 0;
}
+
+ public boolean hasSVG() {
+ return svgs != null;
+ }
+
+ public void setSVG(Map<Integer, SVGGlyphData> svgs) {
+ this.svgs = svgs;
+ }
}
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttribute("embedding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttributeAsBoolean("simulate-style", false),
- fontCfg.getAttributeAsBoolean("embed-as-type1", false));
+ fontCfg.getAttributeAsBoolean("embed-as-type1", false),
+ fontCfg.getAttributeAsBoolean("svg", true));
instance.fonts.add(font);
boolean hasTriplets = false;
for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) {
private final boolean embedAsType1;
private final boolean simulateStyle;
+ private final boolean useSVG;
+
private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>();
public List<FontTriplet> getTripletList() {
private Font(String metrics, String embed, String afm, String pfm, String subFont, boolean kerning,
boolean advanced, String encodingMode, String embeddingMode, boolean simulateStyle,
- boolean embedAsType1) {
+ boolean embedAsType1, boolean useSVG) {
this.metrics = metrics;
this.embedUri = embed;
this.afm = afm;
this.embeddingMode = embeddingMode;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
}
/**
public boolean getEmbedAsType1() {
return embedAsType1;
}
+
+ public boolean getUseSVG() {
+ return useSVG;
+ }
}
}
EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode());
EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, font.isKerning(),
font.isAdvanced(), tripletList, subFont, encodingMode, embeddingMode,
- font.getSimulateStyle(), font.getEmbedAsType1());
+ font.getSimulateStyle(), font.getEmbedAsType1(), font.getUseSVG());
if (fontCache != null) {
if (!fontCache.containsFont(embedFontInfo)) {
fontCache.addFont(embedFontInfo, resourceResolver);
/** simulates bold or italic on a regular font */
private final boolean simulateStyle;
private final boolean embedAsType1;
+ private final boolean useSVG;
/** the PostScript name of the font */
protected String postScriptName;
*/
public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, String subFontName, EncodingMode encodingMode,
- EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1) {
+ EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1, boolean useSVG) {
this.kerning = kerning;
this.advanced = advanced;
this.fontTriplets = fontTriplets;
this.fontUris = fontUris;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
}
/**
public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, String subFontName) {
this(fontUris, kerning, advanced, fontTriplets, subFontName, EncodingMode.AUTO,
- EmbeddingMode.AUTO, false, false);
+ EmbeddingMode.AUTO, false, false, true);
}
/**
return embedAsType1;
}
+ public boolean getUseSVG() {
+ return useSVG;
+ }
+
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
public static CustomFont loadFont(FontUris fontUris, String subFontName,
boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode,
boolean useKerning, boolean useAdvanced, InternalResourceResolver resourceResolver,
- boolean simulateStyle, boolean embedAsType1) throws IOException {
+ boolean simulateStyle, boolean embedAsType1, boolean useSVG) throws IOException {
boolean type1 = isType1(fontUris);
FontLoader loader;
if (type1) {
resourceResolver);
} else {
loader = new OFFontLoader(fontUris.getEmbed(), subFontName, embedded, embeddingMode,
- encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1);
+ encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1, useSVG);
}
return loader.getFont();
}
private final boolean useAdvanced;
private boolean simulateStyle;
private boolean embedAsType1;
+ private boolean useSVG;
private final EncodingMode encodingMode;
private final EmbeddingMode embeddingMode;
private final String subFontName;
}
this.simulateStyle = fontInfo.getSimulateStyle();
this.embedAsType1 = fontInfo.getEmbedAsType1();
+ useSVG = fontInfo.getUseSVG();
this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode()
: EncodingMode.AUTO;
this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode()
if (fontUris.getEmbed() == null) {
throw new RuntimeException("Cannot load font. No font URIs available.");
}
- realFont = FontLoader.loadFont(fontUris, subFontName, embedded, embeddingMode,
- encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1);
+ realFont = FontLoader.loadFont(fontUris, subFontName, embedded, embeddingMode, encodingMode,
+ useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1, useSVG);
}
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;
import org.apache.fop.complexscripts.util.CharAssociation;
import org.apache.fop.complexscripts.util.CharNormalize;
import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.util.CharUtilities;
/**
public InputStream getCmapStream() {
return null;
}
+
+ public SVGGlyphData getSVG(char c) {
+ int gid = findGlyphIndex(c);
+ return svgs.get(gid);
+ }
}
try {
OFFontLoader ttfLoader = new OFFontLoader(fontURI, fontName, true,
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced,
- resourceResolver, false, false);
+ resourceResolver, false, false, true);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
try {
FontUris fontUris = new FontUris(fontURI, null);
customFont = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO,
- useKerning, useAdvanced, resourceResolver, false, false);
+ useKerning, useAdvanced, resourceResolver, false, false, true);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
private EmbeddingMode embeddingMode;
private boolean simulateStyle;
private boolean embedAsType1;
+ private boolean useSVG;
/**
* Default constructor
*/
public OFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) {
this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver, false,
- false);
+ false, true);
}
/**
* @param resolver the FontResolver for font URI resolution
* @param simulateStyle Determines whether to simulate font styles if a font does not support those by default.
*/
- public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded,
- EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning,
- boolean useAdvanced, InternalResourceResolver resolver, boolean simulateStyle, boolean embedAsType1) {
+ public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded, EmbeddingMode embeddingMode,
+ EncodingMode encodingMode, boolean useKerning, boolean useAdvanced, InternalResourceResolver resolver,
+ boolean simulateStyle, boolean embedAsType1, boolean useSVG) {
super(fontFileURI, embedded, useKerning, useAdvanced, resolver);
this.subFontName = subFontName;
this.encodingMode = encodingMode;
this.embeddingMode = embeddingMode;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
if (this.encodingMode == EncodingMode.AUTO) {
this.encodingMode = EncodingMode.CID; //Default to CID mode for TrueType
}
if (!supported) {
throw new IOException("The font does not have a Unicode cmap table: " + fontFileURI);
}
- buildFont(otf, ttcFontName, embedAsType1);
+ buildFont(otf, ttcFontName);
loaded = true;
} finally {
IOUtils.closeQuietly(in);
return null;
}
- private void buildFont(OpenFont otf, String ttcFontName, boolean embedAsType1) {
+ private void buildFont(OpenFont otf, String ttcFontName) {
boolean isCid = this.embedded;
if (this.encodingMode == EncodingMode.SINGLE_BYTE) {
isCid = false;
copyGlyphMetricsSingleByte(otf);
}
returnFont.setCMap(getCMap(otf));
+ if (useSVG) {
+ returnFont.setSVG(otf.svgs);
+ }
if (otf.getKerning() != null && useKerning) {
copyKerning(otf, isCid);
/** Vertical Metrics. */
public static final OFTableName VMTX = new OFTableName("vmtx");
+ public static final OFTableName SVG = new OFTableName("SVG ");
+
private final String name;
private OFTableName(String name) {
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
private int[] ansiWidth;
private Map<Integer, List<Integer>> ansiIndex;
+ protected Map<Integer, SVGGlyphData> svgs;
// internal mapping of glyph indexes to unicode indexes
// used for quick mappings in this class
readPostScript();
readOS2();
determineAscDesc();
+ readSVG();
readName();
boolean pcltFound = readPCLT();
}
}
+ private void readSVG() throws IOException {
+ OFDirTabEntry dirTab = dirTabs.get(OFTableName.SVG);
+ if (dirTab != null) {
+ svgs = new LinkedHashMap<>();
+ fontFile.seekSet(dirTab.getOffset());
+ fontFile.readTTFUShort(); //version
+ fontFile.readTTFULong(); //svgDocumentListOffset
+ fontFile.readTTFULong(); //reserved
+ int numEntries = fontFile.readTTFUShort();
+ for (int i = 0; i < numEntries; i++) {
+ int startGlyphID = fontFile.readTTFUShort();
+ fontFile.readTTFUShort(); //endGlyphID
+ SVGGlyphData svgGlyph = new SVGGlyphData();
+ svgGlyph.svgDocOffset = fontFile.readTTFULong();
+ svgGlyph.svgDocLength = fontFile.readTTFULong();
+ svgs.put(startGlyphID, svgGlyph);
+ }
+ for (SVGGlyphData entry : svgs.values()) {
+ seekTab(fontFile, OFTableName.SVG, entry.svgDocOffset);
+ fontFile.readTTFUShort(); //version
+ fontFile.readTTFULong(); //svgDocumentListOffset
+ fontFile.readTTFULong(); //reserved
+ entry.setSVG(fontFile.readTTFString((int) entry.svgDocLength));
+ }
+ }
+ }
+
/**
* Read "hmtx" table and put the horizontal metrics
* in the mtxTab array. If the number of metrics is less
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+package org.apache.fop.fonts.truetype;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.apache.xmlgraphics.util.uri.DataURLUtil;
+
+public class SVGGlyphData {
+ protected long svgDocOffset;
+ protected long svgDocLength;
+ private String svg;
+ public float scale = 1;
+
+ public void setSVG(String svg) {
+ this.svg = svg;
+ }
+
+ public String getDataURL(int height) {
+ try {
+ String modifiedSVG = updateTransform(svg, height);
+ return DataURLUtil.createDataURL(new ByteArrayInputStream(modifiedSVG.getBytes("UTF-8")), "image/svg");
+ } catch (IOException | TransformerException | SAXException | ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String updateTransform(String svg, int height)
+ throws IOException, ParserConfigurationException, SAXException, TransformerException {
+ DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputSource inputSource = new InputSource();
+ inputSource.setCharacterStream(new StringReader(svg));
+ Document doc = documentBuilder.parse(inputSource);
+ NodeList nodes = doc.getElementsByTagName("g");
+ Element gElement = (Element) nodes.item(0);
+ if (gElement != null) {
+ String transform = gElement.getAttribute("transform");
+ if (transform.contains("scale(")) {
+ String scaleStr = transform.split("scale\\(")[1].split("\\)")[0].trim();
+ scale = Float.parseFloat(scaleStr);
+ gElement.removeAttribute("transform");
+ } else {
+ gElement.setAttribute("transform", "translate(0," + height + ")");
+ }
+ } else {
+ Element svgElement = (Element) doc.getElementsByTagName("svg").item(0);
+ svgElement.setAttribute("viewBox", "0 0 1000 " + height);
+ gElement = doc.createElement("g");
+ gElement.setAttribute("transform", "translate(0," + height + ")");
+ NodeList paths = doc.getElementsByTagName("path");
+ for (int i = 0; i < paths.getLength(); i++) {
+ Node path = paths.item(i);
+ if (i == 0) {
+ path.getParentNode().insertBefore(gElement, path);
+ }
+ gElement.appendChild(path);
+ }
+ }
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ StreamResult result = new StreamResult(new StringWriter());
+ DOMSource source = new DOMSource(doc);
+ transformer.transform(source, result);
+ return result.getWriter().toString();
+ }
+}
try {
FontUris fontUris = new FontUris(new URI(fontUri), null);
EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, false, true, null, subfont, EncodingMode.AUTO,
- EmbeddingMode.FULL, false, false);
+ EmbeddingMode.FULL, false, false, true);
Typeface tf = new LazyFont(embedFontInfo, resourceResolver, false).getRealFont();
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset,
import org.apache.fop.ResourceEventProducer;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.Constants;
+import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.ImageHandlerUtil;
int[][] dp, String text, boolean nextIsSpace) throws IFException {
drawText(x, y, letterSpacing, wordSpacing, dp, text);
}
+
+ protected void drawSVGText(MultiByteFont multiByteFont, FontTriplet triplet, int x, int y, String text,
+ IFState state) throws IFException {
+ int sizeMillipoints = state.getFontSize();
+ Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
+ int newx = x;
+ for (char c : text.toCharArray()) {
+ SVGGlyphData svg = multiByteFont.getSVG(c);
+ if (svg != null) {
+ int codePoint = font.mapCodePoint(c);
+ String dataURL = svg.getDataURL(multiByteFont.getCapHeight());
+ Rectangle boundingBox = multiByteFont.getBoundingBox(codePoint, (int) (sizeMillipoints / 1000f));
+ boundingBox.y = y - boundingBox.height - boundingBox.y;
+ boundingBox.x = newx;
+ boundingBox.width = (int) (sizeMillipoints * svg.scale);
+ boundingBox.height = (int) (sizeMillipoints * svg.scale);
+ drawImage(dataURL, boundingBox);
+ }
+ newx += font.getCharWidth(c);
+ }
+ }
}
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
FontUris fontUris = configFontInfo.getFontUris();
- CustomFont fontMetrics = FontLoader.loadFont(fontUris,
- configFontInfo.getSubFontName(), true,
+ CustomFont fontMetrics = FontLoader.loadFont(fontUris, configFontInfo.getSubFontName(), true,
configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(),
configFontInfo.getKerning(), configFontInfo.getAdvanced(), resourceResolver,
- configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1());
+ configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1(),
+ configFontInfo.getUseSVG());
font = new CustomFontMetricsMapper(fontMetrics);
}
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.pdf.PDFArray;
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
-
- if ((dp == null) || IFUtil.isDPOnlyDX(dp)) {
+ String fontKey = getFontInfo().getInternalFontKey(triplet);
+ Typeface typeface = getTypeface(fontKey);
+ if (typeface instanceof MultiByteFont && ((MultiByteFont) typeface).hasSVG()) {
+ drawSVGText((MultiByteFont) typeface, triplet, x, y, text, state);
+ } else if ((dp == null) || IFUtil.isDPOnlyDX(dp)) {
drawTextWithDX(x, y, text, triplet, letterSpacing,
wordSpacing, IFUtil.convertDPToDX(dp));
} else {
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.gvt.GraphicsNode;
-import org.apache.batik.transcoder.SVGAbstractTranscoder;
-import org.apache.batik.transcoder.TranscoderException;
-import org.apache.batik.transcoder.TranscoderInput;
-import org.apache.batik.transcoder.TranscoderOutput;
-import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.ps.ImageEncoder;
import org.apache.xmlgraphics.ps.ImageEncodingHelper;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.image.loader.batik.BatikUtil;
+import org.apache.fop.image.loader.batik.ImageConverterSVG2G2D;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.ps.svg.PSSVGGraphics2D;
ImageXMLDOM imageSVG = (ImageXMLDOM)image;
if (shouldRaster(imageSVG)) {
- InputStream is = renderSVGToInputStream(context, imageSVG);
+ InputStream is = renderSVGToInputStream(imageSVG, pos);
float x = (float) pos.getX() / 1000f;
float y = (float) pos.getY() / 1000f;
}
}
- private InputStream renderSVGToInputStream(RenderingContext context, ImageXMLDOM imageSVG) throws IOException {
- PNGTranscoder png = new PNGTranscoder();
- Float width = getDimension(imageSVG.getDocument(), "width") * 8;
- png.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, width);
- Float height = getDimension(imageSVG.getDocument(), "height") * 8;
- png.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, height);
- TranscoderInput input = new TranscoderInput(imageSVG.getDocument());
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- TranscoderOutput output = new TranscoderOutput(os);
+ private InputStream renderSVGToInputStream(ImageXMLDOM imageSVG, Rectangle destinationRect)
+ throws IOException {
+ Rectangle rectangle;
+ int width;
+ int height;
+ Float widthSVG = getDimension(imageSVG.getDocument(), "width");
+ Float heightSVG = getDimension(imageSVG.getDocument(), "height");
+ if (widthSVG != null && heightSVG != null) {
+ width = (int) (widthSVG * 8);
+ height = (int) (heightSVG * 8);
+ rectangle = new Rectangle(0, 0, width, height);
+ } else {
+ int scale = 10;
+ width = destinationRect.width / scale;
+ height = destinationRect.height / scale;
+ rectangle = new Rectangle(0, 0, destinationRect.width / 100, destinationRect.height / 100);
+ destinationRect.width *= scale;
+ destinationRect.height *= scale;
+ }
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D graphics2D = image.createGraphics();
try {
- png.transcode(input, output);
- } catch (TranscoderException ex) {
- SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
- context.getUserAgent().getEventBroadcaster());
- eventProducer.svgRenderingError(this, ex, imageSVG.getInfo().getOriginalURI());
- } finally {
- os.flush();
- os.close();
+ ImageGraphics2D img = (ImageGraphics2D) new ImageConverterSVG2G2D().convert(imageSVG, new HashMap());
+ img.getGraphics2DImagePainter().paint(graphics2D, rectangle);
+ } catch (ImageException e) {
+ throw new IOException(e);
}
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", os);
return new ByteArrayInputStream(os.toByteArray());
}
}
PSGenerator generator = getGenerator();
generator.useColor(state.getTextColor());
+ FontTriplet triplet = new FontTriplet(state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
+ String fontKey = getFontKey(triplet);
+ Typeface typeface = getTypeface(fontKey);
+ if (typeface instanceof MultiByteFont && ((MultiByteFont) typeface).hasSVG()) {
+ drawSVGText((MultiByteFont) typeface, triplet, x, y, text, state);
+ return;
+ }
beginTextObject();
- FontTriplet triplet = new FontTriplet(
- state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
//TODO Opportunity for font caching if font state is more heavily used
- String fontKey = getFontKey(triplet);
int sizeMillipoints = state.getFontSize();
// This assumes that *all* CIDFonts use a /ToUnicode mapping
- Typeface tf = getTypeface(fontKey);
SingleByteFont singleByteFont = null;
- if (tf instanceof SingleByteFont) {
- singleByteFont = (SingleByteFont)tf;
+ if (typeface instanceof SingleByteFont) {
+ singleByteFont = (SingleByteFont)typeface;
}
Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
PSFontResource res = getDocumentHandler().getPSResourceForFontKey(fontKey);
- boolean otf = tf instanceof MultiByteFont && ((MultiByteFont)tf).isOTFFile();
- useFont(fontKey, sizeMillipoints, otf);
+ boolean isOpenTypeFont = typeface instanceof MultiByteFont && ((MultiByteFont)typeface).isOTFFile();
+ useFont(fontKey, sizeMillipoints, isOpenTypeFont);
if (dp != null && dp[0] != null) {
x += dp[0][0];
int currentEncoding = -1;
for (int i = 0; i < textLen; i++) {
char c = text.charAt(i);
- char mapped = tf.mapChar(c);
+ char mapped = typeface.mapChar(c);
int encoding = mapped / 256;
if (currentEncoding != encoding) {
if (i > 0) {
writeText(text, start, i - start,
- letterSpacing, wordSpacing, dp, font, tf, false);
+ letterSpacing, wordSpacing, dp, font, typeface, false);
}
if (encoding == 0) {
useFont(fontKey, sizeMillipoints, false);
}
}
} else {
- if (tf instanceof MultiByteFont && ((MultiByteFont)tf).isOTFFile()) {
+ if (typeface instanceof MultiByteFont && ((MultiByteFont)typeface).isOTFFile()) {
//Analyze string and split up in order to paint in different sub-fonts/encodings
int curEncoding = 0;
for (int i = start; i < textLen; i++) {
char orgChar = text.charAt(i);
- MultiByteFont mbFont = (MultiByteFont)tf;
+ MultiByteFont mbFont = (MultiByteFont)typeface;
mbFont.mapChar(orgChar);
int origGlyphIdx = mbFont.findGlyphIndex(orgChar);
int newGlyphIdx = mbFont.getUsedGlyphs().get(origGlyphIdx);
int encoding = newGlyphIdx / 256;
if (encoding != curEncoding) {
if (i != 0) {
- writeText(text, start, i - start, letterSpacing, wordSpacing, dp, font, tf,
+ writeText(text, start, i - start, letterSpacing, wordSpacing, dp, font, typeface,
true);
start = i;
}
useFont(fontKey, sizeMillipoints, false);
}
}
- writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, tf,
- tf instanceof MultiByteFont);
+ writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, typeface,
+ typeface instanceof MultiByteFont);
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
}
File file = new File("test/resources/fonts/ttf/DejaVuLGCSerif.ttf");
FontUris fontUris = new FontUris(file.toURI(), null);
font = FontLoader.loadFont(fontUris, "", true, EmbeddingMode.AUTO, EncodingMode.AUTO,
- false, false, resolver, false, false);
+ false, false, resolver, false, false, true);
}
/**
triplets.add(triplet);
FontUris fontUris = new FontUris(embedURI, metricsURI);
sut = new EmbedFontInfo(fontUris, kerning, useAdvanced, triplets, subFontName, encMode,
- embedMode, false, false);
+ embedMode, false, false, true);
}
@Test
InternalResourceResolver rr = ResourceResolverFactory.createDefaultInternalResourceResolver(
new File(".").toURI());
CustomFont realFont = FontLoader.loadFont(new FontUris(new File(s).toURI(), null), null, true,
- EmbeddingMode.SUBSET, EncodingMode.AUTO, true, true, rr, false, true);
+ EmbeddingMode.SUBSET, EncodingMode.AUTO, true, true, rr, false, true, true);
realFont.mapChar('d');
return realFont;
}
OFFontLoader fontLoader = new OFFontLoader(absoluteFilePath, fontName, embedded,
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useComplexScriptFeatures,
- resourceResolver, false, false);
+ resourceResolver, false, false, true);
assertTrue(fontLoader.getFont().hasKerningInfo());
useKerning = false;
fontLoader = new OFFontLoader(absoluteFilePath, fontName, embedded, EmbeddingMode.AUTO,
- EncodingMode.AUTO, useKerning, useComplexScriptFeatures, resourceResolver, false, false);
+ EncodingMode.AUTO, useKerning, useComplexScriptFeatures, resourceResolver, false, false, true);
assertFalse(fontLoader.getFont().hasKerningInfo());
}
}
import org.apache.commons.io.IOUtils;
+import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode;
fos.close();
FontUris fontUris = new FontUris(pfbNoAFM.toURI(), null, null, pfm.toURI());
+ InternalResourceResolver resourceResolver =
+ ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI());
CustomFont x = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true,
- ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI()), false, false);
+ resourceResolver, false, false, true);
Assert.assertEquals(x.getBoundingBox(0, 12).getBounds(), new Rectangle(-240, -60, 0, 60));
} finally {
pfbNoAFM.delete();
PDFFactory pdfFactory = new PDFFactory(doc);
URI uri = new File("test/resources/fonts/otf/SourceSansProBold.otf").toURI();
CustomFont sb = OFFontLoader.loadFont(new FontUris(uri, null),
- null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false);
+ null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false, true);
for (char c = 0; c < 512; c++) {
sb.mapChar(c);
}
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.util.HashMap;
import java.util.Locale;
+import java.util.Map;
import javax.xml.transform.stream.StreamResult;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFPage;
+ "\n"
+ "endstream");
}
+
+ @Test
+ public void testSVGFont() throws IFException, IOException {
+ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+ foUserAgent = fopFactory.newFOUserAgent();
+ PDFDocumentHandler pdfDocumentHandler = new PDFDocumentHandler(new IFContext(foUserAgent));
+ pdfDocumentHandler.setResult(new StreamResult(new ByteArrayOutputStream()));
+ pdfDocumentHandler.startDocument();
+ pdfDocumentHandler.startPage(0, "", "", new Dimension());
+ FontInfo fi = new FontInfo();
+ fi.addFontProperties("f1", new FontTriplet("a", "normal", 400));
+ MultiByteFont font = new MultiByteFont(null, null);
+ font.setWidthArray(new int[1]);
+ Map<Integer, SVGGlyphData> svgs = new HashMap<>();
+ SVGGlyphData svgGlyph = new SVGGlyphData();
+ svgGlyph.setSVG("<svg xmlns=\"http://www.w3.org/2000/svg\">\n"
+ + "<circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" />\n"
+ + "</svg>");
+ svgs.put(0, svgGlyph);
+ font.setSVG(svgs);
+ font.setBBoxArray(new Rectangle[] {new Rectangle()});
+ fi.addMetrics("f1", font);
+ pdfDocumentHandler.setFontInfo(fi);
+ PDFPainter pdfPainter = new PDFPainter(pdfDocumentHandler, null);
+ pdfPainter.setFont("a", "normal", 400, null, 12, null);
+ pdfPainter.drawText(0, 0, 0, 0, null, "test");
+ PDFFilterList filters = pdfPainter.generator.getStream().getFilterList();
+ filters.setDisableAllFilters(true);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ pdfPainter.generator.getStream().output(bos);
+ Assert.assertTrue(bos.toString().contains("0.00012 0 0 0.00012 0 0 cm"));
+ Assert.assertTrue(bos.toString().contains("1 0 0 rg"));
+ }
}
package org.apache.fop.render.ps;
import java.awt.Color;
+import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.ByteArrayOutputStream;
import java.io.File;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.Typeface;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
mbf.setIsOTFFile(otf);
fi.addMetrics(name, mbf);
}
+
+ @Test
+ public void testSVGFont() throws IFException {
+ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+ FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+ PSDocumentHandler psDocumentHandler = new PSDocumentHandler(new IFContext(foUserAgent));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ psDocumentHandler.setResult(new StreamResult(bos));
+ psDocumentHandler.startDocument();
+ psDocumentHandler.startPage(0, "", "", new Dimension());
+ FontInfo fi = new FontInfo();
+ fi.addFontProperties("f1", new FontTriplet("a", "normal", 400));
+ MultiByteFont font = new MultiByteFont(null, null);
+ font.setWidthArray(new int[1]);
+ Map<Integer, SVGGlyphData> svgs = new HashMap<>();
+ SVGGlyphData svgGlyph = new SVGGlyphData();
+ svgGlyph.setSVG("<svg xmlns=\"http://www.w3.org/2000/svg\">\n"
+ + "<circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" />\n"
+ + "</svg>");
+ svgs.put(0, svgGlyph);
+ font.setSVG(svgs);
+ font.setBBoxArray(new Rectangle[] {new Rectangle()});
+ fi.addMetrics("f1", font);
+ psDocumentHandler.setFontInfo(fi);
+ PSPainter psPainter = new PSPainter(psDocumentHandler);
+ psPainter.setFont("a", "normal", 400, null, 12, Color.black);
+ psPainter.drawText(0, 0, 0, 0, null, "test");
+ Assert.assertTrue(bos.toString().contains("%FOPBeginSVG"));
+ Assert.assertTrue(bos.toString().contains("[0.00012 0 0 0.00012 0 0] CT"));
+ Assert.assertTrue(bos.toString().contains("1 0 0 RC"));
+ }
}
URI baseURI = new File("test/resources/fonts/ttf").toURI();
InternalResourceResolver resolver = ResourceResolverFactory.createDefaultInternalResourceResolver(baseURI);
OFFontLoader fontLoader = new OFFontLoader(new URI(filename), null, true,
- EmbeddingMode.AUTO, EncodingMode.AUTO, true, useAdvanced, resolver, false, false);
+ EmbeddingMode.AUTO, EncodingMode.AUTO, true, useAdvanced, resolver, false, false, true);
FontMetrics font = fontLoader.getFont();
registerFont(font, "F" + fontKey++, fontName);
return this;