org.apache.fop.render.afp.AFPFontConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fop Show documentation
Show all versions of fop Show documentation
Apache FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, AFP, TIFF, PNG, SVG, XML (area tree representation), Print, AWT and TXT. The primary output target is PDF.
/*
* 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.render.afp;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.afp.AFPEventProducer;
import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.fonts.AFPFontInfo;
import org.apache.fop.afp.fonts.CharacterSet;
import org.apache.fop.afp.fonts.CharacterSetBuilder;
import org.apache.fop.afp.fonts.CharacterSetType;
import org.apache.fop.afp.fonts.DoubleByteFont;
import org.apache.fop.afp.fonts.OutlineFont;
import org.apache.fop.afp.fonts.RasterFont;
import org.apache.fop.afp.util.AFPResourceAccessor;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.events.EventProducer;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.FontConfig;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.FontTriplet.Matcher;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.FontUris;
import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.fonts.Typeface;
/**
* The config object for AFP fonts, these differ from the the more generic fonts (TTF and Type1).
*/
public final class AFPFontConfig implements FontConfig {
private static final Log LOG = LogFactory.getLog(AFPFontConfig.class);
private final List fontsConfig;
private AFPFontConfig() {
fontsConfig = new ArrayList();
}
/**
* Returns a list of AFP font configuration data.
* @return the AFP font config data
*/
public List getFontConfig() {
return fontsConfig;
}
/**
* The parser for AFP font data.
*/
static final class AFPFontInfoConfigParser implements FontConfigParser {
/** {@inheritDoc}} */
public AFPFontConfig parse(Configuration cfg, FontManager fontManager, boolean strict,
EventProducer eventProducer) throws FOPException {
try {
return new ParserHelper(cfg, fontManager, strict,
(AFPEventProducer) eventProducer).fontConfig;
} catch (ConfigurationException ce) {
throw new FOPException(ce);
}
}
AFPFontConfig getEmptyConfig() {
return new AFPFontConfig();
}
}
private static final class AggregateMatcher implements Matcher {
private final List matchers;
private AggregateMatcher(Matcher... matchers) {
this.matchers = new ArrayList();
for (Matcher matcher : matchers) {
if (matcher != null) {
this.matchers.add(matcher);
}
}
}
public boolean matches(FontTriplet triplet) {
for (Matcher matcher : matchers) {
if (matcher.matches(triplet)) {
return true;
}
}
return false;
}
}
private static final class ParserHelper {
private static final Log LOG = LogFactory.getLog(ParserHelper.class);
private final AFPFontConfig fontConfig;
private final Matcher matcher;
private ParserHelper(Configuration cfg, FontManager fontManager, boolean strict,
AFPEventProducer eventProducer) throws FOPException, ConfigurationException {
Configuration fonts = cfg.getChild("fonts");
Matcher localMatcher = null;
Configuration referencedFontsCfg = fonts.getChild("referenced-fonts", false);
if (referencedFontsCfg != null) {
localMatcher = FontManagerConfigurator.createFontsMatcher(referencedFontsCfg, strict);
}
matcher = new AggregateMatcher(fontManager.getReferencedFontsMatcher(), localMatcher);
fontConfig = new AFPFontConfig();
for (Configuration font : fonts.getChildren("font")) {
buildFont(font, eventProducer);
}
}
private void buildFont(Configuration fontCfg, AFPEventProducer eventProducer)
throws ConfigurationException {
//FontManager fontManager = this.userAgent.getFontManager();
Configuration[] triplets = fontCfg.getChildren("font-triplet");
List tripletList = new ArrayList();
if (triplets.length == 0) {
eventProducer.fontConfigMissing(this, " fontTriplets, String type, String codepage,
String encoding, Configuration cfg, AFPEventProducer eventProducer, String embedURI)
throws ConfigurationException {
AFPFontConfigData config = null;
if ("raster".equalsIgnoreCase(type)) {
config = getRasterFont(fontTriplets, type, codepage, encoding, cfg, eventProducer,
embedURI);
} else if ("outline".equalsIgnoreCase(type)) {
config = getOutlineFont(fontTriplets, type, codepage, encoding, cfg, eventProducer,
embedURI);
} else if ("CIDKeyed".equalsIgnoreCase(type)) {
config = getCIDKeyedFont(fontTriplets, type, codepage, encoding, cfg,
eventProducer, embedURI);
} else if ("truetype".equalsIgnoreCase(type)) {
config = getTruetypeFont(fontTriplets, type, codepage, encoding, cfg, eventProducer, embedURI);
} else {
LOG.error("No or incorrect type attribute: " + type);
}
if (config != null) {
fontConfig.fontsConfig.add(config);
}
}
private CIDKeyedFontConfig getCIDKeyedFont(List fontTriplets, String type,
String codepage, String encoding, Configuration cfg, AFPEventProducer eventProducer,
String uri) throws ConfigurationException {
String characterset = cfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
cfg.getLocation());
return null;
}
String name = cfg.getAttribute("name", characterset);
CharacterSetType charsetType = cfg.getAttributeAsBoolean("ebcdic-dbcs", false)
? CharacterSetType.DOUBLE_BYTE_LINE_DATA : CharacterSetType.DOUBLE_BYTE;
return new CIDKeyedFontConfig(fontTriplets, type, codepage, encoding, characterset,
name, charsetType, isEmbbedable(fontTriplets), uri);
}
private OutlineFontConfig getOutlineFont(List fontTriplets, String type,
String codepage, String encoding, Configuration cfg,
AFPEventProducer eventProducer, String uri) throws ConfigurationException {
String characterset = cfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
cfg.getLocation());
return null;
}
String name = cfg.getAttribute("name", characterset);
String base14 = cfg.getAttribute("base14-font", null);
return new OutlineFontConfig(fontTriplets, type, codepage, encoding, characterset,
name, base14, isEmbbedable(fontTriplets), uri);
}
private TrueTypeFontConfig getTruetypeFont(List fontTriplets, String type, String codepage,
String encoding, Configuration cfg, AFPEventProducer eventProducer,
String uri) throws ConfigurationException {
String name = cfg.getAttribute("name", null);
if (name == null) {
eventProducer.fontConfigMissing(this, "font name attribute", cfg.getLocation());
return null;
}
String subfont = cfg.getAttribute("sub-font", null);
return new TrueTypeFontConfig(fontTriplets, type, codepage, encoding, "",
name, subfont, isEmbbedable(fontTriplets), uri);
}
private RasterFontConfig getRasterFont(List triplets, String type,
String codepage, String encoding, Configuration cfg,
AFPEventProducer eventProducer, String uri)
throws ConfigurationException {
String name = cfg.getAttribute("name", "Unknown");
// Create a new font object
Configuration[] rasters = cfg.getChildren("afp-raster-font");
if (rasters.length == 0) {
eventProducer.fontConfigMissing(this, " charsetData = new ArrayList();
for (Configuration rasterCfg : rasters) {
String characterset = rasterCfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
cfg.getLocation());
return null;
}
float size = rasterCfg.getAttributeAsFloat("size");
int sizeMpt = (int) (size * 1000);
String base14 = rasterCfg.getAttribute("base14-font", null);
charsetData.add(new RasterCharactersetData(characterset, sizeMpt, base14));
}
return new RasterFontConfig(triplets, type, codepage, encoding, null, name, uri, charsetData,
isEmbbedable(triplets));
}
private boolean isEmbbedable(List triplets) {
for (FontTriplet triplet : triplets) {
if (matcher.matches(triplet)) {
return false;
}
}
return true;
}
}
abstract static class AFPFontConfigData {
protected final List triplets;
private final String codePage;
private final String encoding;
private final String name;
private final boolean embeddable;
protected final String uri;
AFPFontConfigData(List triplets, String type, String codePage,
String encoding, String name, boolean embeddable, String uri) {
this.triplets = Collections.unmodifiableList(triplets);
this.codePage = codePage;
this.encoding = encoding;
this.name = name;
this.embeddable = embeddable;
this.uri = uri;
}
static AFPFontInfo getFontInfo(AFPFont font, AFPFontConfigData config) {
return font != null ? new AFPFontInfo(font, config.triplets) : null;
}
abstract AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver,
AFPEventProducer eventProducer) throws IOException;
AFPResourceAccessor getAccessor(InternalResourceResolver resourceResolver) {
return new AFPResourceAccessor(resourceResolver, uri);
}
}
static final class CIDKeyedFontConfig extends AFPFontConfigData {
private final CharacterSetType charsetType;
private final String characterset;
private CIDKeyedFontConfig(List triplets, String type, String codePage, String encoding,
String characterset, String name, CharacterSetType charsetType, boolean embeddable, String uri) {
super(triplets, type, codePage, encoding, name, embeddable, uri);
this.characterset = characterset;
this.charsetType = charsetType;
}
@Override
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer)
throws IOException {
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS(
characterset, super.codePage, super.encoding, charsetType, accessor, eventProducer);
return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet,
eventProducer), this);
}
}
static final class TrueTypeFontConfig extends AFPFontConfigData {
private String characterset;
private String subfont;
private String fontUri;
private TrueTypeFontConfig(List triplets, String type, String codePage,
String encoding, String characterset, String name, String subfont,
boolean embeddable, String uri) {
super(triplets, type, codePage, encoding, name, embeddable, null);
this.characterset = characterset;
this.subfont = subfont;
this.fontUri = uri;
}
@Override
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer)
throws IOException {
try {
Typeface tf = new LazyFont(new EmbedFontInfo(
new FontUris(new URI(fontUri), null)
, false, true, null, subfont), resourceResolver, false).getRealFont();
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset,
super.codePage, super.encoding, tf, accessor, eventProducer);
OutlineFont font = new AFPTrueTypeFont(super.name, super.embeddable, characterSet,
eventProducer, subfont, new URI(fontUri));
return getFontInfo(font, this);
} catch (URISyntaxException e) {
throw new IOException(e);
}
}
}
public static class AFPTrueTypeFont extends OutlineFont {
private String ttc;
private URI uri;
public AFPTrueTypeFont(String name, boolean embeddable, CharacterSet charSet, AFPEventProducer eventProducer,
String ttc, URI uri) {
super(name, embeddable, charSet, eventProducer);
this.ttc = ttc;
this.uri = uri;
}
public FontType getFontType() {
return FontType.TRUETYPE;
}
public String getTTC() {
return ttc;
}
public URI getUri() {
return uri;
}
}
static final class OutlineFontConfig extends AFPFontConfigData {
private final String base14;
private final String characterset;
private OutlineFontConfig(List triplets, String type, String codePage,
String encoding, String characterset, String name, String base14, boolean embeddable, String uri) {
super(triplets, type, codePage, encoding, name, embeddable, uri);
this.characterset = characterset;
this.base14 = base14;
}
@Override
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer)
throws IOException {
CharacterSet characterSet = null;
if (base14 != null) {
try {
Typeface tf = getTypeFace(base14);
characterSet = CharacterSetBuilder.getSingleByteInstance()
.build(characterset, super.codePage,
super.encoding, tf, eventProducer);
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + characterset
+ " could not be found";
LOG.error(msg);
}
} else {
AFPResourceAccessor accessor = getAccessor(resourceResolver);
characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS(
characterset, super.codePage, super.encoding, accessor, eventProducer);
}
return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet,
eventProducer), this);
}
}
private static Typeface getTypeFace(String base14Name) throws ClassNotFoundException {
try {
Class clazz = Class.forName("org.apache.fop.fonts.base14."
+ base14Name).asSubclass(Typeface.class);
return clazz.getDeclaredConstructor().newInstance();
} catch (IllegalAccessException iae) {
LOG.error(iae.getMessage());
} catch (ClassNotFoundException cnfe) {
LOG.error(cnfe.getMessage());
} catch (InstantiationException ie) {
LOG.error(ie.getMessage());
} catch (NoSuchMethodException e) {
LOG.error(e.getMessage());
} catch (InvocationTargetException e) {
LOG.error(e.getMessage());
}
throw new ClassNotFoundException("Couldn't load file for AFP font with base14 name: "
+ base14Name);
}
static final class RasterFontConfig extends AFPFontConfigData {
private final List charsets;
private RasterFontConfig(List triplets, String type, String codePage,
String encoding, String characterset, String name, String uri,
List csetData, boolean embeddable) {
super(triplets, type, codePage, encoding, name, embeddable, uri);
this.charsets = Collections.unmodifiableList(csetData);
}
@Override
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer)
throws IOException {
RasterFont rasterFont = new RasterFont(super.name, super.embeddable);
for (RasterCharactersetData charset : charsets) {
if (charset.base14 != null) {
try {
Typeface tf = getTypeFace(charset.base14);
rasterFont.addCharacterSet(charset.size,
CharacterSetBuilder.getSingleByteInstance().build(
charset.characterset, super.codePage, super.encoding,
tf, eventProducer));
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + charset.characterset
+ " could not be found";
LOG.error(msg);
} catch (IOException ie) {
String msg = "The base 14 font class " + charset.characterset
+ " could not be instantiated";
LOG.error(msg);
}
} else {
AFPResourceAccessor accessor = getAccessor(resourceResolver);
rasterFont.addCharacterSet(charset.size,
CharacterSetBuilder.getSingleByteInstance().buildSBCS(charset.characterset,
super.codePage, super.encoding, accessor, eventProducer));
}
}
return getFontInfo(rasterFont, this);
}
}
static final class RasterCharactersetData {
private final String characterset;
private final int size;
private final String base14;
private RasterCharactersetData(String characterset, int size, String base14) {
this.characterset = characterset;
this.size = size;
this.base14 = base14;
}
}
}