git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1694450 13f79535-47bb-0310-9956-ffa450edef68pull/39/head
import org.apache.fop.afp.fonts.CharacterSet; | import org.apache.fop.afp.fonts.CharacterSet; | ||||
import org.apache.fop.afp.modca.AbstractNamedAFPObject; | import org.apache.fop.afp.modca.AbstractNamedAFPObject; | ||||
import org.apache.fop.afp.modca.AbstractPageObject; | import org.apache.fop.afp.modca.AbstractPageObject; | ||||
import org.apache.fop.afp.modca.ActiveEnvironmentGroup; | |||||
import org.apache.fop.afp.modca.IncludeObject; | import org.apache.fop.afp.modca.IncludeObject; | ||||
import org.apache.fop.afp.modca.IncludedResourceObject; | import org.apache.fop.afp.modca.IncludedResourceObject; | ||||
import org.apache.fop.afp.modca.ObjectContainer; | |||||
import org.apache.fop.afp.modca.PageSegment; | import org.apache.fop.afp.modca.PageSegment; | ||||
import org.apache.fop.afp.modca.Registry; | import org.apache.fop.afp.modca.Registry; | ||||
import org.apache.fop.afp.modca.ResourceGroup; | import org.apache.fop.afp.modca.ResourceGroup; | ||||
import org.apache.fop.afp.modca.ResourceObject; | import org.apache.fop.afp.modca.ResourceObject; | ||||
import org.apache.fop.afp.modca.triplets.EncodingTriplet; | |||||
import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; | |||||
import org.apache.fop.afp.util.AFPResourceAccessor; | import org.apache.fop.afp.util.AFPResourceAccessor; | ||||
import org.apache.fop.afp.util.AFPResourceUtil; | import org.apache.fop.afp.util.AFPResourceUtil; | ||||
import org.apache.fop.apps.io.InternalResourceResolver; | import org.apache.fop.apps.io.InternalResourceResolver; | ||||
import org.apache.fop.fonts.FontType; | |||||
import org.apache.fop.render.afp.AFPFontConfig; | |||||
/** | /** | ||||
* Manages the creation and storage of document resources | * Manages the creation and storage of document resources | ||||
//Embed fonts (char sets and code pages) | //Embed fonts (char sets and code pages) | ||||
if (charSet.getResourceAccessor() != null) { | if (charSet.getResourceAccessor() != null) { | ||||
AFPResourceAccessor accessor = charSet.getResourceAccessor(); | AFPResourceAccessor accessor = charSet.getResourceAccessor(); | ||||
createIncludedResource( | |||||
charSet.getName(), accessor, | |||||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||||
createIncludedResource( | |||||
charSet.getCodePage(), accessor, | |||||
ResourceObject.TYPE_CODE_PAGE); | |||||
if (afpFont.getFontType() == FontType.TRUETYPE) { | |||||
createIncludedResource(afpFont.getFontName(), accessor.resolveURI("."), accessor, | |||||
ResourceObject.TYPE_OBJECT_CONTAINER, true, | |||||
((AFPFontConfig.AFPTrueTypeFont) afpFont).getTTC()); | |||||
} else { | |||||
createIncludedResource( | |||||
charSet.getName(), accessor, | |||||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||||
createIncludedResource( | |||||
charSet.getCodePage(), accessor, | |||||
ResourceObject.TYPE_CODE_PAGE); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
+ " (" + e.getMessage() + ")"); | + " (" + e.getMessage() + ")"); | ||||
} | } | ||||
createIncludedResource(resourceName, uri, accessor, resourceObjectType); | |||||
createIncludedResource(resourceName, uri, accessor, resourceObjectType, false, null); | |||||
} | } | ||||
/** | /** | ||||
* @throws IOException if an I/O error occurs while loading the resource | * @throws IOException if an I/O error occurs while loading the resource | ||||
*/ | */ | ||||
public void createIncludedResource(String resourceName, URI uri, AFPResourceAccessor accessor, | public void createIncludedResource(String resourceName, URI uri, AFPResourceAccessor accessor, | ||||
byte resourceObjectType) throws IOException { | |||||
byte resourceObjectType, boolean truetype, String ttc) throws IOException { | |||||
AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); | AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); | ||||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | AFPResourceInfo resourceInfo = new AFPResourceInfo(); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug("Adding included resource: " + resourceName); | log.debug("Adding included resource: " + resourceName); | ||||
} | } | ||||
IncludedResourceObject resourceContent = new IncludedResourceObject( | |||||
resourceName, accessor, uri); | |||||
ResourceObject resourceObject = factory.createResource(resourceName); | |||||
resourceObject.setDataObject(resourceContent); | |||||
resourceObject.setType(resourceObjectType); | |||||
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel); | ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel); | ||||
resourceGroup.addObject(resourceObject); | |||||
if (truetype) { | |||||
ResourceObject res = factory.createResource(); | |||||
res.setType(ResourceObject.TYPE_OBJECT_CONTAINER); | |||||
ActiveEnvironmentGroup.setupTruetypeMDR(res, false); | |||||
ObjectContainer oc = factory.createObjectContainer(); | |||||
InputStream is; | |||||
try { | |||||
is = accessor.createInputStream(new URI(".")); | |||||
} catch (URISyntaxException e) { | |||||
throw new IOException(e); | |||||
} | |||||
if (ttc != null) { | |||||
oc.setData(extractTTC(ttc, is)); | |||||
} else { | |||||
oc.setData(IOUtils.toByteArray(is)); | |||||
} | |||||
ActiveEnvironmentGroup.setupTruetypeMDR(oc, true); | |||||
res.addTriplet(new EncodingTriplet(1200)); | |||||
res.setFullyQualifiedName(FullyQualifiedNameTriplet.TYPE_REPLACE_FIRST_GID_NAME, | |||||
FullyQualifiedNameTriplet.FORMAT_CHARSTR, resourceName, true); | |||||
res.setDataObject(oc); | |||||
resourceGroup.addObject(res); | |||||
} else { | |||||
ResourceObject resourceObject = factory.createResource(resourceName); | |||||
IncludedResourceObject resourceContent = new IncludedResourceObject( | |||||
resourceName, accessor, uri); | |||||
resourceObject.setDataObject(resourceContent); | |||||
resourceObject.setType(resourceObjectType); | |||||
resourceGroup.addObject(resourceObject); | |||||
} | |||||
//TODO what is the data object? | //TODO what is the data object? | ||||
cachedObject = new CachedObject(resourceName, null); | cachedObject = new CachedObject(resourceName, null); | ||||
} | } | ||||
} | } | ||||
private byte[] extractTTC(String ttc, InputStream is) throws IOException { | |||||
// TrueTypeCollection trueTypeCollection = new TrueTypeCollection(is); | |||||
// for (TrueTypeFont ttf : trueTypeCollection.getFonts()) { | |||||
// String name = ttf.getNaming().getFontFamily(); | |||||
// if (name.equals(ttc)) { | |||||
// ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||||
// TTFSubsetter s = new TTFSubsetter(ttf, null); | |||||
// for (int i = 0; i < 256 * 256; i++) { | |||||
// s.addCharCode(i); | |||||
// } | |||||
// s.writeToStream(bos); | |||||
// return bos.toByteArray(); | |||||
// } | |||||
// } | |||||
throw new IOException(ttc + " not supported"); | |||||
} | |||||
/** | /** | ||||
* Creates an included resource extracting the named resource from an external source. | * Creates an included resource extracting the named resource from an external source. | ||||
* @param resourceName the name of the resource | * @param resourceName the name of the resource |
// the character set name must be 8 chars long | // the character set name must be 8 chars long | ||||
this.name = padName(name); | this.name = padName(name); | ||||
// the code page name must be 8 chars long | |||||
this.codePage = padName(codePage); | |||||
if (codePage == null) { | |||||
this.codePage = null; | |||||
} else { | |||||
// the code page name must be 8 chars long | |||||
this.codePage = padName(codePage); | |||||
} | |||||
this.encoding = encoding; | this.encoding = encoding; | ||||
this.encoder = charsetType.getEncoder(encoding); | this.encoder = charsetType.getEncoder(encoding); |
eventProducer); | eventProducer); | ||||
} | } | ||||
public CharacterSet build(String characterSetName, String codePageName, String encoding, | |||||
Typeface typeface, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | |||||
throws IOException { | |||||
return new FopCharacterSet(codePageName, encoding, characterSetName, typeface, accessor, eventProducer); | |||||
} | |||||
private CharacterSet processFont(String characterSetName, String codePageName, String encoding, | private CharacterSet processFont(String characterSetName, String codePageName, String encoding, | ||||
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | ||||
throws IOException { | throws IOException { |
this.charSet = charSet; | this.charSet = charSet; | ||||
} | } | ||||
public FopCharacterSet(String codePage, String encoding, String name, Typeface charSet, | |||||
AFPResourceAccessor accessor, AFPEventProducer eventProducer) { | |||||
super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, accessor, eventProducer); | |||||
this.charSet = charSet; | |||||
} | |||||
/** | /** | ||||
* Ascender height is the distance from the character baseline to the | * Ascender height is the distance from the character baseline to the | ||||
* top of the character box. A negative ascender height signifies that | * top of the character box. A negative ascender height signifies that |
* | * | ||||
* @param triplet the triplet to add | * @param triplet the triplet to add | ||||
*/ | */ | ||||
protected void addTriplet(AbstractTriplet triplet) { | |||||
public void addTriplet(AbstractTriplet triplet) { | |||||
triplets.add(triplet); | triplets.add(triplet); | ||||
} | } | ||||
* @param fqName the fully qualified name of this resource | * @param fqName the fully qualified name of this resource | ||||
*/ | */ | ||||
public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName) { | public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName) { | ||||
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName)); | |||||
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName, false)); | |||||
} | |||||
public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName, boolean utf16be) { | |||||
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName, utf16be)); | |||||
} | } | ||||
/** @return the fully qualified name of this triplet or null if it does not exist */ | /** @return the fully qualified name of this triplet or null if it does not exist */ |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.fop.afp.AFPDataObjectInfo; | |||||
import org.apache.fop.afp.Factory; | import org.apache.fop.afp.Factory; | ||||
import org.apache.fop.afp.fonts.AFPFont; | import org.apache.fop.afp.fonts.AFPFont; | ||||
import org.apache.fop.afp.modca.triplets.AbstractTriplet; | |||||
import org.apache.fop.afp.modca.triplets.EncodingTriplet; | |||||
import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; | |||||
import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet; | |||||
import org.apache.fop.afp.util.BinaryUtils; | |||||
import org.apache.fop.apps.MimeConstants; | |||||
import org.apache.fop.fonts.FontType; | |||||
import org.apache.fop.render.afp.AFPFontConfig; | |||||
/** | /** | ||||
* An Active Environment Group (AEG) is associated with each page, | * An Active Environment Group (AEG) is associated with each page, | ||||
/** the resource manager */ | /** the resource manager */ | ||||
private final Factory factory; | private final Factory factory; | ||||
private MapDataResource mdr; | |||||
/** | /** | ||||
* Constructor for the ActiveEnvironmentGroup, this takes a | * Constructor for the ActiveEnvironmentGroup, this takes a | ||||
* name parameter which must be 8 characters long. | * name parameter which must be 8 characters long. | ||||
* @param orientation the orientation of the font (e.g. 0, 90, 180, 270) | * @param orientation the orientation of the font (e.g. 0, 90, 180, 270) | ||||
*/ | */ | ||||
public void createFont(int fontRef, AFPFont font, int size, int orientation) { | public void createFont(int fontRef, AFPFont font, int size, int orientation) { | ||||
MapCodedFont mapCodedFont = getCurrentMapCodedFont(); | |||||
if (mapCodedFont == null) { | |||||
mapCodedFont = factory.createMapCodedFont(); | |||||
mapCodedFonts.add(mapCodedFont); | |||||
} | |||||
if (font.getFontType() == FontType.TRUETYPE) { | |||||
if (mdr == null) { | |||||
mdr = factory.createMapDataResource(); | |||||
mapCodedFonts.add(mdr); | |||||
} | |||||
mdr.addTriplet(new EncodingTriplet(1200)); | |||||
String name = font.getFontName(); | |||||
if (((AFPFontConfig.AFPTrueTypeFont)font).getTTC() != null) { | |||||
name = ((AFPFontConfig.AFPTrueTypeFont)font).getTTC(); | |||||
} | |||||
mdr.setFullyQualifiedName(FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_EXTERNAL_RESOURCE_REF, | |||||
FullyQualifiedNameTriplet.FORMAT_CHARSTR, name, true); | |||||
mdr.addTriplet(new FontFullyQualifiedNameTriplet((byte) fontRef)); | |||||
try { | |||||
mapCodedFont.addFont(fontRef, font, size, orientation); | |||||
} catch (MaximumSizeExceededException msee) { | |||||
mapCodedFont = factory.createMapCodedFont(); | |||||
mapCodedFonts.add(mapCodedFont); | |||||
setupTruetypeMDR(mdr, false); | |||||
mdr.addTriplet(new DataObjectFontTriplet(size / 1000)); | |||||
mdr.finishElement(); | |||||
} else { | |||||
MapCodedFont mapCodedFont = getCurrentMapCodedFont(); | |||||
if (mapCodedFont == null) { | |||||
mapCodedFont = factory.createMapCodedFont(); | |||||
mapCodedFonts.add(mapCodedFont); | |||||
} | |||||
try { | try { | ||||
mapCodedFont.addFont(fontRef, font, size, orientation); | mapCodedFont.addFont(fontRef, font, size, orientation); | ||||
} catch (MaximumSizeExceededException ex) { | |||||
// Should never happen (but log just in case) | |||||
LOG.error("createFont():: resulted in a MaximumSizeExceededException"); | |||||
} catch (MaximumSizeExceededException msee) { | |||||
mapCodedFont = factory.createMapCodedFont(); | |||||
mapCodedFonts.add(mapCodedFont); | |||||
try { | |||||
mapCodedFont.addFont(fontRef, font, size, orientation); | |||||
} catch (MaximumSizeExceededException ex) { | |||||
// Should never happen (but log just in case) | |||||
LOG.error("createFont():: resulted in a MaximumSizeExceededException"); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
public static void setupTruetypeMDR(AbstractTripletStructuredObject mdr, boolean res) { | |||||
AFPDataObjectInfo dataInfo = new AFPDataObjectInfo(); | |||||
dataInfo.setMimeType(MimeConstants.MIME_AFP_TRUETYPE); | |||||
mdr.setObjectClassification(ObjectClassificationTriplet.CLASS_DATA_OBJECT_FONT, | |||||
dataInfo.getObjectType(), res, false, res); | |||||
} | |||||
public static class FontFullyQualifiedNameTriplet extends AbstractTriplet { | |||||
private byte fqName; | |||||
public FontFullyQualifiedNameTriplet(byte fqName) { | |||||
super(FULLY_QUALIFIED_NAME); | |||||
this.fqName = fqName; | |||||
} | |||||
public int getDataLength() { | |||||
return 5; | |||||
} | |||||
public void writeToStream(OutputStream os) throws IOException { | |||||
byte[] data = getData(); | |||||
data[2] = FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_INTERNAL_RESOURCE_REF; | |||||
data[3] = FullyQualifiedNameTriplet.FORMAT_CHARSTR; | |||||
data[4] = fqName; | |||||
os.write(data); | |||||
} | |||||
} | |||||
static class DataObjectFontTriplet extends AbstractTriplet { | |||||
private int pointSize; | |||||
public DataObjectFontTriplet(int size) { | |||||
super(DATA_OBJECT_FONT_DESCRIPTOR); | |||||
pointSize = size; | |||||
} | |||||
public int getDataLength() { | |||||
return 16; | |||||
} | |||||
public void writeToStream(OutputStream os) throws IOException { | |||||
byte[] data = getData(); | |||||
data[3] = 0x20; | |||||
byte[] pointSizeBytes = BinaryUtils.convert(pointSize * 20, 2); | |||||
data[4] = pointSizeBytes[0]; //vfs | |||||
data[5] = pointSizeBytes[1]; | |||||
// data[6] = pointSizeBytes[0]; //hsf | |||||
// data[7] = pointSizeBytes[1]; | |||||
//charrot | |||||
data[11] = 0x03; //encenv | |||||
data[13] = 0x01; //encid | |||||
os.write(data); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Getter method for the most recent MapCodedFont added to the | * Getter method for the most recent MapCodedFont added to the | ||||
* Active Environment Group (returns null if no MapCodedFonts exist) | * Active Environment Group (returns null if no MapCodedFonts exist) |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.apache.fop.afp.modca.triplets.AbstractTriplet; | |||||
import org.apache.fop.afp.modca.triplets.Triplet; | |||||
import org.apache.fop.afp.util.BinaryUtils; | import org.apache.fop.afp.util.BinaryUtils; | ||||
/** | /** | ||||
* required for presentation. | * required for presentation. | ||||
*/ | */ | ||||
public class MapDataResource extends AbstractTripletStructuredObject { | public class MapDataResource extends AbstractTripletStructuredObject { | ||||
private List<List<AbstractTriplet>> tripletsList = new ArrayList<List<AbstractTriplet>>(); | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
public MapDataResource() { | public MapDataResource() { | ||||
} | } | ||||
public void finishElement() { | |||||
tripletsList.add(triplets); | |||||
triplets = new ArrayList<AbstractTriplet>(); | |||||
} | |||||
@Override | |||||
protected int getTripletDataLength() { | |||||
int dataLength = 0; | |||||
for (List<AbstractTriplet> l : tripletsList) { | |||||
dataLength += getTripletDataLength(l) + 2; | |||||
} | |||||
return dataLength; | |||||
} | |||||
private int getTripletDataLength(List<AbstractTriplet> l) { | |||||
int dataLength = 0; | |||||
for (Triplet triplet : l) { | |||||
dataLength += triplet.getDataLength(); | |||||
} | |||||
return dataLength; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void writeToStream(OutputStream os) throws IOException { | public void writeToStream(OutputStream os) throws IOException { | ||||
super.writeStart(os); | super.writeStart(os); | ||||
byte[] data = new byte[11]; | |||||
byte[] data = new byte[9]; | |||||
copySF(data, Type.MAP, Category.DATA_RESOURCE); | copySF(data, Type.MAP, Category.DATA_RESOURCE); | ||||
int tripletDataLen = getTripletDataLength(); | int tripletDataLen = getTripletDataLength(); | ||||
byte[] len = BinaryUtils.convert(10 + tripletDataLen, 2); | |||||
byte[] len = BinaryUtils.convert(8 + tripletDataLen, 2); | |||||
data[1] = len[0]; | data[1] = len[0]; | ||||
data[2] = len[1]; | data[2] = len[1]; | ||||
len = BinaryUtils.convert(2 + tripletDataLen, 2); | |||||
data[9] = len[0]; | |||||
data[10] = len[1]; | |||||
os.write(data); | os.write(data); | ||||
writeTriplets(os); | |||||
for (List<AbstractTriplet> l : tripletsList) { | |||||
len = BinaryUtils.convert(2 + getTripletDataLength(l), 2); | |||||
os.write(len); | |||||
writeObjects(l, os); | |||||
} | |||||
} | } | ||||
} | } |
public class ObjectContainer extends AbstractDataObject { | public class ObjectContainer extends AbstractDataObject { | ||||
/** the object container data maximum length */ | /** the object container data maximum length */ | ||||
private static final int MAX_DATA_LEN = 32759; | |||||
private static final int MAX_DATA_LEN = 8192; | |||||
private byte[] data; | private byte[] data; | ||||
MimeConstants.MIME_PCL | MimeConstants.MIME_PCL | ||||
) | ) | ||||
); | ); | ||||
mimeObjectTypeMap.put( | |||||
MimeConstants.MIME_AFP_TRUETYPE, | |||||
new ObjectType( | |||||
COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT, | |||||
new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x33}, | |||||
"TrueType/OpenType Font Resource Object", | |||||
true, | |||||
MimeConstants.MIME_AFP_TRUETYPE | |||||
) | |||||
); | |||||
// mimeObjectTypeMap.put( | // mimeObjectTypeMap.put( | ||||
// null, | |||||
// new ObjectType( | |||||
// COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT, | |||||
// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x33}, | |||||
// "TrueType/OpenType Font Resource Object", | |||||
// true, | |||||
// null | |||||
// ) | |||||
// ); | |||||
// mimeObjectTypeMap.put( | |||||
// null, | |||||
// MimeConstants.MIME_AFP_TTC, | |||||
// new ObjectType( | // new ObjectType( | ||||
// COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT, | // COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT, | ||||
// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x35}, | // new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x35}, | ||||
// "TrueType/OpenType Font Collection Resource Object", | // "TrueType/OpenType Font Collection Resource Object", | ||||
// true, | // true, | ||||
// null | |||||
// MimeConstants.MIME_AFP_TTC | |||||
// ) | // ) | ||||
// ); | // ); | ||||
} | } |
/** the actual fully qualified name */ | /** the actual fully qualified name */ | ||||
private final String fqName; | private final String fqName; | ||||
private String encoding = AFPConstants.EBCIDIC_ENCODING; | |||||
private int charlen = 1; | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* | * | ||||
* @param format the fully qualified name format | * @param format the fully qualified name format | ||||
* @param fqName the fully qualified name | * @param fqName the fully qualified name | ||||
*/ | */ | ||||
public FullyQualifiedNameTriplet(byte type, byte format, String fqName) { | |||||
public FullyQualifiedNameTriplet(byte type, byte format, String fqName, boolean utf16be) { | |||||
super(FULLY_QUALIFIED_NAME); | super(FULLY_QUALIFIED_NAME); | ||||
this.type = type; | this.type = type; | ||||
this.format = format; | this.format = format; | ||||
this.fqName = fqName; | this.fqName = fqName; | ||||
if (utf16be) { | |||||
encoding = "UTF-16BE"; | |||||
charlen = 2; | |||||
} | |||||
} | } | ||||
/** | /** | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public int getDataLength() { | public int getDataLength() { | ||||
return 4 + fqName.length(); | |||||
return 4 + (fqName.length() * charlen); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
// FQName | // FQName | ||||
byte[] fqNameBytes; | byte[] fqNameBytes; | ||||
String encoding = AFPConstants.EBCIDIC_ENCODING; | |||||
if (format == FORMAT_URL) { | if (format == FORMAT_URL) { | ||||
encoding = AFPConstants.US_ASCII_ENCODING; | encoding = AFPConstants.US_ASCII_ENCODING; | ||||
} | } |
try { | try { | ||||
getResourceManager().createIncludedResource(formMap.getName(), | getResourceManager().createIncludedResource(formMap.getName(), | ||||
formMap.getSrc(), accessor, | formMap.getSrc(), accessor, | ||||
ResourceObject.TYPE_FORMDEF); | |||||
ResourceObject.TYPE_FORMDEF, false, null); | |||||
} catch (IOException ioe) { | } catch (IOException ioe) { | ||||
throw new IFException( | throw new IFException( | ||||
"I/O error while embedding form map resource: " + formMap.getName(), ioe); | "I/O error while embedding form map resource: " + formMap.getName(), ioe); |
package org.apache.fop.render.afp; | package org.apache.fop.render.afp; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.net.URI; | |||||
import java.net.URISyntaxException; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.apps.io.InternalResourceResolver; | import org.apache.fop.apps.io.InternalResourceResolver; | ||||
import org.apache.fop.events.EventProducer; | import org.apache.fop.events.EventProducer; | ||||
import org.apache.fop.fonts.EmbedFontInfo; | |||||
import org.apache.fop.fonts.FontConfig; | import org.apache.fop.fonts.FontConfig; | ||||
import org.apache.fop.fonts.FontManager; | import org.apache.fop.fonts.FontManager; | ||||
import org.apache.fop.fonts.FontManagerConfigurator; | import org.apache.fop.fonts.FontManagerConfigurator; | ||||
import org.apache.fop.fonts.FontTriplet; | import org.apache.fop.fonts.FontTriplet; | ||||
import org.apache.fop.fonts.FontTriplet.Matcher; | 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.FontUtil; | ||||
import org.apache.fop.fonts.LazyFont; | |||||
import org.apache.fop.fonts.Typeface; | import org.apache.fop.fonts.Typeface; | ||||
/** | /** | ||||
triplet.getAttribute("style"), weight); | triplet.getAttribute("style"), weight); | ||||
tripletList.add(fontTriplet); | tripletList.add(fontTriplet); | ||||
} | } | ||||
String tturi = fontCfg.getAttribute("embed-url", null); | |||||
if (tturi != null) { | |||||
fontFromType(tripletList, "truetype", null, "UTF-16BE", fontCfg, eventProducer, tturi); | |||||
return; | |||||
} | |||||
//build the fonts | //build the fonts | ||||
Configuration[] config = fontCfg.getChildren("afp-font"); | Configuration[] config = fontCfg.getChildren("afp-font"); | ||||
if (config.length == 0) { | if (config.length == 0) { | ||||
embedURI); | embedURI); | ||||
} else if ("CIDKeyed".equalsIgnoreCase(type)) { | } else if ("CIDKeyed".equalsIgnoreCase(type)) { | ||||
config = getCIDKeyedFont(fontTriplets, type, codepage, encoding, cfg, | config = getCIDKeyedFont(fontTriplets, type, codepage, encoding, cfg, | ||||
eventProducer, | |||||
embedURI); | |||||
eventProducer, embedURI); | |||||
} else if ("truetype".equalsIgnoreCase(type)) { | |||||
config = getTruetypeFont(fontTriplets, type, codepage, encoding, cfg, eventProducer, embedURI); | |||||
} else { | } else { | ||||
LOG.error("No or incorrect type attribute: " + type); | LOG.error("No or incorrect type attribute: " + type); | ||||
} | } | ||||
name, base14, isEmbbedable(fontTriplets), uri); | name, base14, isEmbbedable(fontTriplets), uri); | ||||
} | } | ||||
private TrueTypeFontConfig getTruetypeFont(List<FontTriplet> 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<FontTriplet> triplets, String type, | private RasterFontConfig getRasterFont(List<FontTriplet> triplets, String type, | ||||
String codepage, String encoding, Configuration cfg, | String codepage, String encoding, Configuration cfg, | ||||
AFPEventProducer eventProducer, String uri) | AFPEventProducer eventProducer, String uri) | ||||
} | } | ||||
abstract static class AFPFontConfigData { | abstract static class AFPFontConfigData { | ||||
private final List<FontTriplet> triplets; | |||||
protected final List<FontTriplet> triplets; | |||||
private final String codePage; | private final String codePage; | ||||
private final String encoding; | private final String encoding; | ||||
private final String name; | private final String name; | ||||
private final boolean embeddable; | private final boolean embeddable; | ||||
private final String uri; | |||||
protected final String uri; | |||||
AFPFontConfigData(List<FontTriplet> triplets, String type, String codePage, | AFPFontConfigData(List<FontTriplet> triplets, String type, String codePage, | ||||
String encoding, String name, boolean embeddable, String uri) { | String encoding, String name, boolean embeddable, String uri) { | ||||
} | } | ||||
} | } | ||||
static final class TrueTypeFontConfig extends AFPFontConfigData { | |||||
private String characterset; | |||||
private String subfont; | |||||
private TrueTypeFontConfig(List<FontTriplet> triplets, String type, String codePage, | |||||
String encoding, String characterset, String name, String subfont, | |||||
boolean embeddable, String uri) { | |||||
super(triplets, type, codePage, encoding, name, embeddable, uri); | |||||
this.characterset = characterset; | |||||
this.subfont = subfont; | |||||
} | |||||
@Override | |||||
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer) | |||||
throws IOException { | |||||
Typeface tf; | |||||
try { | |||||
tf = new LazyFont(new EmbedFontInfo( | |||||
new FontUris(new URI(uri), null) | |||||
, false, true, null, subfont), resourceResolver, false).getRealFont(); | |||||
} catch (URISyntaxException e) { | |||||
throw new IOException(e); | |||||
} | |||||
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); | |||||
return getFontInfo(font, this); | |||||
} | |||||
} | |||||
public static class AFPTrueTypeFont extends OutlineFont { | |||||
private String ttc; | |||||
public AFPTrueTypeFont(String name, boolean embeddable, CharacterSet charSet, AFPEventProducer eventProducer, | |||||
String ttc) { | |||||
super(name, embeddable, charSet, eventProducer); | |||||
this.ttc = ttc; | |||||
} | |||||
public FontType getFontType() { | |||||
return FontType.TRUETYPE; | |||||
} | |||||
public String getTTC() { | |||||
return ttc; | |||||
} | |||||
} | |||||
static final class OutlineFontConfig extends AFPFontConfigData { | static final class OutlineFontConfig extends AFPFontConfigData { | ||||
private final String base14; | private final String base14; | ||||
private final String characterset; | private final String characterset; |
import org.apache.fop.afp.util.AFPResourceAccessor; | import org.apache.fop.afp.util.AFPResourceAccessor; | ||||
import org.apache.fop.fonts.Font; | import org.apache.fop.fonts.Font; | ||||
import org.apache.fop.fonts.FontTriplet; | import org.apache.fop.fonts.FontTriplet; | ||||
import org.apache.fop.fonts.FontType; | |||||
import org.apache.fop.fonts.Typeface; | import org.apache.fop.fonts.Typeface; | ||||
import org.apache.fop.render.ImageHandlerUtil; | import org.apache.fop.render.ImageHandlerUtil; | ||||
import org.apache.fop.render.RenderingContext; | import org.apache.fop.render.RenderingContext; | ||||
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement); | builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement); | ||||
boolean fixedSpaceMode = false; | boolean fixedSpaceMode = false; | ||||
int ttPos = p.x; | |||||
for (int i = 0; i < l; i++) { | for (int i = 0; i < l; i++) { | ||||
char orgChar = text.charAt(i); | char orgChar = text.charAt(i); | ||||
float glyphAdjust = 0; | float glyphAdjust = 0; | ||||
if (CharUtilities.isFixedWidthSpace(orgChar)) { | |||||
if (afpFont.getFontType() == FontType.TRUETYPE) { | |||||
flushText(builder, sb, charSet); | |||||
fixedSpaceMode = true; | |||||
int charWidth = font.getCharWidth(orgChar); | |||||
sb.append(orgChar); | |||||
glyphAdjust += charWidth; | |||||
} else if (CharUtilities.isFixedWidthSpace(orgChar)) { | |||||
flushText(builder, sb, charSet); | flushText(builder, sb, charSet); | ||||
builder.setVariableSpaceCharacterIncrement( | builder.setVariableSpaceCharacterIncrement( | ||||
fixedSpaceCharacterIncrement); | fixedSpaceCharacterIncrement); | ||||
glyphAdjust += dx[i + 1]; | glyphAdjust += dx[i + 1]; | ||||
} | } | ||||
if (glyphAdjust != 0) { | |||||
if (afpFont.getFontType() == FontType.TRUETYPE) { | |||||
flushText(builder, sb, charSet); | |||||
ttPos += Math.round(unitConv.mpt2units(glyphAdjust)); | |||||
builder.absoluteMoveInline(ttPos); | |||||
} else if (glyphAdjust != 0) { | |||||
flushText(builder, sb, charSet); | flushText(builder, sb, charSet); | ||||
int increment = Math.round(unitConv.mpt2units(glyphAdjust)); | int increment = Math.round(unitConv.mpt2units(glyphAdjust)); | ||||
builder.relativeMoveInline(increment); | builder.relativeMoveInline(increment); |
/* | |||||
* 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.ByteArrayInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.apache.fop.afp.AFPConstants; | |||||
import org.apache.fop.afp.ptoca.PtocaBuilder; | |||||
import junit.framework.Assert; | |||||
public class AFPParser { | |||||
private boolean readText; | |||||
public AFPParser(boolean readText) { | |||||
this.readText = readText; | |||||
} | |||||
public void read(InputStream bis, StringBuilder sb) throws IOException { | |||||
while (bis.available() > 0) { | |||||
readField(bis, sb); | |||||
} | |||||
} | |||||
private void readField(InputStream bis, StringBuilder sb) throws IOException { | |||||
bis.read(); | |||||
int len = getLength(bis.read(), bis.read()); | |||||
byte[] field = new byte[len - 2]; | |||||
bis.read(field); | |||||
InputStream fieldStream = new ByteArrayInputStream(field); | |||||
fieldStream.read(); | |||||
byte type = (byte) fieldStream.read(); | |||||
byte category = (byte) fieldStream.read(); | |||||
fieldStream.skip(3); | |||||
String typeStr = TYPE_MAP.get(type & 0xFF); | |||||
String catStr = CATEGORY_MAP.get(category & 0xFF); | |||||
if (typeStr != null && catStr != null) { | |||||
sb.append(typeStr + " " + catStr); | |||||
if (typeStr.equals("BEGIN") || typeStr.equals("END")) { | |||||
byte[] name = new byte[8]; | |||||
fieldStream.read(name); | |||||
sb.append(" " + new String(name, AFPConstants.EBCIDIC_ENCODING)); | |||||
fieldStream.skip(2); | |||||
readTriplet(fieldStream, sb); | |||||
} else if (typeStr.equals("MAP")) { | |||||
fieldStream.skip(2); | |||||
readTriplet(fieldStream, sb); | |||||
} else if (typeStr.equals("DESCRIPTOR") && catStr.equals("OBJECT_AREA")) { | |||||
readTriplet(fieldStream, sb); | |||||
} else if (typeStr.equals("DATA") && catStr.equals("PRESENTATION_TEXT") && readText) { | |||||
readData(fieldStream, sb); | |||||
} | |||||
sb.append("\n"); | |||||
} | |||||
} | |||||
private void readData(InputStream bis, StringBuilder sb) throws IOException { | |||||
Assert.assertEquals(bis.read(), 0x2B); | |||||
Assert.assertEquals(bis.read(), 0xD3); | |||||
while (bis.available() > 0) { | |||||
int len = bis.read(); | |||||
int functionType = bis.read(); | |||||
sb.append(" " + PTOCA_MAP.get(functionType)); | |||||
if ("TRN".equals(PTOCA_MAP.get(functionType))) { | |||||
byte[] data = new byte[len - 2]; | |||||
bis.read(data); | |||||
sb.append(" " + new String(data, "UTF-16BE")); | |||||
} else { | |||||
bis.skip(len - 2); | |||||
} | |||||
} | |||||
} | |||||
private void readTriplet(InputStream des, StringBuilder sb) throws IOException { | |||||
if (des.available() > 0) { | |||||
sb.append(" Triplets: "); | |||||
} | |||||
while (des.available() > 0) { | |||||
int len2 = des.read(); | |||||
int id = des.read(); | |||||
int b = id & 0xFF; | |||||
if (TRIPLET_MAP.containsKey(b)) { | |||||
sb.append(TRIPLET_MAP.get(b) + ","); | |||||
} else { | |||||
sb.append(String.format("0x%02X,", b)); | |||||
} | |||||
des.skip(len2 - 2); | |||||
} | |||||
} | |||||
private int getLength(int a, int b) { | |||||
return (a * 256) + b; | |||||
} | |||||
private static final Map<Integer, String> TYPE_MAP = new HashMap<Integer, String>(); | |||||
private static final Map<Integer, String> CATEGORY_MAP = new HashMap<Integer, String>(); | |||||
private static final Map<Integer, String> TRIPLET_MAP = new HashMap<Integer, String>(); | |||||
private static final Map<Integer, String> PTOCA_MAP = new HashMap<Integer, String>(); | |||||
static { | |||||
PTOCA_MAP.put(0xC2 | PtocaBuilder.CHAIN_BIT, "SIA"); | |||||
PTOCA_MAP.put(0xC4 | PtocaBuilder.CHAIN_BIT, "SVI"); | |||||
PTOCA_MAP.put(0xC6 | PtocaBuilder.CHAIN_BIT, "AMI"); | |||||
PTOCA_MAP.put(0xC8 | PtocaBuilder.CHAIN_BIT, "RMI"); | |||||
PTOCA_MAP.put(0xD2 | PtocaBuilder.CHAIN_BIT, "AMB"); | |||||
PTOCA_MAP.put(0xDA | PtocaBuilder.CHAIN_BIT, "TRN"); | |||||
PTOCA_MAP.put(0xE4 | PtocaBuilder.CHAIN_BIT, "DIR"); | |||||
PTOCA_MAP.put(0xE6 | PtocaBuilder.CHAIN_BIT, "DBR"); | |||||
PTOCA_MAP.put(0x80 | PtocaBuilder.CHAIN_BIT, "SEC"); | |||||
PTOCA_MAP.put(0xF0 | PtocaBuilder.CHAIN_BIT, "SCFL"); | |||||
PTOCA_MAP.put(0xF6 | PtocaBuilder.CHAIN_BIT, "STO"); | |||||
PTOCA_MAP.put(0xF8 | PtocaBuilder.CHAIN_BIT, "NOP"); | |||||
TYPE_MAP.put(0xA0, "ATTRIBUTE"); | |||||
TYPE_MAP.put(0xA2, "COPY_COUNT"); | |||||
TYPE_MAP.put(0xA6, "DESCRIPTOR"); | |||||
TYPE_MAP.put(0xA7, "CONTROL"); | |||||
TYPE_MAP.put(0xA8, "BEGIN"); | |||||
TYPE_MAP.put(0xA9, "END"); | |||||
TYPE_MAP.put(0xAB, "MAP"); | |||||
TYPE_MAP.put(0xAC, "POSITION"); | |||||
TYPE_MAP.put(0xAD, "PROCESS"); | |||||
TYPE_MAP.put(0xAF, "INCLUDE"); | |||||
TYPE_MAP.put(0xB0, "TABLE"); | |||||
TYPE_MAP.put(0xB1, "MIGRATION"); | |||||
TYPE_MAP.put(0xB2, "VARIABLE"); | |||||
TYPE_MAP.put(0xB4, "LINK"); | |||||
TYPE_MAP.put(0xEE, "DATA"); | |||||
CATEGORY_MAP.put(0x5F, "PAGE_SEGMENT"); | |||||
CATEGORY_MAP.put(0x6B, "OBJECT_AREA"); | |||||
CATEGORY_MAP.put(0x77, "COLOR_ATTRIBUTE_TABLE"); | |||||
CATEGORY_MAP.put(0x7B, "IM_IMAGE"); | |||||
CATEGORY_MAP.put(0x88, "MEDIUM"); | |||||
CATEGORY_MAP.put(0x8A, "CODED_FONT"); | |||||
CATEGORY_MAP.put(0x90, "PROCESS_ELEMENT"); | |||||
CATEGORY_MAP.put(0x92, "OBJECT_CONTAINER"); | |||||
CATEGORY_MAP.put(0x9B, "PRESENTATION_TEXT"); | |||||
CATEGORY_MAP.put(0xA7, "INDEX"); | |||||
CATEGORY_MAP.put(0xA8, "DOCUMENT"); | |||||
CATEGORY_MAP.put(0xAD, "PAGE_GROUP"); | |||||
CATEGORY_MAP.put(0xAF, "PAGE"); | |||||
CATEGORY_MAP.put(0xBB, "GRAPHICS"); | |||||
CATEGORY_MAP.put(0xC3, "DATA_RESOURCE"); | |||||
CATEGORY_MAP.put(0xC4, "DOCUMENT_ENVIRONMENT_GROUP"); | |||||
CATEGORY_MAP.put(0xC6, "RESOURCE_GROUP"); | |||||
CATEGORY_MAP.put(0xC7, "OBJECT_ENVIRONMENT_GROUP"); | |||||
CATEGORY_MAP.put(0xC9, "ACTIVE_ENVIRONMENT_GROUP"); | |||||
CATEGORY_MAP.put(0xCC, "MEDIUM_MAP"); | |||||
CATEGORY_MAP.put(0xCD, "FORM_MAP"); | |||||
CATEGORY_MAP.put(0xCE, "NAME_RESOURCE"); | |||||
CATEGORY_MAP.put(0xD8, "PAGE_OVERLAY"); | |||||
CATEGORY_MAP.put(0xD9, "RESOURCE_ENVIROMENT_GROUP"); | |||||
CATEGORY_MAP.put(0xDF, "OVERLAY"); | |||||
CATEGORY_MAP.put(0xEA, "DATA_SUPRESSION"); | |||||
CATEGORY_MAP.put(0xEB, "BARCODE"); | |||||
CATEGORY_MAP.put(0xEE, "NO_OPERATION"); | |||||
CATEGORY_MAP.put(0xFB, "IMAGE"); | |||||
TRIPLET_MAP.put(0x02, "FULLY_QUALIFIED_NAME"); | |||||
TRIPLET_MAP.put(0x04, "MAPPING_OPTION"); | |||||
TRIPLET_MAP.put(0x10, "OBJECT_CLASSIFICATION"); | |||||
TRIPLET_MAP.put(0x18, "MODCA_INTERCHANGE_SET"); | |||||
TRIPLET_MAP.put(0x1F, "FONT_DESCRIPTOR_SPECIFICATION"); | |||||
TRIPLET_MAP.put(0x21, "OBJECT_FUNCTION_SET_SPECIFICATION"); | |||||
TRIPLET_MAP.put(0x22, "EXTENDED_RESOURCE_LOCAL_IDENTIFIER"); | |||||
TRIPLET_MAP.put(0x24, "RESOURCE_LOCAL_IDENTIFIER"); | |||||
TRIPLET_MAP.put(0x25, "RESOURCE_SECTION_NUMBER"); | |||||
TRIPLET_MAP.put(0x26, "CHARACTER_ROTATION"); | |||||
TRIPLET_MAP.put(0x2D, "OBJECT_BYTE_OFFSET"); | |||||
TRIPLET_MAP.put(0x36, "ATTRIBUTE_VALUE"); | |||||
TRIPLET_MAP.put(0x43, "DESCRIPTOR_POSITION"); | |||||
TRIPLET_MAP.put(0x45, "MEDIA_EJECT_CONTROL"); | |||||
TRIPLET_MAP.put(0x46, "PAGE_OVERLAY_CONDITIONAL_PROCESSING"); | |||||
TRIPLET_MAP.put(0x47, "RESOURCE_USAGE_ATTRIBUTE"); | |||||
TRIPLET_MAP.put(0x4B, "MEASUREMENT_UNITS"); | |||||
TRIPLET_MAP.put(0x4C, "OBJECT_AREA_SIZE"); | |||||
TRIPLET_MAP.put(0x4D, "AREA_DEFINITION"); | |||||
TRIPLET_MAP.put(0x4E, "COLOR_SPECIFICATION"); | |||||
TRIPLET_MAP.put(0x50, "ENCODING_SCHEME_ID"); | |||||
TRIPLET_MAP.put(0x56, "MEDIUM_MAP_PAGE_NUMBER"); | |||||
TRIPLET_MAP.put(0x57, "OBJECT_BYTE_EXTENT"); | |||||
TRIPLET_MAP.put(0x58, "OBJECT_STRUCTURED_FIELD_OFFSET"); | |||||
TRIPLET_MAP.put(0x59, "OBJECT_STRUCTURED_FIELD_EXTENT"); | |||||
TRIPLET_MAP.put(0x5A, "OBJECT_OFFSET"); | |||||
TRIPLET_MAP.put(0x5D, "FONT_HORIZONTAL_SCALE_FACTOR"); | |||||
TRIPLET_MAP.put(0x5E, "OBJECT_COUNT"); | |||||
TRIPLET_MAP.put(0x62, "OBJECT_DATE_AND_TIMESTAMP"); | |||||
TRIPLET_MAP.put(0x65, "COMMENT"); | |||||
TRIPLET_MAP.put(0x68, "MEDIUM_ORIENTATION"); | |||||
TRIPLET_MAP.put(0x6C, "RESOURCE_OBJECT_INCLUDE"); | |||||
TRIPLET_MAP.put(0x70, "PRESENTATION_SPACE_RESET_MIXING"); | |||||
TRIPLET_MAP.put(0x71, "PRESENTATION_SPACE_MIXING_RULE"); | |||||
TRIPLET_MAP.put(0x72, "UNIVERSAL_DATE_AND_TIMESTAMP"); | |||||
TRIPLET_MAP.put(0x74, "TONER_SAVER"); | |||||
TRIPLET_MAP.put(0x75, "COLOR_FIDELITY"); | |||||
TRIPLET_MAP.put(0x78, "FONT_FIDELITY"); | |||||
TRIPLET_MAP.put(0x80, "ATTRIBUTE_QUALIFIER"); | |||||
TRIPLET_MAP.put(0x81, "PAGE_POSITION_INFORMATION"); | |||||
TRIPLET_MAP.put(0x82, "PARAMETER_VALUE"); | |||||
TRIPLET_MAP.put(0x83, "PRESENTATION_CONTROL"); | |||||
TRIPLET_MAP.put(0x84, "FONT_RESOLUTION_AND_METRIC_TECHNOLOGY"); | |||||
TRIPLET_MAP.put(0x85, "FINISHING_OPERATION"); | |||||
TRIPLET_MAP.put(0x86, "TEXT_FIDELITY"); | |||||
TRIPLET_MAP.put(0x87, "MEDIA_FIDELITY"); | |||||
TRIPLET_MAP.put(0x88, "FINISHING_FIDELITY"); | |||||
TRIPLET_MAP.put(0x8B, "DATA_OBJECT_FONT_DESCRIPTOR"); | |||||
TRIPLET_MAP.put(0x8C, "LOCALE_SELECTOR"); | |||||
TRIPLET_MAP.put(0x8E, "UP3I_FINISHING_OPERATION"); | |||||
TRIPLET_MAP.put(0x91, "COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR"); | |||||
TRIPLET_MAP.put(0x95, "RENDERING_INTENT"); | |||||
TRIPLET_MAP.put(0x96, "CMR_TAG_FIDELITY"); | |||||
TRIPLET_MAP.put(0x97, "DEVICE_APPEARANCE"); | |||||
} | |||||
} |
/* | |||||
* 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.awt.Color; | |||||
import java.io.ByteArrayInputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import javax.xml.transform.Result; | |||||
import javax.xml.transform.Source; | |||||
import javax.xml.transform.Transformer; | |||||
import javax.xml.transform.TransformerException; | |||||
import javax.xml.transform.TransformerFactory; | |||||
import javax.xml.transform.sax.SAXResult; | |||||
import javax.xml.transform.stream.StreamSource; | |||||
import org.junit.Test; | |||||
import org.xml.sax.SAXException; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.afp.AFPPaintingState; | |||||
import org.apache.fop.afp.AFPResourceManager; | |||||
import org.apache.fop.afp.DataStream; | |||||
import org.apache.fop.afp.Factory; | |||||
import org.apache.fop.afp.fonts.FopCharacterSet; | |||||
import org.apache.fop.afp.modca.PageObject; | |||||
import org.apache.fop.apps.FOUserAgent; | |||||
import org.apache.fop.apps.Fop; | |||||
import org.apache.fop.apps.FopConfParser; | |||||
import org.apache.fop.apps.FopFactory; | |||||
import org.apache.fop.apps.FopFactoryBuilder; | |||||
import org.apache.fop.fonts.EmbeddingMode; | |||||
import org.apache.fop.fonts.FontInfo; | |||||
import org.apache.fop.fonts.FontTriplet; | |||||
import org.apache.fop.fonts.MultiByteFont; | |||||
import org.apache.fop.render.intermediate.IFException; | |||||
import junit.framework.Assert; | |||||
public class AFPTrueTypeTestCase { | |||||
@Test | |||||
public void testAFPTrueType() throws IOException, SAXException, TransformerException { | |||||
String fopxconf = "<fop version=\"1.0\">\n" | |||||
+ " <renderers>\n" | |||||
+ " <renderer mime=\"application/x-afp\">\n" | |||||
+ " <fonts>\n" | |||||
+ " <font name=\"Univers\" embed-url=\"test/resources/fonts/ttf/DejaVuLGCSerif.ttf\">\n" | |||||
+ " <font-triplet name=\"Univers\" style=\"normal\" weight=\"normal\"/>\n" | |||||
+ " <font-triplet name=\"any\" style=\"normal\" weight=\"normal\"/>\n" | |||||
+ " </font>\n" | |||||
+ " </fonts>\n" | |||||
+ " </renderer>\n" | |||||
+ " </renderers>\n" | |||||
+ "</fop>"; | |||||
String fo = "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n" | |||||
+ " <fo:layout-master-set>\n" | |||||
+ " <fo:simple-page-master master-name=\"simple\">\n" | |||||
+ " <fo:region-body />\n" | |||||
+ " </fo:simple-page-master>\n" | |||||
+ " </fo:layout-master-set>\n" | |||||
+ " <fo:page-sequence master-reference=\"simple\">\n" | |||||
+ " <fo:flow flow-name=\"xsl-region-body\">\n" | |||||
+ " <fo:block font-family=\"Univers\">Univers</fo:block>\n" | |||||
+ " </fo:flow>\n" | |||||
+ " </fo:page-sequence>\n" | |||||
+ "</fo:root>"; | |||||
FopFactoryBuilder confBuilder = new FopConfParser( | |||||
new ByteArrayInputStream(fopxconf.getBytes()), new File(".").toURI()).getFopFactoryBuilder(); | |||||
FopFactory fopFactory = confBuilder.build(); | |||||
FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); | |||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||||
Fop fop = fopFactory.newFop("application/x-afp", foUserAgent, bos); | |||||
TransformerFactory factory = TransformerFactory.newInstance(); | |||||
Transformer transformer = factory.newTransformer(); | |||||
Source src = new StreamSource(new ByteArrayInputStream(fo.getBytes())); | |||||
Result res = new SAXResult(fop.getDefaultHandler()); | |||||
transformer.transform(src, res); | |||||
bos.close(); | |||||
StringBuilder sb = new StringBuilder(); | |||||
InputStream bis = new ByteArrayInputStream(bos.toByteArray()); | |||||
new AFPParser(false).read(bis, sb); | |||||
String format = "BEGIN RESOURCE_GROUP RG000001\n" | |||||
+ "BEGIN NAME_RESOURCE RES00001 Triplets: OBJECT_FUNCTION_SET_SPECIFICATION" | |||||
+ ",OBJECT_CLASSIFICATION,0x01,FULLY_QUALIFIED_NAME,\n" | |||||
+ "BEGIN OBJECT_CONTAINER OC000001 Triplets: 0x41,0x00,0x00,\n"; | |||||
for (int i = 0; i < 29; i++) { | |||||
format += "DATA OBJECT_CONTAINER\n"; | |||||
} | |||||
format += "END OBJECT_CONTAINER OC000001\n" | |||||
+ "END NAME_RESOURCE RES00001\n" | |||||
+ "END RESOURCE_GROUP RG000001\n" | |||||
+ "BEGIN DOCUMENT DOC00001\n" | |||||
+ "BEGIN PAGE_GROUP PGP00001\n" | |||||
+ "BEGIN PAGE PGN00001\n" | |||||
+ "BEGIN ACTIVE_ENVIRONMENT_GROUP AEG00001\n" | |||||
+ "MAP DATA_RESOURCE Triplets: 0x01,FULLY_QUALIFIED_NAME,FULLY_QUALIFIED_NAME" | |||||
+ ",OBJECT_CLASSIFICATION,DATA_OBJECT_FONT_DESCRIPTOR,\n" | |||||
+ "DESCRIPTOR PAGE\n" | |||||
+ "MIGRATION PRESENTATION_TEXT\n" | |||||
+ "END ACTIVE_ENVIRONMENT_GROUP AEG00001\n" | |||||
+ "BEGIN PRESENTATION_TEXT PT000001\n" | |||||
+ "DATA PRESENTATION_TEXT\n" | |||||
+ "END PRESENTATION_TEXT PT000001\n" | |||||
+ "END PAGE PGN00001\n" | |||||
+ "END PAGE_GROUP PGP00001\n" | |||||
+ "END DOCUMENT DOC00001\n"; | |||||
Assert.assertEquals(sb.toString(), format); | |||||
} | |||||
@Test | |||||
public void testAFPPainter() throws IFException, IOException { | |||||
AFPDocumentHandler afpDocumentHandler = mock(AFPDocumentHandler.class); | |||||
when(afpDocumentHandler.getPaintingState()).thenReturn(new AFPPaintingState()); | |||||
when(afpDocumentHandler.getResourceManager()).thenReturn(new AFPResourceManager(null)); | |||||
DataStream ds = mock(DataStream.class); | |||||
when(afpDocumentHandler.getDataStream()).thenReturn(ds); | |||||
PageObject po = new PageObject(new Factory(), "PAGE0001", 0, 0, 0, 0, 0); | |||||
when(ds.getCurrentPage()).thenReturn(po); | |||||
AFPPainter afpPainter = new MyAFPPainter(afpDocumentHandler); | |||||
afpPainter.setFont("any", "normal", 400, null, null, Color.BLACK); | |||||
afpPainter.drawText(0, 0, 0, 0, null, "test"); | |||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||||
po.writeToStream(bos); | |||||
InputStream bis = new ByteArrayInputStream(bos.toByteArray()); | |||||
StringBuilder sb = new StringBuilder(); | |||||
new AFPParser(true).read(bis, sb); | |||||
Assert.assertTrue(sb.toString(), | |||||
sb.toString().contains("DATA PRESENTATION_TEXT AMB AMI SCFL TRN t TRN e TRN s TRN t")); | |||||
} | |||||
class MyAFPPainter extends AFPPainter { | |||||
public MyAFPPainter(AFPDocumentHandler documentHandler) { | |||||
super(documentHandler); | |||||
} | |||||
protected FOUserAgent getUserAgent() { | |||||
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||||
return fopFactory.newFOUserAgent(); | |||||
} | |||||
protected FontInfo getFontInfo() { | |||||
FontInfo f = new FontInfo(); | |||||
f.addFontProperties("any", FontTriplet.DEFAULT_FONT_TRIPLET); | |||||
MultiByteFont font = new MultiByteFont(null, EmbeddingMode.AUTO); | |||||
font.setWidthArray(new int[100]); | |||||
f.addMetrics("any", new AFPFontConfig.AFPTrueTypeFont("", true, | |||||
new FopCharacterSet("", "UTF-16BE", "", font, null, null), null, null)); | |||||
return f; | |||||
} | |||||
} | |||||
} |