From: Jeremias Maerki Date: Mon, 2 Dec 2002 14:24:07 +0000 (+0000) Subject: Moved PFM classes to type1 subpackage X-Git-Tag: Alt-Design-integration-base~278 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9114696fbbd3f8cdd41388065ad2576dc8c923b9;p=xmlgraphics-fop.git Moved PFM classes to type1 subpackage Added PFB classes (taken from branch) git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195709 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/org/apache/fop/fonts/type1/PFBData.java b/src/org/apache/fop/fonts/type1/PFBData.java new file mode 100644 index 000000000..ae0653e47 --- /dev/null +++ b/src/org/apache/fop/fonts/type1/PFBData.java @@ -0,0 +1,148 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.fonts.type1; + +import java.io.OutputStream; +import java.io.IOException; + +/** + * Class that represents the contents of a PFB file. + * + * @see PFBParser + */ +public class PFBData { + + /** + * Raw format, no special file structure + */ + public static final int PFB_RAW = 0; + + /** + * PC format + */ + public static final int PFB_PC = 1; + + /** + * MAC Format (unsupported, yet) + */ + public static final int PFB_MAC = 2; + + private int pfbFormat; //One of the PFB_* constants + private byte[] headerSegment; + private byte[] encryptedSegment; + private byte[] trailerSegment; + + + /** + * Sets the PFB format the font was loaded with. + * @param format one of the PFB_* constants + */ + public void setPFBFormat(int format) { + switch (format) { + case PFB_RAW: + case PFB_PC: + this.pfbFormat = format; + break; + case PFB_MAC: + throw new UnsupportedOperationException("Mac format is not yet implemented"); + default: + throw new IllegalArgumentException("Invalid value for PFB format: " + format); + } + } + + + /** + * Returns the format the font was loaded with. + * @return int one of the PFB_* constants + */ + public int getPFBFormat() { + return this.pfbFormat; + } + + /** + * Sets the header segment of the font file. + * @param headerSeg the header segment + */ + public void setHeaderSegment(byte[] headerSeg) { + this.headerSegment = headerSeg; + } + + /** + * Sets the encrypted segment of the font file. + * @param encryptedSeg the encrypted segment + */ + public void setEncryptedSegment(byte[] encryptedSeg) { + this.encryptedSegment = encryptedSeg; + } + + /** + * Sets the trailer segment of the font file. + * @param trailerSeg the trailer segment + */ + public void setTrailerSegment(byte[] trailerSeg) { + this.trailerSegment = trailerSeg; + } + + /** + * Returns the full length of the raw font file. + * @return int the raw file length + */ + public int getLength() { + return getLength1() + getLength2() + getLength3(); + } + + + /** + * Returns the Length1 (length of the header segment). + * @return int Length1 + */ + public int getLength1() { + return this.headerSegment.length; + } + + + /** + * Returns the Length2 (length of the encrypted segment). + * @return int Length2 + */ + public int getLength2() { + return this.encryptedSegment.length; + } + + + /** + * Returns the Length3 (length of the trailer segment). + * @return int Length3 + */ + public int getLength3() { + return this.trailerSegment.length; + } + + + /** + * Writes the PFB file in raw format to an OutputStream. + * @param out the OutputStream to write to + * @throws IOException In case of an I/O problem + */ + public void outputAllParts(OutputStream out) throws IOException { + out.write(this.headerSegment); + out.write(this.encryptedSegment); + out.write(this.trailerSegment); + } + + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return "PFB: format=" + getPFBFormat() + + " len1=" + getLength1() + + " len2=" + getLength2() + + " len3=" + getLength3(); + } + +} \ No newline at end of file diff --git a/src/org/apache/fop/fonts/type1/PFBParser.java b/src/org/apache/fop/fonts/type1/PFBParser.java new file mode 100644 index 000000000..6b43c3fea --- /dev/null +++ b/src/org/apache/fop/fonts/type1/PFBParser.java @@ -0,0 +1,232 @@ +/* + * $Id$ + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.fonts.type1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.BufferedInputStream; + +//FOP +import org.apache.fop.util.StreamUtilities; + +/** + * This class represents a parser for Adobe Type 1 PFB files. + * + * @see PFBData + */ +public class PFBParser { + + private static final byte[] CURRENTFILE_EEXEC; + private static final byte[] CLEARTOMARK; + + static { + try { + CURRENTFILE_EEXEC = "currentfile eexec".getBytes("US-ASCII"); + CLEARTOMARK = "cleartomark".getBytes("US-ASCII"); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException("Incompatible VM. It doesn't support the US-ASCII encoding"); + } + } + + + /** + * Parses a PFB file into a PFBData object. + * @param url URL to load the PFB file from + * @return PFBData memory representation of the font + * @throws IOException In case of an I/O problem + */ + public PFBData parsePFB(java.net.URL url) throws IOException { + InputStream in = url.openStream(); + try { + return parsePFB(in); + } finally { + in.close(); + } + } + + + /** + * Parses a PFB file into a PFBData object. + * @param pfbFile File to load the PFB file from + * @return PFBData memory representation of the font + * @throws IOException In case of an I/O problem + */ + public PFBData parsePFB(java.io.File pfbFile) throws IOException { + InputStream in = new java.io.FileInputStream(pfbFile); + try { + return parsePFB(in); + } finally { + in.close(); + } + } + + + /** + * Parses a PFB file into a PFBData object. + * @param in InputStream to load the PFB file from + * @return PFBData memory representation of the font + * @throws IOException In case of an I/O problem + */ + public PFBData parsePFB(InputStream in) throws IOException { + PFBData pfb = new PFBData(); + BufferedInputStream bin = new BufferedInputStream(in); + DataInputStream din = new DataInputStream(bin); + din.mark(32); + int firstByte = din.readUnsignedByte(); + din.reset(); + if (firstByte == 128) { + pfb.setPFBFormat(PFBData.PFB_PC); + parsePCFormat(pfb, din); + } else { + pfb.setPFBFormat(PFBData.PFB_RAW); + parseRAWFormat(pfb, bin); + } + return pfb; + } + + + private static int swapInteger(final int value) { + return (((value >> 0) & 0xff) << 24) + + (((value >> 8) & 0xff) << 16) + + (((value >> 16) & 0xff) << 8) + + (((value >> 24) & 0xff) << 0); + } + + + private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException { + int segmentHead; + int segmentType; + int bytesRead; + + //Read first segment + segmentHead = din.readUnsignedByte(); + if (segmentHead != 128) { + throw new IOException("Invalid file format. Expected ASCII 80hex"); + } + segmentType = din.readUnsignedByte(); //Read + int len1 = swapInteger(din.readInt()); + byte[] headerSegment = new byte[len1]; + bytesRead = din.read(headerSegment); + if (bytesRead != len1) { + throw new IOException("Could not load the whole segment"); + } + pfb.setHeaderSegment(headerSegment); + + //Read second segment + segmentHead = din.readUnsignedByte(); + if (segmentHead != 128) { + throw new IOException("Invalid file format. Expected ASCII 80hex"); + } + segmentType = din.readUnsignedByte(); + int len2 = swapInteger(din.readInt()); + byte[] encryptedSegment = new byte[len2]; + bytesRead = din.read(encryptedSegment); + if (bytesRead != len2) { + throw new IOException("Could not load the whole segment"); + } + pfb.setEncryptedSegment(encryptedSegment); + + //Read third segment + segmentHead = din.readUnsignedByte(); + if (segmentHead != 128) { + throw new IOException("Invalid file format. Expected ASCII 80hex"); + } + segmentType = din.readUnsignedByte(); + int len3 = swapInteger(din.readInt()); + byte[] trailerSegment = new byte[len3]; + bytesRead = din.read(trailerSegment); + if (bytesRead != len3) { + throw new IOException("Could not load the whole segment"); + } + pfb.setTrailerSegment(trailerSegment); + + //Read EOF indicator + segmentHead = din.readUnsignedByte(); + if (segmentHead != 128) { + throw new IOException("Invalid file format. Expected ASCII 80hex"); + } + segmentType = din.readUnsignedByte(); + if (segmentType != 3) { + throw new IOException("Expected segment type 3, but found: " + segmentType); + } + } + + + private static final boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) { + for (int i = 0; i < cmp.length; i++) { + // System.out.println("Compare: " + src[srcOffset + i] + " " + cmp[i]); + if (src[srcOffset + i] != cmp[i]) { + return false; + } + } + return true; + } + + private void calcLengths(PFBData pfb, byte[] originalData) { + // Calculate length 1 and 3 + // System.out.println ("Checking font, size = "+originalData.length); + + // Length1 is the size of the initial ascii portion + // search for "currentfile eexec" + // Get the first binary number and search backwards for "eexec" + int len1 = 30; + + // System.out.println("Length1="+len1); + while (!byteCmp(originalData, len1 - CURRENTFILE_EEXEC.length, CURRENTFILE_EEXEC)) { + len1++; + } + + // Skip newline + len1++; + + // Length3 is length of the last portion of the file + int len3 = 0; + len3 -= CLEARTOMARK.length; + while (!byteCmp(originalData, originalData.length + len3, CLEARTOMARK)) { + len3--; + // System.out.println("Len3="+len3); + } + len3 = -len3; + len3++; + // Eat 512 zeroes + int numZeroes = 0; + byte[] ws1 = new byte[]{0x0D}; //CR + byte[] ws2 = new byte[]{0x0A}; //LF + byte[] ws3 = new byte[]{0x30}; //"0" + while ((originalData[originalData.length - len3] == ws1[0] + || originalData[originalData.length - len3] == ws2[0] + || originalData[originalData.length - len3] == ws3[0]) + && numZeroes < 512) { + len3++; + if (originalData[originalData.length - len3] == ws3[0]) { + numZeroes++; + } + } + // System.out.println("Length3="+len3); + + //Create the 3 segments + byte[] buffer = new byte[len1]; + System.arraycopy(originalData, 0, buffer, 0, len1); + pfb.setHeaderSegment(buffer); + + int len2 = originalData.length - len3 - len1; + buffer = new byte[len2]; + System.arraycopy(originalData, len1, buffer, 0, len2); + pfb.setEncryptedSegment(buffer); + + buffer = new byte[len3]; + System.arraycopy(originalData, len1 + len2, buffer, 0, len3); + pfb.setTrailerSegment(buffer); + } + + private void parseRAWFormat(PFBData pfb, BufferedInputStream bin) + throws IOException { + calcLengths(pfb, StreamUtilities.toByteArray(bin, 32768)); + } + +} \ No newline at end of file diff --git a/src/org/apache/fop/fonts/type1/PFMFile.java b/src/org/apache/fop/fonts/type1/PFMFile.java new file mode 100644 index 000000000..682b59b02 --- /dev/null +++ b/src/org/apache/fop/fonts/type1/PFMFile.java @@ -0,0 +1,425 @@ +/* + * $Id$ + * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.fonts.type1; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +//Avalon +import org.apache.avalon.framework.logger.AbstractLogEnabled; + +//FOP +import org.apache.fop.fonts.Glyphs; +import org.apache.fop.util.StreamUtilities; + +/** + * This class represents a PFM file (or parts of it) as a Java object. + */ +public class PFMFile extends AbstractLogEnabled { + + // Header stuff + private String windowsName; + private String postscriptName; + private short dfItalic; + private int dfWeight; + private short dfCharSet; + private short dfPitchAndFamily; + private int dfAvgWidth; + private int dfMaxWidth; + private int dfMinWidth; + private short dfFirstChar; + private short dfLastChar; + + // Extension stuff + // --- + + // Extend Text Metrics + private int etmCapHeight; + private int etmXHeight; + private int etmLowerCaseAscent; + private int etmLowerCaseDescent; + + // Extent table + private int[] extentTable; + + private Map kerningTab = new java.util.HashMap(); + + /** + * Parses a PFM file + * + * @param inStream The stream from which to read the PFM file. + * @throws IOException In case of an I/O problem + */ + public void load(InputStream inStream) throws IOException { + final byte[] buf = StreamUtilities.toByteArray(inStream, 8000); + final InputStream bufin = new java.io.ByteArrayInputStream(buf); + PFMInputStream in = new PFMInputStream(bufin); + /*final int version =*/ in.readShort(); + final long filesize = in.readInt(); + if (filesize != buf.length) { + getLogger().warn("Effective file size is not the same as indicated in the header."); + } + bufin.reset(); + + loadHeader(in); + loadExtension(in); + } + + /** + * Parses the header of the PFM file. + * + * @param inStream The stream from which to read the PFM file. + * @throws IOException In case of an I/O problem + */ + private void loadHeader(PFMInputStream inStream) throws IOException { + inStream.skip(80); + dfItalic = inStream.readByte(); + inStream.skip(2); + dfWeight = inStream.readShort(); + dfCharSet = inStream.readByte(); + inStream.skip(4); + dfPitchAndFamily = inStream.readByte(); + dfAvgWidth = inStream.readShort(); + dfMaxWidth = inStream.readShort(); + dfFirstChar = inStream.readByte(); + dfLastChar = inStream.readByte(); + inStream.skip(8); + long faceOffset = inStream.readInt(); + + inStream.reset(); + inStream.skip(faceOffset); + windowsName = inStream.readString(); + + inStream.reset(); + inStream.skip(117); + } + + /** + * Parses the extension part of the PFM file. + * + * @param inStream The stream from which to read the PFM file. + */ + private void loadExtension(PFMInputStream inStream) throws IOException { + final int size = inStream.readShort(); + if (size != 30) { + getLogger().warn("Size of extension block was expected to be " + + "30 bytes, but was " + size + " bytes."); + } + final long extMetricsOffset = inStream.readInt(); + final long extentTableOffset = inStream.readInt(); + inStream.skip(4); //Skip dfOriginTable + final long kernPairOffset = inStream.readInt(); + inStream.skip(4); //Skip dfTrackKernTable + long driverInfoOffset = inStream.readInt(); + + if (kernPairOffset > 0) { + inStream.reset(); + inStream.skip(kernPairOffset); + loadKernPairs(inStream); + } + + inStream.reset(); + inStream.skip(driverInfoOffset); + postscriptName = inStream.readString(); + + if (extMetricsOffset != 0) { + inStream.reset(); + inStream.skip(extMetricsOffset); + loadExtMetrics(inStream); + } + if (extentTableOffset != 0) { + inStream.reset(); + inStream.skip(extentTableOffset); + loadExtentTable(inStream); + } + + } + + /** + * Parses the kernPairs part of the pfm file + * + * @param inStream The stream from which to read the PFM file. + */ + private void loadKernPairs(PFMInputStream inStream) throws IOException { + int i = inStream.readShort(); + + + getLogger().info(i + " kerning pairs"); + while (i > 0) { + int g1 = (int)inStream.readByte(); + i--; + + int g2 = (int)inStream.readByte(); + + int adj = inStream.readShort(); + if (adj > 0x8000) { + adj = -(0x10000 - adj); + } + getLogger().debug("Char no: (" + g1 + ", " + g2 + ") kern: " + adj); + + if (getLogger().isDebugEnabled()) { + final String glyph1 = Glyphs.TEX8R_GLYPH_NAMES[g1]; + final String glyph2 = Glyphs.TEX8R_GLYPH_NAMES[g2]; + getLogger().debug("glyphs: " + glyph1 + ", " + glyph2); + } + + Map adjTab = (Map)kerningTab.get(new Integer(g1)); + if (adjTab == null) { + adjTab = new java.util.HashMap(); + } + adjTab.put(new Integer(g2), new Integer(adj)); + kerningTab.put(new Integer(g1), adjTab); + } + } + + /** + * Parses the extended metrics part of the PFM file. + * + * @param inStream The stream from which to read the PFM file. + */ + private void loadExtMetrics(PFMInputStream inStream) throws IOException { + final int size = inStream.readShort(); + if (size != 52) { + getLogger().warn("Size of extension block was expected to be " + + "52 bytes, but was " + size + " bytes."); + } + inStream.skip(12); //Skip etmPointSize, etmOrientation, etmMasterHeight, + //etmMinScale, etmMaxScale, emtMasterUnits + etmCapHeight = inStream.readShort(); + etmXHeight = inStream.readShort(); + etmLowerCaseAscent = inStream.readShort(); + etmLowerCaseDescent = inStream.readShort(); + //Ignore the rest of the values + } + + /** + * Parses the extent table of the PFM file. + * + * @param inStream The stream from which to read the PFM file. + */ + private void loadExtentTable(PFMInputStream inStream) throws IOException { + extentTable = new int[dfLastChar - dfFirstChar + 1]; + dfMinWidth = dfMaxWidth; + for (short i = dfFirstChar; i <= dfLastChar; i++) { + extentTable[i - dfFirstChar] = inStream.readShort(); + if (extentTable[i - dfFirstChar] < dfMinWidth) { + dfMinWidth = extentTable[i - dfFirstChar]; + } + } + } + + /** + * Returns the Windows name of the font. + * + * @return The Windows name. + */ + public String getWindowsName() { + return windowsName; + } + + /** + * Return the kerning table. The kerning table is a Map with + * strings with glyphnames as keys, containing Maps as value. + * The value map contains a glyph name string key and an Integer value + * + * @return A Map containing the kerning table + */ + public Map getKerning() { + return kerningTab; + } + + /** + * Returns the Postscript name of the font. + * + * @return The Postscript name. + */ + public String getPostscriptName() { + return postscriptName; + } + + /** + * Returns the charset used for the font. + * + * @return The charset (0=WinAnsi). + */ + public short getCharSet() { + return dfCharSet; + } + + /** + * Returns the charset of the font as a string. + * + * @return The name of the charset. + */ + public String getCharSetName() { + switch (dfCharSet) { + case 0: + return "WinAnsi"; + case 128: + return "Shift-JIS (Japanese)"; + default: + return "Unknown"; + } + } + + /** + * Returns the number of the character that defines + * the first entry in the widths list. + * + * @return The number of the first character. + */ + public short getFirstChar() { + return dfFirstChar; + } + + /** + * Returns the number of the character that defines + * the last entry in the widths list. + * + * @return The number of the last character. + */ + public short getLastChar() { + return dfLastChar; + } + + /** + * Returns the CapHeight parameter for the font (height of uppercase H). + * + * @return The CapHeight parameter. + */ + public int getCapHeight() { + return etmCapHeight; + } + + /** + * Returns the XHeight parameter for the font (height of lowercase x). + * + * @return The CapHeight parameter. + */ + public int getXHeight() { + return etmXHeight; + } + + /** + * Returns the LowerCaseAscent parameter for the font (height of lowercase d). + * + * @return The LowerCaseAscent parameter. + */ + public int getLowerCaseAscent() { + return etmLowerCaseAscent; + } + + /** + * Returns the LowerCaseDescent parameter for the font (height of lowercase p). + * + * @return The LowerCaseDescent parameter. + */ + public int getLowerCaseDescent() { + return etmLowerCaseDescent; + } + + /** + * Tells whether the font has proportional character spacing. + * + * @return ex. true for Times, false for Courier. + */ + public boolean getIsProportional() { + return ((dfPitchAndFamily & 1) == 1); + } + + /** + * Returns the bounding box for the font. + * Note: this value is just an approximation, + * it does not really exist in the PFM file. + * + * @return The calculated Font BBox. + */ + public int[] getFontBBox() { + int[] bbox = new int[4]; + + // Just guessing.... + if (!getIsProportional() && (dfAvgWidth == dfMaxWidth)) { + bbox[0] = -20; + } else { + bbox[0] = -100; + } + bbox[1] = -(getLowerCaseDescent() + 5); + bbox[2] = dfMaxWidth + 10; + bbox[3] = getLowerCaseAscent() + 5; + return bbox; + } + + /** + * Returns the characteristics flags for the font as + * needed for a PDF font descriptor (See PDF specs). + * + * @return The characteristics flags. + */ + public int getFlags() { + int flags = 0; + if (!getIsProportional()) { + flags |= 1; + } + if ((dfPitchAndFamily & 16) == 16) { + flags |= 2; + } + if ((dfPitchAndFamily & 64) == 64) { + flags |= 4; + } + if (dfCharSet == 0) { + flags |= 6; + } + if (dfItalic != 0) { + flags |= 7; + } + return flags; + } + + /** + * Returns the width of the dominant vertical stems of the font. + * Note: this value is just an approximation, + * it does not really exist in the PFM file. + * + * @return The vertical stem width. + */ + public int getStemV() { + // Just guessing.... + if (dfItalic != 0) { + return (int)Math.round(dfMinWidth * 0.25); + } else { + return (int)Math.round(dfMinWidth * 0.6); + } + } + + /** + * Returns the italic angle of the font. + * Note: this value is just an approximation, + * it does not really exist in the PFM file. + * + * @return The italic angle. + */ + public int getItalicAngle() { + if (dfItalic != 0) { + return -16; // Just guessing.... + } else { + return 0; + } + } + + /** + * Returns the width of a character + * + * @param which The number of the character for which the width is requested. + * @return The width of a character. + */ + public int getCharWidth(short which) { + return extentTable[which - dfFirstChar]; + } + +} diff --git a/src/org/apache/fop/fonts/type1/PFMInputStream.java b/src/org/apache/fop/fonts/type1/PFMInputStream.java new file mode 100644 index 000000000..1fbcbd48e --- /dev/null +++ b/src/org/apache/fop/fonts/type1/PFMInputStream.java @@ -0,0 +1,96 @@ +/* + * $Id$ + * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.fonts.type1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.InputStreamReader; + +/** + * This is a helper class for reading PFM files. It defines functions for + * extracting specific values out of the stream. + */ +public class PFMInputStream extends java.io.FilterInputStream { + + private DataInputStream datain; + + /** + * Constructs a PFMInputStream based on an InputStream representing the + * PFM file. + * + * @param in The stream from which to read the PFM file + */ + public PFMInputStream(InputStream in) { + super(in); + datain = new DataInputStream(in); + } + + /** + * Parses a one byte value out of the stream. + * + * @return The value extracted + * @throws IOException In case of an I/O problem + */ + public short readByte() throws IOException { + short s = datain.readByte(); + // Now, we've got to trick Java into forgetting the sign + int s1 = (((s & 0xF0) >>> 4) << 4) + (s & 0x0F); + return (short)s1; + } + + /** + * Parses a two byte value out of the stream. + * + * @return The value extracted + * @throws IOException In case of an I/O problem + */ + public int readShort() throws IOException { + int i = datain.readShort(); + + // Change byte order + int high = (i & 0xFF00) >>> 8; + int low = (i & 0x00FF) << 8; + return low + high; + } + + /** + * Parses a four byte value out of the stream. + * + * @return The value extracted + * @throws IOException In case of an I/O problem + */ + public long readInt() throws IOException { + int i = datain.readInt(); + + // Change byte order + int i1 = (i & 0xFF000000) >>> 24; + int i2 = (i & 0x00FF0000) >>> 8; + int i3 = (i & 0x0000FF00) << 8; + int i4 = (i & 0x000000FF) << 24; + return i1 + i2 + i3 + i4; + } + + /** + * Parses a zero-terminated string out of the stream. + * + * @return The value extracted + * @throws IOException In case of an I/O problem + */ + public String readString() throws IOException { + InputStreamReader reader = new InputStreamReader(in, "ISO-8859-1"); + StringBuffer buf = new StringBuffer(); + int ch = reader.read(); + while (ch != 0) { + buf.append((char)ch); + ch = reader.read(); + } + return buf.toString(); + } + +} diff --git a/src/org/apache/fop/fonts/type1/package.html b/src/org/apache/fop/fonts/type1/package.html new file mode 100644 index 000000000..0c492fc4d --- /dev/null +++ b/src/org/apache/fop/fonts/type1/package.html @@ -0,0 +1,6 @@ + +org.apache.fop.fonts.type1 Package + +

Classes for Adobe Type 1 fonts.

+ + \ No newline at end of file