aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/pdfbox/pdmodel/font
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/pdfbox/pdmodel/font')
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java248
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java66
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java66
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFont.java863
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java530
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java446
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java580
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java108
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java62
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java239
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java437
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java129
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java206
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java267
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java152
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java607
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/package.html9
17 files changed, 5015 insertions, 0 deletions
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java
new file mode 100644
index 0000000..e13b821
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation for the CIDFontType0/CIDFontType2 Fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public abstract class PDCIDFont extends PDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFont.class);
+
+
+ private Map widthCache = new HashMap();
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFont()
+ {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y )
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the font bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the default width. The default value for the default width is 1000.
+ *
+ * @return The default width for the glyphs in this font.
+ */
+ public long getDefaultWidth()
+ {
+ long dw = 1000;
+ COSNumber number = (COSNumber)font.getDictionaryObject( COSName.getPDFName( "DW" ) );
+ if( number != null )
+ {
+ dw = number.intValue();
+ }
+ return dw;
+ }
+
+ /**
+ * This will set the default width for the glyphs of this font.
+ *
+ * @param dw The default width.
+ */
+ public void setDefaultWidth( long dw )
+ {
+ font.setItem( COSName.getPDFName( "DW" ), new COSInteger( dw ) );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+
+ float retval = 0.0f;
+ int code = getCodeFromArray( c, offset, length );
+
+ Float widthFloat = (Float)widthCache.get( new Integer( code ) );
+ if( widthFloat == null )
+ {
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.getPDFName( "W" ) );
+
+ if( widths != null )
+ {
+ boolean foundWidth = false;
+ for( int i=0; !foundWidth && i<widths.size(); i++ )
+ {
+ COSNumber firstCode = (COSNumber)widths.getObject( i++ );
+ COSBase next = widths.getObject( i );
+ if( next instanceof COSArray )
+ {
+ COSArray array = (COSArray)next;
+ if( code >= firstCode.intValue() &&
+ code < firstCode.intValue() + array.size() )
+ {
+ COSNumber rangeWidth =
+ (COSNumber)array.get( code - firstCode.intValue() );
+ retval = rangeWidth.floatValue();
+ foundWidth = true;
+ }
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber)next;
+ i++;
+ COSNumber rangeWidth = (COSNumber)widths.getObject( i );
+ if( code >= firstCode.intValue() &&
+ code <= secondCode.intValue() )
+ {
+ retval = rangeWidth.floatValue();
+ foundWidth = true;
+ }
+ }
+ }
+ widthCache.put( new Integer( code ), new Float( retval ) );
+ }
+ }
+ else
+ {
+ retval = widthFloat.floatValue();
+ }
+
+ if(log.isDebugEnabled() )
+ {
+ log.debug( "PDCIDFontType0Font.getFontWidth( code=" + code +" ) retval=" +retval );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ float totalWidths = 0.0f;
+ float characterCount = 0.0f;
+ float defaultWidth = getDefaultWidth();
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.getPDFName( "W" ) );
+
+ if( widths != null )
+ {
+ for( int i=0; i<widths.size(); i++ )
+ {
+ COSNumber firstCode = (COSNumber)widths.getObject( i++ );
+ COSBase next = widths.getObject( i );
+ float nextWidth=0.0f;
+ if( next instanceof COSArray )
+ {
+ COSArray array = (COSArray)next;
+ for( int j=0; j<array.size(); j++ )
+ {
+ COSNumber width = (COSNumber)array.get( j );
+ totalWidths+=width.floatValue();
+ characterCount += 1;
+ }
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber)next;
+ i++;
+ COSNumber rangeWidth = (COSNumber)widths.getObject( i );
+ if( rangeWidth.floatValue() > 0 )
+ {
+ totalWidths += rangeWidth.floatValue();
+ characterCount += 1;
+ }
+ }
+ }
+ }
+ float average = totalWidths / characterCount;
+ if( average <= 0 )
+ {
+ average = defaultWidth;
+ }
+ return average;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java
new file mode 100644
index 0000000..4c6589c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation of the CIDFontType0 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDCIDFontType0Font extends PDCIDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFontType0Font.class);
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFontType0Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "CIDFontType0" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFontType0Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java
new file mode 100644
index 0000000..bda6c4a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation of the CIDFontType2 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDCIDFontType2Font extends PDCIDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFontType2Font.class);
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFontType2Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "CIDFontType2" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFontType2Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDFont.java
new file mode 100644
index 0000000..593c8b0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFont.java
@@ -0,0 +1,863 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.afmparser.AFMParser;
+
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.cmapparser.CMapParser;
+
+import org.pdfbox.cmaptypes.CMap;
+
+import org.pdfbox.encoding.AFMEncoding;
+import org.pdfbox.encoding.DictionaryEncoding;
+import org.pdfbox.encoding.Encoding;
+import org.pdfbox.encoding.EncodingManager;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDMatrix;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.pdfbox.util.ResourceLoader;
+
+import org.apache.log4j.Logger;
+
+import java.awt.Graphics;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This is the base class for all PDF fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.32 $
+ */
+public abstract class PDFont implements COSObjectable
+{
+ private static Logger log = Logger.getLogger(PDFont.class);
+
+ /**
+ * The cos dictionary for this font.
+ */
+ protected COSDictionary font;
+
+ /**
+ * This is only used if this is a font object and it has an encoding.
+ */
+ private Encoding fontEncoding = null;
+ /**
+ * This is only used if this is a font object and it has an encoding and it is
+ * a type0 font with a cmap.
+ */
+ private CMap cmap = null;
+
+ private static Map afmResources = null;
+ private static Map cmapObjects = null;
+ private static Map afmObjects = null;
+ private static Map cmapSubstitutions = null;
+
+ static
+ {
+ //these are read-only once they are created
+ afmResources = new HashMap();
+ cmapSubstitutions = new HashMap();
+
+ //these are read-write
+ cmapObjects = Collections.synchronizedMap( new HashMap() );
+ afmObjects = Collections.synchronizedMap( new HashMap() );
+
+
+ afmResources.put( COSName.getPDFName( "Courier-Bold" ), "Resources/afm/Courier-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Courier-BoldOblique" ), "Resources/afm/Courier-BoldOblique.afm" );
+ afmResources.put( COSName.getPDFName( "Courier" ), "Resources/afm/Courier.afm" );
+ afmResources.put( COSName.getPDFName( "Courier-Oblique" ), "Resources/afm/Courier-Oblique.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica" ), "Resources/afm/Helvetica.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-Bold" ), "Resources/afm/Helvetica-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-BoldOblique" ), "Resources/afm/Helvetica-BoldOblique.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-Oblique" ), "Resources/afm/Helvetica-Oblique.afm" );
+ afmResources.put( COSName.getPDFName( "Symbol" ), "Resources/afm/Symbol.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Bold" ), "Resources/afm/Times-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Times-BoldItalic" ), "Resources/afm/Times-BoldItalic.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Italic" ), "Resources/afm/Times-Italic.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Roman" ), "Resources/afm/Times-Roman.afm" );
+ afmResources.put( COSName.getPDFName( "ZapfDingbats" ), "Resources/afm/ZapfDingbats.afm" );
+
+ cmapSubstitutions.put( "ETenms-B5-H", "ETen-B5-H" );
+ cmapSubstitutions.put( "ETenms-B5-V", "ETen-B5-V" );
+ }
+
+ /**
+ * This will clear AFM resources that are stored statically.
+ * This is usually not a problem unless you want to reclaim
+ * resources for a long running process.
+ *
+ * SPECIAL NOTE: The font calculations are currently in COSObject, which
+ * is where they will reside until PDFont is mature enough to take them over.
+ * PDFont is the appropriate place for them and not in COSObject but we need font
+ * calculations for text extractaion. THIS METHOD WILL BE MOVED OR REMOVED
+ * TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX.
+ */
+ public static void clearResources()
+ {
+ afmObjects.clear();
+ cmapObjects.clear();
+ }
+
+ /**
+ * Constructor.
+ */
+ public PDFont()
+ {
+ font = new COSDictionary();
+ font.setItem( COSName.TYPE, COSName.FONT );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDFont( COSDictionary fontDictionary )
+ {
+ font = fontDictionary;
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return font;
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public abstract float getFontWidth( byte[] c, int offset, int length ) throws IOException;
+
+ /**
+ * This will get the width of this string for this font.
+ *
+ * @param string The string to get the width of.
+ *
+ * @return The width of the string in 1000 units of text space, ie 333 567...
+ *
+ * @throws IOException If there is an error getting the width information.
+ */
+ public float getStringWidth( String string ) throws IOException
+ {
+ byte[] data = string.getBytes();
+ float totalWidth = 0;
+ for( int i=0; i<data.length; i++ )
+ {
+ totalWidth+=getFontWidth( data, i, 1 );
+ }
+ return totalWidth;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public abstract float getAverageFontWidth() throws IOException;
+
+ /**
+ * This will draw a string on a canvas using the font.
+ *
+ * @param string The string to draw.
+ * @param g The graphics to draw onto.
+ * @param fontSize The size of the font to draw.
+ * @param xScale The x scaling percent.
+ * @param yScale The y scaling percent.
+ * @param x The x coordinate to draw at.
+ * @param y The y coordinate to draw at.
+ *
+ * @throws IOException If there is an error drawing the specific string.
+ */
+ public abstract void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException;
+
+ /**
+ * Used for multibyte encodings.
+ *
+ * @param data The array of data.
+ * @param offset The offset into the array.
+ * @param length The number of bytes to use.
+ *
+ * @return The int value of data from the array.
+ */
+ protected int getCodeFromArray( byte[] data, int offset, int length )
+ {
+ int code = 0;
+ for( int i=0; i<length; i++ )
+ {
+ code <<= 8;
+ code = (data[offset+i]+256)%256;
+ }
+ return code;
+ }
+
+ /**
+ * This will attempt to get the font width from an AFM file.
+ *
+ * @param code The character code we are trying to get.
+ *
+ * @return The font width from the AFM file.
+ *
+ * @throws IOException if we cannot find the width.
+ */
+ protected float getFontWidthFromAFMFile( int code ) throws IOException
+ {
+ float retval = 0;
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ Encoding encoding = getEncoding();
+ COSName characterName = encoding.getName( code );
+ retval = metric.getCharacterWidth( characterName.getName() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will attempt to get the average font width from an AFM file.
+ *
+ * @return The average font width from the AFM file.
+ *
+ * @throws IOException if we cannot find the width.
+ */
+ protected float getAverageFontWidthFromAFMFile() throws IOException
+ {
+ float retval = 0;
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ retval = metric.getAverageCharacterWidth();
+ }
+ return retval;
+ }
+
+ /**
+ * This will get an AFM object if one exists.
+ *
+ * @return The afm object from the name.
+ *
+ * @throws IOException If there is an error getting the AFM object.
+ */
+ protected FontMetric getAFM() throws IOException
+ {
+ COSName name = (COSName)font.getDictionaryObject( COSName.BASE_FONT );
+ FontMetric result = null;
+ if( name != null )
+ {
+ result = (FontMetric)afmObjects.get( name );
+ if( result == null )
+ {
+ String resource = (String)afmResources.get( name );
+ if( log.isDebugEnabled() )
+ {
+ log.debug("resource: " + resource + ", name: " + name.getName());
+ }
+ if( resource == null )
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "resource is null" );
+ }
+ //ok for now
+ //throw new IOException( "Unknown AFM font '" + name.getName() + "'" );
+ }
+ else
+ {
+ InputStream afmStream = ResourceLoader.loadResource( resource );
+ if( afmStream == null )
+ {
+ throw new IOException( "Can't handle font width:" + resource );
+ }
+ AFMParser parser = new AFMParser( afmStream );
+ parser.parse();
+ result = parser.getResult();
+ afmObjects.put( name, result );
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This will perform the encoding of a character if needed.
+ *
+ * @param c The character to encode.
+ * @param offset The offset into the array to get the data
+ * @param length The number of bytes to read.
+ *
+ * @return The value of the encoded character.
+ *
+ * @throws IOException If there is an error during the encoding.
+ */
+ public String encode( byte[] c, int offset, int length ) throws IOException
+ {
+ String retval = null;
+ COSName fontSubtype = (COSName)font.getDictionaryObject( COSName.SUBTYPE );
+ String fontSubtypeName = fontSubtype.getName();
+ if( fontSubtypeName.equals( "Type0" ) ||
+ fontSubtypeName.equals( "Type1" ) ||
+ fontSubtypeName.equals( "TrueType" ))
+ {
+ if( cmap == null )
+ {
+ if( font.getDictionaryObject( COSName.TO_UNICODE ) != null )
+ {
+ COSStream toUnicode = (COSStream)font.getDictionaryObject( COSName.TO_UNICODE );
+ if( toUnicode != null )
+ {
+ parseCmap( toUnicode.getUnfilteredStream(), null );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting embedded CMAP Stream from ToUnicode" );
+ }
+ }
+ }
+ else
+ {
+ COSBase encoding = font.getDictionaryObject( COSName.ENCODING );
+ if( encoding instanceof COSStream )
+ {
+ COSStream encodingStream = (COSStream)encoding;
+ parseCmap( encodingStream.getUnfilteredStream(), null );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting embedded CMAP Stream from encoding" );
+ }
+ }
+ else if( fontSubtypeName.equals( "Type0" ) &&
+ encoding instanceof COSName )
+ {
+ COSName encodingName = (COSName)encoding;
+ cmap = (CMap)cmapObjects.get( encodingName );
+ if( cmap != null )
+ {
+ cmap = (CMap)cmapObjects.get( encodingName );
+ }
+ else
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting CMAP Stream from resource" );
+ }
+ String cmapName = encodingName.getName();
+ cmapName = performCMAPSubstitution( cmapName );
+ String resourceName = "Resources/cmap/" + cmapName;
+ parseCmap( ResourceLoader.loadResource( resourceName ), encodingName );
+ if( cmap == null && !encodingName.getName().equals( COSName.IDENTITY_H.getName() ) )
+ {
+ throw new IOException( "Error: Could not find predefined " +
+ "CMAP file for '" + encodingName.getName() + "'" );
+ }
+ }
+ }
+ else if( encoding instanceof COSName ||
+ encoding instanceof COSDictionary )
+ {
+ Encoding currentFontEncoding = getEncoding();
+ if( currentFontEncoding != null )
+ {
+ retval = currentFontEncoding.getCharacter( getCodeFromArray( c, offset, length ) );
+ }
+ }
+ else
+ {
+ COSDictionary fontDescriptor =
+ (COSDictionary)font.getDictionaryObject( COSName.FONT_DESC );
+ if( fontSubtypeName.equals( "TrueType" ) &&
+ fontDescriptor != null &&
+ (fontDescriptor.getDictionaryObject( COSName.FONT_FILE )!= null ||
+ fontDescriptor.getDictionaryObject( COSName.FONT_FILE2 ) != null ||
+ fontDescriptor.getDictionaryObject( COSName.FONT_FILE3 ) != null ) )
+ {
+ //If we are using an embedded font then there is not much we can do besides
+ //return the same character codes.
+ //retval = new String( c,offset, length );
+ retval = getStringFromArray( c, offset, length );
+ }
+ else
+ {
+ //this case will be handled below after checking the cmap
+ }
+ }
+ }
+
+
+ }
+ }
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "retval=" + retval + " cmap=" + cmap);
+ }
+ if( retval == null && cmap != null )
+ {
+
+ retval = cmap.lookup( c, offset, length );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "cmap.lookup(" +c + ")='" +retval + "'" );
+ }
+ }
+ //if we havn't found a value yet and
+ //we are still on the first byte and
+ //there is no cmap or the cmap does not have 2 byte mappings then try to encode
+ //using fallback methods.
+ if( retval == null &&
+ length == 1 &&
+ (cmap == null || !cmap.hasTwoByteMappings()))
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "No CMAP: Using fallback method");
+ }
+ Encoding encoding = getEncoding();
+ if( encoding != null )
+ {
+ retval = encoding.getCharacter( getCodeFromArray( c, offset, length ) );
+ }
+ if( retval == null )
+ {
+ retval = getStringFromArray( c, offset, length );
+ }
+ }
+ return retval;
+ }
+
+ private static final String[] SINGLE_CHAR_STRING = new String[256];
+ private static final String[][] DOUBLE_CHAR_STRING = new String[256][256];
+ static
+ {
+ for( int i=0; i<256; i++ )
+ {
+ SINGLE_CHAR_STRING[i] = new String( new byte[] {(byte)i} );
+ for( int j=0; j<256; j++ )
+ {
+ DOUBLE_CHAR_STRING[i][j] = new String( new byte[] {(byte)i, (byte)j} );
+ }
+ }
+ }
+
+ private static String getStringFromArray( byte[] c, int offset, int length ) throws IOException
+ {
+ String retval = null;
+ if( length == 1 )
+ {
+ retval = SINGLE_CHAR_STRING[(c[offset]+256)%256];
+ }
+ else if( length == 2 )
+ {
+ retval = DOUBLE_CHAR_STRING[(c[offset]+256)%256][(c[offset+1]+256)%256];
+ }
+ else
+ {
+ throw new IOException( "Error:Unknown character length:" + length );
+ }
+ return retval;
+ }
+
+ /**
+ * Some cmap names are synonyms for other CMAPs. If that is the case
+ * then this method will perform that substitution.
+ *
+ * @param cmapName The name of the cmap to attempt to look up.
+ *
+ * @return Either the original name or the substituted name.
+ */
+ private String performCMAPSubstitution( String cmapName )
+ {
+ String retval = (String)cmapSubstitutions.get( cmapName );
+ if( retval == null )
+ {
+ //if there is no substitution then just return the same value.
+ retval = cmapName;
+ }
+ return retval;
+ }
+
+ private void parseCmap( InputStream cmapStream, COSName encodingName ) throws IOException
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Parsing a new CMAP for font:" + font );
+ }
+ if( cmapStream != null )
+ {
+ CMapParser parser = new CMapParser( cmapStream, null );
+ parser.parse();
+ cmap = parser.getResult();
+ if( encodingName != null )
+ {
+ cmapObjects.put( encodingName, cmap );
+ }
+ }
+ }
+
+ /**
+ * The will set the encoding for this font.
+ *
+ * @param enc The font encoding.
+ */
+ public void setEncoding( Encoding enc )
+ {
+ font.setItem( COSName.ENCODING, enc );
+ fontEncoding = enc;
+ }
+
+ /**
+ * This will get or create the encoder.
+ *
+ * modified by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
+ *
+ * @return The encoding to use.
+ *
+ * @throws IOException If there is an error getting the encoding.
+ */
+ public Encoding getEncoding() throws IOException
+ {
+ EncodingManager manager = new EncodingManager();
+ if( fontEncoding == null )
+ {
+ COSBase encoding = font.getDictionaryObject( COSName.ENCODING );
+ if( encoding == null )
+ {
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ fontEncoding = new AFMEncoding( metric );
+ }
+ if( fontEncoding == null )
+ {
+ fontEncoding = manager.getStandardEncoding();
+ }
+ }
+ /**
+ * Si la clé /Encoding existe dans le dictionnaire fonte il y a deux possibilités :
+ * 1er cas : elle est associé à une reference contenant un dictionnaire de type encoding.
+ * Ce dictionnaire PDF est représenté par un DictionaryEncoding.
+ * If the /Encoding Key does exist in the font dictionary, there are two cases :
+ * case one : The value associated with /Encoding is a reference to a dictionary.
+ * This dictionary is represented by an instance of DictionaryEncoding class
+ */
+ else if( encoding instanceof COSDictionary )
+ {
+ COSDictionary encodingDic = (COSDictionary)encoding;
+ //Let's see if the encoding dictionary has a base encoding
+ //If it does not then we will attempt to get it from the font
+ //file
+ COSName baseEncodingName = (COSName) encodingDic.getDictionaryObject(
+ COSName.BASE_ENCODING);
+ //on ajoute une entrée /BaseEncoding dans /Encoding uniquement si elle en est absente
+ //if not find in Encoding dictinary target, we try to find it from else where
+ if( baseEncodingName == null)
+ {
+ COSName fontEncodingFromFile = getEncodingFromFont();
+ encodingDic.setItem(
+ COSName.BASE_ENCODING,
+ fontEncodingFromFile );
+ }
+ fontEncoding = new DictionaryEncoding( encodingDic );
+ }
+ else if( encoding instanceof COSName )
+ {
+ if( !encoding.equals( COSName.IDENTITY_H ) )
+ {
+ fontEncoding = manager.getEncoding( (COSName)encoding );
+ }
+ }
+ else
+ {
+ throw new IOException( "Unexpected encoding type:" + encoding.getClass().getName() );
+ }
+ }
+ return fontEncoding;
+ }
+
+ /**
+ * This will always return "Font" for fonts.
+ *
+ * @return The type of object that this is.
+ */
+ public String getType()
+ {
+ return font.getNameAsString( COSName.TYPE );
+ }
+
+ /**
+ * This will get the subtype of font, Type1, Type3, ...
+ *
+ * @return The type of font that this is.
+ */
+ public String getSubType()
+ {
+ return font.getNameAsString( COSName.SUBTYPE );
+ }
+
+ /**
+ * The PostScript name of the font.
+ *
+ * @return The postscript name of the font.
+ */
+ public String getBaseFont()
+ {
+ return font.getNameAsString( COSName.BASE_FONT );
+ }
+
+ /**
+ * Set the PostScript name of the font.
+ *
+ * @param baseFont The postscript name for the font.
+ */
+ public void setBaseFont( String baseFont )
+ {
+ font.setName( COSName.BASE_FONT, baseFont );
+ }
+
+ /**
+ * The code for the first char or -1 if there is none.
+ *
+ * @return The code for the first character.
+ */
+ public int getFirstChar()
+ {
+ return font.getInt( COSName.FIRST_CHAR, -1 );
+ }
+
+ /**
+ * Set the first character this font supports.
+ *
+ * @param firstChar The first character.
+ */
+ public void setFirstChar( int firstChar )
+ {
+ font.setInt( COSName.FIRST_CHAR, firstChar );
+ }
+
+ /**
+ * The code for the last char or -1 if there is none.
+ *
+ * @return The code for the last character.
+ */
+ public int getLastChar()
+ {
+ return font.getInt( COSName.LAST_CHAR, -1 );
+ }
+
+ /**
+ * Set the last character this font supports.
+ *
+ * @param lastChar The last character.
+ */
+ public void setLastChar( int lastChar )
+ {
+ font.setInt( COSName.LAST_CHAR, lastChar );
+ }
+
+ /**
+ * The widths of the characters. This will be null for the standard 14 fonts.
+ *
+ * @return The widths of the characters.
+ */
+ public List getWidths()
+ {
+ COSArray array = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ return COSArrayList.convertFloatCOSArrayToList( array );
+ }
+
+ /**
+ * Set the widths of the characters code.
+ *
+ * @param widths The widths of the character codes.
+ */
+ public void setWidths( List widths )
+ {
+ font.setItem( COSName.WIDTHS, COSArrayList.converterToCOSArray( widths ) );
+ }
+
+ /**
+ * This will get the matrix that is used to transform glyph space to
+ * text space. By default there are 1000 glyph units to 1 text space
+ * unit, but type3 fonts can use any value.
+ *
+ * Note:If this is a type3 font then it can be modified via the PDType3Font.setFontMatrix, otherwise this
+ * is a read-only property.
+ *
+ * @return The matrix to transform from glyph space to text space.
+ */
+ public PDMatrix getFontMatrix()
+ {
+ PDMatrix matrix = null;
+ COSArray array = (COSArray)font.getDictionaryObject( COSName.FONT_MATRIX );
+ if( array == null )
+ {
+ array = new COSArray();
+ array.add( new COSFloat( 0.001f ) );
+ array.add( COSNumber.ZERO );
+ array.add( COSNumber.ZERO );
+ array.add( new COSFloat( 0.001f ) );
+ array.add( COSNumber.ZERO );
+ array.add( COSNumber.ZERO );
+ }
+ matrix = new PDMatrix(array);
+
+ return matrix;
+ }
+
+ /**
+ * Try to get the encoding for the font and add it to the target
+ * the target must be an an Encoding Dictionary.
+ *
+ * added by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
+ *
+ * @return The encoding from the font.
+ *
+ * @throws IOException If there is an error reading the file.
+ */
+ private COSName getEncodingFromFont() throws IOException
+ {
+ //This whole section of code needs to be replaced with an actual
+ //type1 font parser!!
+
+
+ COSName retvalue = null;
+ //recuperer le programme de fonte dans son stream qui doit se trouver
+ //dans le flux référencé par à la clé FileFont lui même situé dans
+ //le dictionnaire associé à /FontDescriptor du dictionnaire de type /Font courrant
+ //get the font program in the stream which should be located in
+ //the /FileFont Stream object himself in the /FontDescriptior of the current
+ //font dictionary
+ COSDictionary fontDescriptor = (COSDictionary) font.getDictionaryObject(
+ COSName.FONT_DESC);
+ if( fontDescriptor != null )
+ {
+ COSStream fontFile = (COSStream) fontDescriptor.getDictionaryObject(
+ COSName.FONT_FILE);
+ if( fontFile != null )
+ {
+ BufferedReader in =
+ new BufferedReader(new InputStreamReader(fontFile.getUnfilteredStream()));
+ /**
+ * this section parse the FileProgram stream searching for a /Encoding entry
+ * the research stop if the entry "currentdict end" is reach or after 100 lignes
+ */
+ StringTokenizer st = null;
+ boolean found = false;
+ String line = "";
+ String key = null;
+ for( int i = 0; null!=( line = in.readLine() ) &&
+ i < 40 &&
+ !line.equals("currentdict end")
+ && !found; i++)
+ {
+ st = new StringTokenizer(line);
+ if( st.hasMoreTokens() )
+ {
+ key = st.nextToken();
+ if(key.equals("/Encoding") && st.hasMoreTokens() )
+ {
+ COSName value = COSName.getPDFName( st.nextToken() );
+ found = true;
+ if( value.equals( COSName.MAC_ROMAN_ENCODING ) ||
+ value.equals( COSName.PDF_DOC_ENCODING ) ||
+ value.equals( COSName.STANDARD_ENCODING ) ||
+ value.equals( COSName.WIN_ANSI_ENCODING ) )
+ {
+ //value is expected to be one of the encodings
+ //ie. StandardEncoding,WinAnsiEncoding,MacRomanEncoding,PDFDocEncoding
+ retvalue = value;
+ }
+ }
+ }
+ }
+ }
+ }
+ return retvalue;
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public abstract PDRectangle getFontBoundingBox() throws IOException;
+
+ /**
+ * @see Object#equals( Object )
+ */
+ public boolean equals( Object other )
+ {
+ return other instanceof PDFont && ((PDFont)other).getCOSObject() == this.getCOSObject();
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return this.getCOSObject().hashCode();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java
new file mode 100644
index 0000000..59668ce
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java
@@ -0,0 +1,530 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+/**
+ * This class represents an interface to the font description. This will depend
+ * on the font type for the actual implementation. If it is a AFM/cmap/or embedded font.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.1 $
+ */
+public abstract class PDFontDescriptor
+{
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_FIXED_PITCH = 1;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SERIF = 2;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SYMBOLIC = 3;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SCRIPT = 4;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_NON_SYMBOLIC = 6;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_ITALIC = 7;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_ALL_CAP = 17;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SMALL_CAP = 18;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_FORCE_BOLD = 19;
+
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public abstract String getFontName();
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public abstract void setFontName( String fontName );
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public abstract String getFontFamily();
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public abstract void setFontFamily( String fontFamily );
+
+ /**
+ * A string representing the preferred font stretch.
+ * According to the PDF Spec:
+ * The font stretch value; it must be one of the following (ordered from
+ * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed,
+ * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded.
+ *
+ * @return The font stretch.
+ */
+ public abstract String getFontStretch();
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The font stretch
+ */
+ public abstract void setFontStretch( String fontStretch );
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public abstract float getFontWeight();
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public abstract void setFontWeight( float fontWeight );
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public abstract int getFlags();
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public abstract void setFlags( int flags );
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isFixedPitch()
+ {
+ return isFlagBitOn( FLAG_FIXED_PITCH );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setFixedPitch( boolean flag )
+ {
+ setFlagBit( FLAG_FIXED_PITCH, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSerif()
+ {
+ return isFlagBitOn( FLAG_SERIF );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSerif( boolean flag )
+ {
+ setFlagBit( FLAG_SERIF, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSymbolic()
+ {
+ return isFlagBitOn( FLAG_SYMBOLIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSymbolic( boolean flag )
+ {
+ setFlagBit( FLAG_SYMBOLIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isScript()
+ {
+ return isFlagBitOn( FLAG_SCRIPT );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setScript( boolean flag )
+ {
+ setFlagBit( FLAG_SCRIPT, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isNonSymbolic()
+ {
+ return isFlagBitOn( FLAG_NON_SYMBOLIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setNonSymbolic( boolean flag )
+ {
+ setFlagBit( FLAG_NON_SYMBOLIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isItalic()
+ {
+ return isFlagBitOn( FLAG_ITALIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setItalic( boolean flag )
+ {
+ setFlagBit( FLAG_ITALIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isAllCap()
+ {
+ return isFlagBitOn( FLAG_ALL_CAP);
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setAllCap( boolean flag )
+ {
+ setFlagBit( FLAG_ALL_CAP, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSmallCap()
+ {
+ return isFlagBitOn( FLAG_SMALL_CAP );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSmallCap( boolean flag )
+ {
+ setFlagBit( FLAG_SMALL_CAP, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isForceBold()
+ {
+ return isFlagBitOn( FLAG_FORCE_BOLD );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setForceBold( boolean flag )
+ {
+ setFlagBit( FLAG_FORCE_BOLD, flag );
+ }
+
+ private boolean isFlagBitOn( int bit )
+ {
+ return (getFlags() & (1 << (bit-1))) != 0;
+ }
+
+ private void setFlagBit( int bit, boolean value )
+ {
+ int flags = getFlags();
+ if( value )
+ {
+ flags = flags| (1 << (bit-1));
+ }
+ else
+ {
+ flags = flags & (0xFFFFFFFF ^ (1 << (bit-1)));
+ }
+ setFlags( flags );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public abstract PDRectangle getFontBoundingBox();
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public abstract void setFontBoundingBox( PDRectangle rect );
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public abstract float getItalicAngle();
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public abstract void setItalicAngle( float angle );
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public abstract float getAscent();
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public abstract void setAscent( float ascent );
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public abstract float getDescent();
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public abstract void setDescent( float descent );
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public abstract float getLeading();
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public abstract void setLeading( float leading );
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public abstract float getCapHeight();
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public abstract void setCapHeight( float capHeight );
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public abstract float getXHeight();
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public abstract void setXHeight( float xHeight );
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public abstract float getStemV();
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public abstract void setStemV( float stemV );
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public abstract float getStemH();
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public abstract void setStemH( float stemH );
+
+ /**
+ * This will get the average width for the font. This is part of the
+ * definition in the font description. If it is not present then PDFBox
+ * will make an attempt to calculate it.
+ *
+ * @return The average width value.
+ *
+ * @throws IOException If there is an error calculating the average width.
+ */
+ public abstract float getAverageWidth() throws IOException;
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public abstract void setAverageWidth( float averageWidth );
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public abstract float getMaxWidth();
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public abstract void setMaxWidth( float maxWidth );
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public abstract String getCharSet();
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public abstract void setCharacterSet( String charSet );
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
new file mode 100644
index 0000000..3326b74
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
@@ -0,0 +1,446 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.pdfbox.util.BoundingBox;
+
+/**
+ * This class represents the font descriptor when the font information
+ * is coming from an AFM file.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.1 $
+ */
+public class PDFontDescriptorAFM extends PDFontDescriptor
+{
+ private FontMetric afm;
+
+ /**
+ * Constructor.
+ *
+ * @param afmFile The AFM file.
+ */
+ public PDFontDescriptorAFM( FontMetric afmFile )
+ {
+ afm = afmFile;
+ }
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public String getFontName()
+ {
+ return afm.getFontName();
+ }
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public void setFontName( String fontName )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public String getFontFamily()
+ {
+ return afm.getFamilyName();
+ }
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public void setFontFamily( String fontFamily )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public float getFontWeight()
+ {
+ String weight = afm.getWeight();
+ float retval = 500;
+ if( weight != null && weight.equalsIgnoreCase( "bold" ) )
+ {
+ retval = 900;
+ }
+ else if( weight != null && weight.equalsIgnoreCase( "light" ) )
+ {
+ retval = 100;
+ }
+ return retval;
+ }
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public void setFontWeight( float fontWeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * A string representing the preferred font stretch.
+ *
+ * @return The font stretch.
+ */
+ public String getFontStretch()
+ {
+ return null;
+ }
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The font stretch
+ */
+ public void setFontStretch( String fontStretch )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public int getFlags()
+ {
+ //I believe that the only flag that AFM supports is the is fixed pitch
+ return afm.isFixedPitch() ? 1 : 0;
+ }
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public void setFlags( int flags )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public PDRectangle getFontBoundingBox()
+ {
+ BoundingBox box = afm.getFontBBox();
+ PDRectangle retval = null;
+ if( box != null )
+ {
+ retval = new PDRectangle( box );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public void setFontBoundingBox( PDRectangle rect )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public float getItalicAngle()
+ {
+ return afm.getItalicAngle();
+ }
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public void setItalicAngle( float angle )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public float getAscent()
+ {
+ return afm.getAscender();
+ }
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public void setAscent( float ascent )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public float getDescent()
+ {
+ return afm.getDescender();
+ }
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public void setDescent( float descent )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public float getLeading()
+ {
+ //AFM does not support setting the leading so we will just ignore it.
+ return 0f;
+ }
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public void setLeading( float leading )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public float getCapHeight()
+ {
+ return afm.getCapHeight();
+ }
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public void setCapHeight( float capHeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public float getXHeight()
+ {
+ return afm.getXHeight();
+ }
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public void setXHeight( float xHeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public float getStemV()
+ {
+ //afm does not have a stem v
+ return 0;
+ }
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public void setStemV( float stemV )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public float getStemH()
+ {
+ //afm does not have a stem h
+ return 0;
+ }
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public void setStemH( float stemH )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the average width for the font.
+ *
+ * @return The average width value.
+ *
+ * @throws IOException If there is an error calculating the average width.
+ */
+ public float getAverageWidth() throws IOException
+ {
+ return afm.getAverageCharacterWidth();
+ }
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public void setAverageWidth( float averageWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public float getMaxWidth()
+ {
+ //afm does not support max width;
+ return 0;
+ }
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public void setMaxWidth( float maxWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the missing width for the font.
+ *
+ * @return The missing width value.
+ */
+ public float getMissingWidth()
+ {
+ return 0;
+ }
+
+ /**
+ * This will set the missing width for the font.
+ *
+ * @param missingWidth The new missing width for the font.
+ */
+ public void setMissingWidth( float missingWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public String getCharSet()
+ {
+ return afm.getCharacterSet();
+ }
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public void setCharacterSet( String charSet )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
new file mode 100644
index 0000000..f3bf61e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
@@ -0,0 +1,580 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This class represents an implementation to the font descriptor that gets its
+ * information from a COS Dictionary.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.2 $
+ */
+public class PDFontDescriptorDictionary extends PDFontDescriptor
+{
+ private COSDictionary dic;
+
+ /**
+ * Constructor.
+ */
+ public PDFontDescriptorDictionary()
+ {
+ dic = new COSDictionary();
+ dic.setName( "Type", "FontDescriptor" );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param desc The wrapped COS Dictionary.
+ */
+ public PDFontDescriptorDictionary( COSDictionary desc )
+ {
+ dic = desc;
+ }
+
+ /**
+ * This will get the dictionary for this object.
+ *
+ * @return The COS dictionary.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return dic;
+ }
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public String getFontName()
+ {
+ String retval = null;
+ COSName name = (COSName)dic.getDictionaryObject( COSName.getPDFName( "FontName" ) );
+ if( name != null )
+ {
+ retval = name.getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public void setFontName( String fontName )
+ {
+ COSName name = null;
+ if( fontName != null )
+ {
+ name = COSName.getPDFName( fontName );
+ }
+ dic.setItem( COSName.getPDFName( "FontName" ), name );
+ }
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public String getFontFamily()
+ {
+ String retval = null;
+ COSString name = (COSString)dic.getDictionaryObject( COSName.getPDFName( "FontFamily" ) );
+ if( name != null )
+ {
+ retval = name.getString();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public void setFontFamily( String fontFamily )
+ {
+ COSString name = null;
+ if( fontFamily != null )
+ {
+ name = new COSString( fontFamily );
+ }
+ dic.setItem( COSName.getPDFName( "FontFamily" ), name );
+ }
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public float getFontWeight()
+ {
+ return dic.getFloat( "FontWeight",0 );
+ }
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public void setFontWeight( float fontWeight )
+ {
+ dic.setFloat( "FontWeight", fontWeight );
+ }
+
+ /**
+ * A string representing the preferred font stretch.
+ * According to the PDF Spec:
+ * The font stretch value; it must be one of the following (ordered from
+ * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed,
+ * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded.
+ *
+ * @return The stretch of the font.
+ */
+ public String getFontStretch()
+ {
+ String retval = null;
+ COSName name = (COSName)dic.getDictionaryObject( COSName.getPDFName( "FontStretch" ) );
+ if( name != null )
+ {
+ retval = name.getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The new stretch for the font.
+ */
+ public void setFontStretch( String fontStretch )
+ {
+ COSName name = null;
+ if( fontStretch != null )
+ {
+ name = COSName.getPDFName( fontStretch );
+ }
+ dic.setItem( COSName.getPDFName( "FontStretch" ), name );
+ }
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public int getFlags()
+ {
+ return dic.getInt( "Flags", 0 );
+ }
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public void setFlags( int flags )
+ {
+ dic.setInt( "Flags", flags );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public PDRectangle getFontBoundingBox()
+ {
+ COSArray rect = (COSArray)dic.getDictionaryObject( COSName.getPDFName( "FontBBox" ) );
+ PDRectangle retval = null;
+ if( rect != null )
+ {
+ retval = new PDRectangle( rect );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public void setFontBoundingBox( PDRectangle rect )
+ {
+ COSArray array = null;
+ if( rect != null )
+ {
+ array = rect.getCOSArray();
+ }
+ dic.setItem( COSName.getPDFName( "FontBBox" ), array );
+ }
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public float getItalicAngle()
+ {
+ return dic.getFloat( "ItalicAngle", 0 );
+ }
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public void setItalicAngle( float angle )
+ {
+ dic.setFloat( "ItalicAngle", angle );
+ }
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public float getAscent()
+ {
+ return dic.getFloat( "Ascent", 0 );
+ }
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public void setAscent( float ascent )
+ {
+ dic.setFloat( "Ascent", ascent );
+ }
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public float getDescent()
+ {
+ return dic.getFloat( "Descent", 0 );
+ }
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public void setDescent( float descent )
+ {
+ dic.setFloat( "Descent", descent );
+ }
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public float getLeading()
+ {
+ return dic.getFloat( "Leading", 0 );
+ }
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public void setLeading( float leading )
+ {
+ dic.setFloat( "Leading", leading );
+ }
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public float getCapHeight()
+ {
+ return dic.getFloat( "CapHeight", 0 );
+ }
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public void setCapHeight( float capHeight )
+ {
+ dic.setFloat( "CapHeight", capHeight );
+ }
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public float getXHeight()
+ {
+ return dic.getFloat( "XHeight", 0 );
+ }
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public void setXHeight( float xHeight )
+ {
+ dic.setFloat( "XHeight", xHeight );
+ }
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public float getStemV()
+ {
+ return dic.getFloat( "StemV", 0 );
+ }
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public void setStemV( float stemV )
+ {
+ dic.setFloat( "StemV", stemV );
+ }
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public float getStemH()
+ {
+ return dic.getFloat( "StemH", 0 );
+ }
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public void setStemH( float stemH )
+ {
+ dic.setFloat( "StemH", stemH );
+ }
+
+ /**
+ * This will get the average width for the font.
+ *
+ * @return The average width value.
+ */
+ public float getAverageWidth()
+ {
+ return dic.getFloat( "AvgWidth", 0 );
+ }
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public void setAverageWidth( float averageWidth )
+ {
+ dic.setFloat( "AvgWidth", averageWidth );
+ }
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public float getMaxWidth()
+ {
+ return dic.getFloat( "MaxWidth", 0 );
+ }
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public void setMaxWidth( float maxWidth )
+ {
+ dic.setFloat( "MaxWidth", maxWidth );
+ }
+
+ /**
+ * This will get the missing width for the font.
+ *
+ * @return The missing width value.
+ */
+ public float getMissingWidth()
+ {
+ return dic.getFloat( "MissingWidth", 0 );
+ }
+
+ /**
+ * This will set the missing width for the font.
+ *
+ * @param missingWidth The new missing width for the font.
+ */
+ public void setMissingWidth( float missingWidth )
+ {
+ dic.setFloat( "MissingWidth", missingWidth );
+ }
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public String getCharSet()
+ {
+ String retval = null;
+ COSString name = (COSString)dic.getDictionaryObject( COSName.getPDFName( "CharSet" ) );
+ if( name != null )
+ {
+ retval = name.getString();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public void setCharacterSet( String charSet )
+ {
+ COSString name = null;
+ if( charSet != null )
+ {
+ name = new COSString( charSet );
+ }
+ dic.setItem( COSName.getPDFName( "CharSet" ), name );
+ }
+
+ /**
+ * A stream containing a Type 1 font program.
+ *
+ * @return A stream containing a Type 1 font program.
+ */
+ public PDStream getFontFile()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the type 1 font program.
+ *
+ * @param type1Stream The type 1 stream.
+ */
+ public void setFontFile( PDStream type1Stream )
+ {
+ dic.setItem( "FontFile", type1Stream );
+ }
+
+ /**
+ * A stream containing a true type font program.
+ *
+ * @return A stream containing a true type font program.
+ */
+ public PDStream getFontFile2()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile2" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the true type font program.
+ *
+ * @param ttfStream The true type stream.
+ */
+ public void setFontFile2( PDStream ttfStream )
+ {
+ dic.setItem( "FontFile2", ttfStream );
+ }
+
+ /**
+ * A stream containing a font program that is not true type or type 1.
+ *
+ * @return A stream containing a font program.
+ */
+ public PDStream getFontFile3()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile3" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set a stream containing a font program that is not true type or type 1.
+ *
+ * @param stream The font program stream.
+ */
+ public void setFontFile3( PDStream stream )
+ {
+ dic.setItem( "FontFile3", stream );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java
new file mode 100644
index 0000000..329a8bf
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This will create the correct type of font based on information in the dictionary.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDFontFactory
+{
+ /**
+ * private constructor, should only use static methods in this class.
+ */
+ private PDFontFactory()
+ {
+ }
+
+ /**
+ * This will create the correct font based on information in the dictionary.
+ *
+ * @param dic The populated dictionary.
+ *
+ * @return The corrent implementation for the font.
+ *
+ * @throws IOException If the dictionary is not valid.
+ */
+ public static PDFont createFont( COSDictionary dic ) throws IOException
+ {
+ PDFont retval = null;
+
+ COSName type = (COSName)dic.getDictionaryObject( COSName.TYPE );
+ if( !type.equals( COSName.FONT ) )
+ {
+ throw new IOException( "Cannot create font if /Type is not /Font. Actual=" +type );
+ }
+
+ COSName subType = (COSName)dic.getDictionaryObject( COSName.SUBTYPE );
+ if( subType.equals( COSName.getPDFName( "Type1" ) ) )
+ {
+ retval = new PDType1Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "MMType1" ) ) )
+ {
+ retval = new PDMMType1Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "TrueType" ) ) )
+ {
+ retval = new PDTrueTypeFont( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "Type3" ) ) )
+ {
+ retval = new PDType3Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "Type0" ) ) )
+ {
+ retval = new PDType0Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "CIDFontType0" ) ) )
+ {
+ retval = new PDCIDFontType0Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "CIDFontType2" ) ) )
+ {
+ retval = new PDCIDFontType2Font( dic );
+ }
+ else
+ {
+ throw new IOException( "Unknown font subtype=" + subType );
+ }
+
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java
new file mode 100644
index 0000000..a0dffba
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is implementation of the Multiple Master Type1 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDMMType1Font extends PDSimpleFont
+{
+ /**
+ * Constructor.
+ */
+ public PDMMType1Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "MMType1" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDMMType1Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java
new file mode 100644
index 0000000..a1356ba
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java
@@ -0,0 +1,239 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSInteger;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This class contains implementation details of the simple pdf fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.11 $
+ */
+public abstract class PDSimpleFont extends PDFont
+{
+ private static Logger log = Logger.getLogger( PDSimpleFont.class );
+ /**
+ * Constructor.
+ */
+ public PDSimpleFont()
+ {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDSimpleFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ log.warn( "Not yet implemented:" + getClass().getName() );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+ float fontWidth = 0;
+ int code = getCodeFromArray( c, offset, length );
+
+ //hmm should this be in a subclass??
+ COSInteger firstChar = (COSInteger)font.getDictionaryObject( COSName.FIRST_CHAR );
+ COSInteger lastChar = (COSInteger)font.getDictionaryObject( COSName.LAST_CHAR );
+ if( firstChar != null && lastChar != null )
+ {
+ long first = firstChar.intValue();
+ long last = lastChar.intValue();
+ if( code >= first && code <= last && font.getDictionaryObject( COSName.WIDTHS ) != null )
+ {
+ COSArray widthArray = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ COSNumber fontWidthObject = (COSNumber)widthArray.get( (int)(code - first) );
+ fontWidth = fontWidthObject.floatValue();
+ }
+ else
+ {
+ fontWidth = getFontWidthFromAFMFile( code );
+ }
+ }
+ else
+ {
+ fontWidth = getFontWidthFromAFMFile( code );
+ }
+ return fontWidth;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ float average = 0.0f;
+ float totalWidth = 0.0f;
+ float characterCount = 0.0f;
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ if( widths != null )
+ {
+ for( int i=0; i<widths.size(); i++ )
+ {
+ COSNumber fontWidth = (COSNumber)widths.getObject( i );
+ if( fontWidth.floatValue() > 0 )
+ {
+ totalWidth += fontWidth.floatValue();
+ characterCount += 1;
+ }
+ }
+ }
+
+ if( totalWidth > 0 )
+ {
+ average = totalWidth / characterCount;
+ }
+ else
+ {
+ average = getAverageFontWidthFromAFMFile();
+ }
+ return average;
+ }
+
+ /**
+ * This will get the font descriptor for this font.
+ *
+ * @return The font descriptor for this font.
+ *
+ * @throws IOException If there is an error parsing an AFM file, or unable to
+ * create a PDFontDescriptor object.
+ */
+ public PDFontDescriptor getFontDescriptor() throws IOException
+ {
+ PDFontDescriptor retval = null;
+ COSDictionary fd = (COSDictionary)font.getDictionaryObject( COSName.getPDFName( "FontDescriptor" ) );
+ if( fd == null )
+ {
+ FontMetric afm = getAFM();
+ if( afm == null )
+ {
+ throw new IOException( "Error: Can't create font descriptor file" );
+ }
+ retval = new PDFontDescriptorAFM( afm );
+ }
+ else
+ {
+ retval = new PDFontDescriptorDictionary( fd );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the font descriptor.
+ *
+ * @param fontDescriptor The font descriptor.
+ */
+ public void setFontDescriptor( PDFontDescriptorDictionary fontDescriptor )
+ {
+ COSDictionary dic = null;
+ if( fontDescriptor != null )
+ {
+ dic = fontDescriptor.getCOSDictionary();
+ }
+ font.setItem( COSName.getPDFName( "FontDescriptor" ), dic );
+ }
+
+ /**
+ * This will get the ToUnicode stream.
+ *
+ * @return The ToUnicode stream.
+ * @throws IOException If there is an error getting the stream.
+ */
+ public PDStream getToUnicode() throws IOException
+ {
+ return PDStream.createFromCOS( font.getDictionaryObject( "ToUnicode" ) );
+ }
+
+ /**
+ * This will set the ToUnicode stream.
+ *
+ * @param unicode The unicode stream.
+ */
+ public void setToUnicode( PDStream unicode )
+ {
+ font.setItem( "ToUnicode", unicode );
+ }
+
+ /**
+ * This will get the fonts bounding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ return getFontDescriptor().getFontBoundingBox();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java
new file mode 100644
index 0000000..d462255
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java
@@ -0,0 +1,437 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.PDDocument;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import org.pdfbox.encoding.WinAnsiEncoding;
+
+import org.pdfbox.ttf.CMAPEncodingEntry;
+import org.pdfbox.ttf.CMAPTable;
+import org.pdfbox.ttf.GlyphData;
+import org.pdfbox.ttf.GlyphTable;
+import org.pdfbox.ttf.HeaderTable;
+import org.pdfbox.ttf.HorizontalHeaderTable;
+import org.pdfbox.ttf.HorizontalMetricsTable;
+import org.pdfbox.ttf.MemoryTTFDataStream;
+import org.pdfbox.ttf.NamingTable;
+import org.pdfbox.ttf.NameRecord;
+import org.pdfbox.ttf.OS2WindowsMetricsTable;
+import org.pdfbox.ttf.PostScriptTable;
+import org.pdfbox.ttf.TTFParser;
+import org.pdfbox.ttf.TrueTypeFont;
+import org.pdfbox.util.ResourceLoader;
+
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This is the TrueType implementation of fonts.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.14 $
+ */
+public class PDTrueTypeFont extends PDSimpleFont
+{
+ /**
+ * This is the key to a property in the Resources/PDFBox_External_Fonts.properties file
+ * to load a Font when a mapping does not exist for the current font.
+ */
+ public static final String UNKNOWN_FONT = "UNKNOWN_FONT";
+
+ private Font awtFont = null;
+
+ private static Properties externalFonts = new Properties();
+ private static Map loadedExternalFonts = new HashMap();
+
+ static
+ {
+ try
+ {
+ ResourceLoader.loadProperties( "Resources/PDFBox_External_Fonts.properties", externalFonts );
+ }
+ catch( IOException io )
+ {
+ io.printStackTrace();
+ throw new RuntimeException( "Error loading font resources" );
+ }
+ }
+
+
+ /**
+ * Constructor.
+ */
+ public PDTrueTypeFont()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.TRUE_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDTrueTypeFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * This will load a TTF font from a font file.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param file The file on the filesystem that holds the font file.
+ * @return A true type font.
+ * @throws IOException If there is an error loading the file data.
+ */
+ public static PDTrueTypeFont loadTTF( PDDocument doc, String file ) throws IOException
+ {
+ return loadTTF( doc, new File( file ) );
+ }
+
+ /**
+ * This will load a TTF to be embedding into a document.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param file A TTF file stream.
+ * @return A PDF TTF.
+ * @throws IOException If there is an error loading the data.
+ */
+ public static PDTrueTypeFont loadTTF( PDDocument doc, File file ) throws IOException
+ {
+ PDTrueTypeFont retval = new PDTrueTypeFont();
+ PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
+ PDStream fontStream = new PDStream(doc, new FileInputStream( file ), false );
+ fontStream.getStream().setInt( COSName.LENGTH1, (int)file.length() );
+ fontStream.addCompression();
+ fd.setFontFile2( fontStream );
+ retval.setFontDescriptor( fd );
+ //only support winansi encoding right now, should really
+ //just use Identity-H with unicode mapping
+ retval.setEncoding( new WinAnsiEncoding() );
+ TrueTypeFont ttf = null;
+ try
+ {
+ TTFParser parser = new TTFParser();
+ ttf = parser.parseTTF( file );
+ NamingTable naming = ttf.getNaming();
+ List records = naming.getNameRecords();
+ for( int i=0; i<records.size(); i++ )
+ {
+ NameRecord nr = (NameRecord)records.get( i );
+ if( nr.getNameId() == NameRecord.NAME_POSTSCRIPT_NAME )
+ {
+ retval.setBaseFont( nr.getString() );
+ fd.setFontName( nr.getString() );
+ }
+ else if( nr.getNameId() == NameRecord.NAME_FONT_FAMILY_NAME )
+ {
+ fd.setFontFamily( nr.getString() );
+ }
+ }
+
+ OS2WindowsMetricsTable os2 = ttf.getOS2Windows();
+ fd.setNonSymbolic( true );
+ switch( os2.getFamilyClass() )
+ {
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SYMBOLIC:
+ fd.setSymbolic( true );
+ fd.setNonSymbolic( false );
+ break;
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS:
+ fd.setScript( true );
+ break;
+ case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS:
+ fd.setSerif( true );
+ break;
+ default:
+ //do nothing
+ }
+ switch( os2.getWidthClass() )
+ {
+ case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_CONDENSED:
+ fd.setFontStretch( "UltraCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_CONDENSED:
+ fd.setFontStretch( "ExtraCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_CONDENSED:
+ fd.setFontStretch( "Condensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_CONDENSED:
+ fd.setFontStretch( "SemiCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_MEDIUM:
+ fd.setFontStretch( "Normal" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_EXPANDED:
+ fd.setFontStretch( "SemiExpanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXPANDED:
+ fd.setFontStretch( "Expanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_EXPANDED:
+ fd.setFontStretch( "ExtraExpanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_EXPANDED:
+ fd.setFontStretch( "UltraExpanded" );
+ break;
+ default:
+ //do nothing
+ }
+ fd.setFontWeight( os2.getWeightClass() );
+
+ //todo retval.setFixedPitch
+ //todo retval.setNonSymbolic
+ //todo retval.setItalic
+ //todo retval.setAllCap
+ //todo retval.setSmallCap
+ //todo retval.setForceBold
+
+ HeaderTable header = ttf.getHeader();
+ PDRectangle rect = new PDRectangle();
+ rect.setLowerLeftX( header.getXMin() * 1000f/header.getUnitsPerEm() );
+ rect.setLowerLeftY( header.getYMin() * 1000f/header.getUnitsPerEm() );
+ rect.setUpperRightX( header.getXMax() * 1000f/header.getUnitsPerEm() );
+ rect.setUpperRightY( header.getYMax() * 1000f/header.getUnitsPerEm() );
+ fd.setFontBoundingBox( rect );
+
+ HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
+ fd.setAscent( hHeader.getAscender() * 1000f/header.getUnitsPerEm() );
+ fd.setDescent( hHeader.getDescender() * 1000f/header.getUnitsPerEm() );
+
+ GlyphTable glyphTable = ttf.getGlyph();
+ GlyphData[] glyphs = glyphTable.getGlyphs();
+
+ PostScriptTable ps = ttf.getPostScript();
+ fd.setFixedPitch( ps.getIsFixedPitch() > 0 );
+ fd.setItalicAngle( ps.getItalicAngle() );
+
+ String[] names = ps.getGlyphNames();
+ if( names != null )
+ {
+ for( int i=0; i<names.length; i++ )
+ {
+ //if we have a capital H then use that, otherwise use the
+ //tallest letter
+ if( names[i].equals( "H" ) )
+ {
+ fd.setCapHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/
+ header.getUnitsPerEm() );
+ }
+ if( names[i].equals( "x" ) )
+ {
+ fd.setXHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/header.getUnitsPerEm() );
+ }
+ }
+ }
+
+ //hmm there does not seem to be a clear definition for StemV,
+ //this is close enough and I am told it doesn't usually get used.
+ fd.setStemV( (fd.getFontBoundingBox().getWidth() * .13f) );
+
+
+ CMAPTable cmapTable = ttf.getCMAP();
+ CMAPEncodingEntry[] cmaps = cmapTable.getCmaps();
+ int[] glyphToCCode = null;
+ for( int i=0; i<cmaps.length; i++ )
+ {
+ if( cmaps[i].getPlatformId() == CMAPTable.PLATFORM_WINDOWS &&
+ cmaps[i].getPlatformEncodingId() == CMAPTable.ENCODING_UNICODE )
+ {
+ glyphToCCode = cmaps[i].getGlyphIdToCharacterCode();
+ }
+ }
+ int firstChar = 0;
+ /**
+ for( int i=0; i<glyphToCCode.length; i++ )
+ {
+ if( glyphToCCode[i] != 0 )
+ {
+ firstChar = Math.min( glyphToCCode[i], firstChar );
+ }
+ }*/
+
+ int maxWidths=256;
+ HorizontalMetricsTable hMet = ttf.getHorizontalMetrics();
+ int[] widthValues = hMet.getAdvanceWidth();
+ List widths = new ArrayList( widthValues.length );
+ Integer zero = new Integer( 250 );
+ for( int i=0; i<widthValues.length && i<maxWidths; i++ )
+ {
+ widths.add( zero );
+ }
+ for( int i=0; i<widthValues.length; i++ )
+ {
+ if(glyphToCCode[i]-firstChar < widths.size() &&
+ glyphToCCode[i]-firstChar >= 0 &&
+ widths.get( glyphToCCode[i]-firstChar) == zero )
+ {
+ widths.set( glyphToCCode[i]-firstChar,
+ new Integer( (int)(widthValues[i]* 1000f)/header.getUnitsPerEm() ) );
+ }
+ }
+ retval.setWidths( widths );
+
+ retval.setFirstChar( firstChar );
+ retval.setLastChar( firstChar + widths.size()-1 );
+
+ }
+ finally
+ {
+ if( ttf != null )
+ {
+ ttf.close();
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary)getFontDescriptor();
+ if( awtFont == null )
+ {
+ PDStream ttfStream = fd.getFontFile2();
+ String fontName = fd.getFontName();
+ awtFont = Font.getFont( fontName, null );
+ if( ttfStream == null )
+ {
+ //throw new IOException( "Error:TTF Stream is null");
+ // Embedded true type programs are optional,
+ // if there is no stream, we must use an external
+ // file.
+ ttfStream = getExternalFontFile2( fd );
+ }
+ if( ttfStream == null )
+ {
+ //if we can't find a font then just fake it.
+ awtFont = new Font("Arial", Font.PLAIN, 1 );
+ }
+ else
+ {
+ try
+ {
+ awtFont = Font.createFont( Font.TRUETYPE_FONT, ttfStream.createInputStream() );
+ }
+ catch( FontFormatException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ }
+ }
+ AffineTransform at = new AffineTransform();
+ at.scale( xScale, yScale );
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+ g2d.setFont( awtFont.deriveFont( at ).deriveFont( fontSize ) );
+ g2d.drawString( string, (int)x, (int)y );
+ }
+
+ /**
+ * Permit to load an external TTF Font program file
+ *
+ * Created by Pascal Allain
+ * Vertical7 Inc.
+ *
+ * @param fd The font descriptor currently used
+ *
+ * @return A PDStream with the Font File program, null if fd is null
+ *
+ * @throws IOException If the font is not found
+ */
+ private PDStream getExternalFontFile2(PDFontDescriptorDictionary fd)
+ throws IOException
+ {
+ PDStream retval = null;
+
+ if ( fd != null )
+ {
+ String baseFont = getBaseFont();
+ String fontResource = externalFonts.getProperty( UNKNOWN_FONT );
+ if( (baseFont != null) &&
+ (externalFonts.containsKey(baseFont)) )
+ {
+ fontResource = externalFonts.getProperty(baseFont);
+ }
+ if( fontResource != null )
+ {
+ TrueTypeFont extTTF = (TrueTypeFont)loadedExternalFonts.get( baseFont );
+ if( extTTF == null )
+ {
+ TTFParser ttfParser = new TTFParser();
+ InputStream is = ResourceLoader.loadResource( fontResource );
+ if( is == null )
+ {
+ throw new IOException( "Error missing font resource '" + externalFonts.get(baseFont) + "'" );
+ }
+ MemoryTTFDataStream stream = new MemoryTTFDataStream( is );
+ extTTF = ttfParser.parseTTF( stream );
+ loadedExternalFonts.put( baseFont, extTTF );
+ }
+ retval = extTTF.getPDStream();
+ }
+ }
+
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java
new file mode 100644
index 0000000..010df33
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import java.io.IOException;
+
+/**
+ * This is implementation of the Type0 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public class PDType0Font extends PDFont
+{
+ /**
+ * Constructor.
+ */
+ public PDType0Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type0" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType0Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y )
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+ COSArray descendantFontArray =
+ (COSArray)font.getDictionaryObject( COSName.getPDFName( "DescendantFonts" ) );
+
+ COSDictionary descendantFontDictionary = (COSDictionary)descendantFontArray.getObject( 0 );
+ PDFont descendentFont = PDFontFactory.createFont( descendantFontDictionary );
+
+ return descendentFont.getFontWidth( c, offset, length );
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ COSArray descendantFontArray =
+ (COSArray)font.getDictionaryObject( COSName.getPDFName( "DescendantFonts" ) );
+
+ COSDictionary descendantFontDictionary = (COSDictionary)descendantFontArray.getObject( 0 );
+ PDFont descendentFont = PDFontFactory.createFont( descendantFontDictionary );
+
+ return descendentFont.getAverageFontWidth();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java
new file mode 100644
index 0000000..89fdc5e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+
+package org.pdfbox.pdmodel.font;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.pdfbox.afmparser.AFMParser;
+import org.pdfbox.afmtypes.CharMetric;
+import org.pdfbox.afmtypes.FontMetric;
+import org.pdfbox.encoding.AFMEncoding;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pfb.PfbParser;
+
+/**
+ * This is implementation of the Type1 Font
+ * with a afm and a pfb file.
+ *
+ * @author <a href="mailto:m.g.n@gmx.de">Michael Niedermair</a>
+ * @version $Revision: 1.3 $
+ */
+public class PDType1AfmPfbFont extends PDType1Font
+{
+ /**
+ * the buffersize.
+ */
+ private static final int BUFFERSIZE = 0xffff;
+
+ /**
+ * The font descriptor.
+ */
+ private PDFontDescriptorDictionary fd;
+
+ /**
+ * the font metric.
+ */
+ private FontMetric metric;
+
+ /**
+ * Create a new object.
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afmname The font filename.
+ * @throws IOException If there is an error loading the data.
+ */
+ public PDType1AfmPfbFont(final PDDocument doc, final String afmname)
+ throws IOException
+ {
+
+ super();
+
+ InputStream afmin = new BufferedInputStream(
+ new FileInputStream(afmname), BUFFERSIZE);
+ String pfbname = afmname.replaceAll(".AFM", "").replaceAll(".afm", "")
+ + ".pfb";
+ InputStream pfbin = new BufferedInputStream(
+ new FileInputStream(pfbname), BUFFERSIZE);
+
+ load(doc, afmin, pfbin);
+ }
+
+ /**
+ * Create a new object.
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afm The afm input.
+ * @param pfb The pfb input.
+ * @throws IOException If there is an error loading the data.
+ */
+ public PDType1AfmPfbFont(final PDDocument doc, final InputStream afm, final InputStream pfb)
+ throws IOException
+ {
+ super();
+
+ load(doc, afm, pfb);
+ }
+
+ /**
+ * This will load a afm and pfb to be embedding into a document.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afm The afm input.
+ * @param pfb The pfb input.
+ * @throws IOException If there is an error loading the data.
+ */
+ private void load(final PDDocument doc, final InputStream afm,
+ final InputStream pfb) throws IOException
+ {
+
+ fd = new PDFontDescriptorDictionary();
+ setFontDescriptor(fd);
+
+ // read the pfb
+ PfbParser pfbparser = new PfbParser(pfb);
+ pfb.close();
+
+ PDStream fontStream = new PDStream(doc, pfbparser.getInputStream(),
+ false);
+ fontStream.getStream().setInt("Length", pfbparser.size());
+ for (int i = 0; i < pfbparser.getLengths().length; i++)
+ {
+ fontStream.getStream().setInt("Length" + (i + 1),
+ pfbparser.getLengths()[i]);
+ }
+ fontStream.addCompression();
+ fd.setFontFile(fontStream);
+
+ // read the afm
+ AFMParser parser = new AFMParser(afm);
+ parser.parse();
+ metric = parser.getResult();
+ setEncoding(new AFMEncoding(metric));
+
+ // set the values
+ setBaseFont(metric.getFontName());
+ fd.setFontName(metric.getFontName());
+ fd.setFontFamily(metric.getFamilyName());
+ fd.setNonSymbolic(true);
+ fd.setFontBoundingBox(new PDRectangle(metric.getFontBBox()));
+ fd.setItalicAngle(metric.getItalicAngle());
+ fd.setAscent(metric.getAscender());
+ fd.setDescent(metric.getDescender());
+ fd.setCapHeight(metric.getCapHeight());
+ fd.setXHeight(metric.getXHeight());
+ fd.setAverageWidth(metric.getAverageCharacterWidth());
+ fd.setCharacterSet(metric.getCharacterSet());
+
+ // get firstchar, lastchar
+ int firstchar = 255;
+ int lastchar = 0;
+
+ // widths
+ List listmetric = metric.getCharMetrics();
+
+ int maxWidths = 256;
+ List widths = new ArrayList(maxWidths);
+ Integer zero = new Integer(0);
+ Iterator iter = listmetric.iterator();
+ while (iter.hasNext())
+ {
+ CharMetric m = (CharMetric) iter.next();
+ int n = m.getCharacterCode();
+ if (n > 0)
+ {
+ firstchar = Math.min(firstchar, n);
+ lastchar = Math.max(lastchar, n);
+ if (m.getWx() > 0)
+ {
+ float width = m.getWx();
+ widths.add(new Float(width));
+ }
+ else
+ {
+ widths.add(zero);
+ }
+ }
+ }
+ setFirstChar(firstchar);
+ setLastChar(lastchar);
+ setWidths(widths);
+
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.font.PDSimpleFont#getFontDescriptor()
+ */
+ public PDFontDescriptor getFontDescriptor() throws IOException
+ {
+ return fd;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java
new file mode 100644
index 0000000..891f7c9
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java
@@ -0,0 +1,267 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is implementation of the Type1 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.10 $
+ */
+public class PDType1Font extends PDSimpleFont
+{
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_ROMAN = new PDType1Font( "Times-Roman" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_BOLD = new PDType1Font( "Times-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_ITALIC = new PDType1Font( "Times-Italic" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font( "Times-BoldItalic" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA = new PDType1Font( "Helvetica" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_BOLD = new PDType1Font( "Helvetica-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font( "Helvetica-Oblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font( "Helvetica-BoldOblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER = new PDType1Font( "Courier" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_BOLD = new PDType1Font( "Courier-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_OBLIQUE = new PDType1Font( "Courier-Oblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font( "Courier-BoldOblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font SYMBOL = new PDType1Font( "Symbol" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font ZAPF_DINGBATS = new PDType1Font( "ZapfDingbats" );
+
+
+ private static final Map STANDARD_14 = new HashMap();
+ static
+ {
+ STANDARD_14.put( TIMES_ROMAN.getBaseFont(), TIMES_ROMAN );
+ STANDARD_14.put( TIMES_BOLD.getBaseFont(), TIMES_BOLD );
+ STANDARD_14.put( TIMES_ITALIC.getBaseFont(), TIMES_ITALIC );
+ STANDARD_14.put( TIMES_BOLD_ITALIC.getBaseFont(), TIMES_BOLD_ITALIC );
+ STANDARD_14.put( HELVETICA.getBaseFont(), HELVETICA );
+ STANDARD_14.put( HELVETICA_BOLD.getBaseFont(), HELVETICA_BOLD );
+ STANDARD_14.put( HELVETICA_OBLIQUE.getBaseFont(), HELVETICA_OBLIQUE );
+ STANDARD_14.put( HELVETICA_BOLD_OBLIQUE.getBaseFont(), HELVETICA_BOLD_OBLIQUE );
+ STANDARD_14.put( COURIER.getBaseFont(), COURIER );
+ STANDARD_14.put( COURIER_BOLD.getBaseFont(), COURIER_BOLD );
+ STANDARD_14.put( COURIER_OBLIQUE.getBaseFont(), COURIER_OBLIQUE );
+ STANDARD_14.put( COURIER_BOLD_OBLIQUE.getBaseFont(), COURIER_BOLD_OBLIQUE );
+ STANDARD_14.put( SYMBOL.getBaseFont(), SYMBOL );
+ STANDARD_14.put( ZAPF_DINGBATS.getBaseFont(), ZAPF_DINGBATS );
+ }
+
+ private Font awtFont = null;
+
+ /**
+ * Constructor.
+ */
+ public PDType1Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type1" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType1Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFont The base font for this font.
+ */
+ public PDType1Font( String baseFont )
+ {
+ this();
+ setBaseFont( baseFont );
+ }
+
+ /**
+ * A convenience method to get one of the standard 14 font from name.
+ *
+ * @param name The name of the font to get.
+ *
+ * @return The font that matches the name or null if it does not exist.
+ */
+ public static PDType1Font getStandardFont( String name )
+ {
+ return (PDType1Font)STANDARD_14.get( name );
+ }
+
+ /**
+ * This will get the names of the standard 14 fonts.
+ *
+ * @return An array of the names of the standard 14 fonts.
+ */
+ public static String[] getStandard14Names()
+ {
+ return (String[])STANDARD_14.keySet().toArray( new String[14] );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ if( awtFont == null )
+ {
+ String baseFont = this.getBaseFont();
+ if( baseFont.equals( TIMES_ROMAN.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( TIMES_ITALIC.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( TIMES_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( TIMES_BOLD_ITALIC.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( HELVETICA.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_BOLD_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( COURIER.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( COURIER_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( COURIER_BOLD_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( COURIER_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( SYMBOL.getBaseFont() ) )
+ {
+ awtFont = new Font( "Symbol", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( ZAPF_DINGBATS.getBaseFont() ) )
+ {
+ awtFont = new Font( "ZapfDingbats", Font.PLAIN, 1 );
+ }
+ else
+ {
+ awtFont = new Font( "Arial", Font.PLAIN, 1 );
+ //throw new IOException( "Not yet implemented:" + getClass().getName() + " " +
+ //this.getBaseFont() +
+ //" " + this + " " + TIMES_ROMAN );
+ }
+ }
+ AffineTransform at = new AffineTransform();
+ at.scale( xScale, yScale );
+
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+ g2d.setFont( awtFont.deriveFont( at ).deriveFont( fontSize ) );
+ //g2d.getFontRenderContext().getTransform().scale( xScale, yScale );
+
+ g2d.drawString( string, (int)x, (int)y );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java
new file mode 100644
index 0000000..5f9c363
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.apache.log4j.Logger;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.pdmodel.common.PDMatrix;
+
+import java.awt.Graphics;
+import java.awt.Image;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is implementation of the Type3 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.6 $
+ */
+public class PDType3Font extends PDSimpleFont
+{
+ private static Logger log = Logger.getLogger( PDType3Font.class );
+
+ //A map of character code to java.awt.Image for the glyph
+ private Map images = new HashMap();
+
+ /**
+ * Constructor.
+ */
+ public PDType3Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type3" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType3Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * Type3 fonts have their glyphs defined as a content stream. This
+ * will create the image that represents that character
+ *
+ * @throws IOException If there is an error creating the image.
+ */
+ private Image createImageIfNecessary( char character ) throws IOException
+ {
+ Character c = new Character( character );
+ Image retval = (Image)images.get( c );
+ if( retval == null )
+ {
+ COSDictionary charProcs = (COSDictionary)font.getDictionaryObject( COSName.getPDFName( "CharProcs" ) );
+ COSStream stream = (COSStream)charProcs.getDictionaryObject( COSName.getPDFName( "" + character ) );
+ if( stream != null )
+ {
+ Type3StreamParser parser = new Type3StreamParser();
+ retval = parser.createImage( stream );
+ images.put( c, retval );
+ }
+ else
+ {
+ log.warn( "Error font type 3 image stream is null" );
+ }
+ }
+ return retval;
+
+ }
+
+ /**
+ * This will draw a string on a canvas using the font.
+ *
+ * @param string The string to draw.
+ * @param g The graphics to draw onto.
+ * @param fontSize The size of the font to draw.
+ * @param x The x coordinate to draw at.
+ * @param y The y coordinate to draw at.
+ *
+ * @throws IOException If there is an error drawing the image on the screen.
+ */
+ public void drawString( String string, Graphics g, float fontSize, float x, float y ) throws IOException
+ {
+ //if( string.equals( "V" )|| string.equals( "o" ) )
+ {
+ for(int i=0; i<string.length(); i++)
+ {
+ //todo need to use image observers and such
+ char c = string.charAt( i );
+ Image image = createImageIfNecessary( c );
+ if( image != null )
+ {
+ int newWidth = (int)(.12*image.getWidth(null));
+ int newHeight = (int)(.12*image.getHeight(null));
+ if( newWidth > 0 && newHeight > 0 )
+ {
+ image = image.getScaledInstance( newWidth, newHeight, Image.SCALE_SMOOTH );
+ g.drawImage( image, (int)x, (int)y, null );
+ x+=newWidth;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the font matrix for this type3 font.
+ *
+ * @param matrix The font matrix for this type3 font.
+ */
+ public void setFontMatrix( PDMatrix matrix )
+ {
+ font.setItem( "FontMatrix", matrix );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java b/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java
new file mode 100644
index 0000000..a2adc1f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java
@@ -0,0 +1,607 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Image;
+
+import java.io.IOException;
+
+import java.util.List;
+
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.graphics.xobject.PDInlinedImage;
+
+import org.pdfbox.util.BoundingBox;
+import org.pdfbox.util.ImageParameters;
+import org.pdfbox.util.PDFOperator;
+import org.pdfbox.util.PDFStreamEngine;
+
+/**
+ * This class will handle creating an image for a type 3 glyph.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.8 $
+ */
+public class Type3StreamParser extends PDFStreamEngine
+{
+ private PDInlinedImage image = null;
+ private BoundingBox box = null;
+
+
+ /**
+ * This will parse a type3 stream and create an image from it.
+ *
+ * @param type3Stream The stream containing the operators to draw the image.
+ *
+ * @return The image that was created.
+ *
+ * @throws IOException If there is an error processing the stream.
+ */
+ public Image createImage( COSStream type3Stream ) throws IOException
+ {
+ processStream( null, null, type3Stream );
+ return image.createImage();
+ }
+
+ /**
+ * This is used to handle an operation.
+ *
+ * @param operator The operation to perform.
+ * @param arguments The list of arguments.
+ *
+ * @throws IOException If there is an error processing the operation.
+ */
+ protected void processOperator( PDFOperator operator, List arguments ) throws IOException
+ {
+ super.processOperator( operator, arguments );
+ String operation = operator.getOperation();
+ /**
+ if( operation.equals( "b" ) )
+ {
+ //Close, fill, and stroke path using nonzero winding number rule
+ }
+ else if( operation.equals( "B" ) )
+ {
+ //Fill and stroke path using nonzero winding number rule
+ }
+ else if( operation.equals( "b*" ) )
+ {
+ //Close, fill, and stroke path using even-odd rule
+ }
+ else if( operation.equals( "B*" ) )
+ {
+ //Fill and stroke path using even-odd rule
+ }
+ else if( operation.equals( "BDC" ) )
+ {
+ //(PDF 1.2) Begin marked-content sequence with property list
+ }
+ else **/if( operation.equals( "BI" ) )
+ {
+ ImageParameters params = operator.getImageParameters();
+ image = new PDInlinedImage();
+ image.setImageParameters( params );
+ image.setImageData( operator.getImageData() );
+ //begin inline image object
+ }/**
+ else if( operation.equals( "BMC" ) )
+ {
+ //(PDF 1.2) Begin marked-content sequence
+ }
+ else if( operation.equals( "BT" ) )
+ {
+ log.debug( "<BT>" );
+ textMatrix = new Matrix();
+ textLineMatrix = new Matrix();
+ }
+ else if( operation.equals( "BX" ) )
+ {
+ //(PDF 1.1) Begin compatibility section
+ }
+ else if( operation.equals( "c" ) )
+ {
+ //Append curved segment to path (three control points)
+ }
+ else if( operation.equals( "cm" ) )
+ {
+ }
+ else if( operation.equals( "cs" ) )
+ {
+ }
+ else if( operation.equals( "CS" ) )
+ {
+ }
+ else if( operation.equals( "d" ) )
+ {
+ //Set the line dash pattern in the graphics state
+ }
+ else */if( operation.equals( "d0" ) )
+ {
+ //set glyph with for a type3 font
+ //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+ //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+ //width = horizontalWidth.intValue();
+ //height = verticalWidth.intValue();
+ }
+ else if( operation.equals( "d1" ) )
+ {
+ //set glyph with and bounding box for type 3 font
+ //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+ //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+ COSNumber llx = (COSNumber)arguments.get( 2 );
+ COSNumber lly = (COSNumber)arguments.get( 3 );
+ COSNumber urx = (COSNumber)arguments.get( 4 );
+ COSNumber ury = (COSNumber)arguments.get( 5 );
+
+ //width = horizontalWidth.intValue();
+ //height = verticalWidth.intValue();
+ box = new BoundingBox();
+ box.setLowerLeftX( llx.floatValue() );
+ box.setLowerLeftY( lly.floatValue() );
+ box.setUpperRightX( urx.floatValue() );
+ box.setUpperRightY( ury.floatValue() );
+ }/*
+ else if( operation.equals( "Do" ) )
+ {
+ //invoke named object.
+ }
+ else if( operation.equals( "DP" ) )
+ {
+ //(PDF 1.2) De.ne marked-content point with property list
+ }
+ else if( operation.equals( "EI" ) )
+ {
+ //end inline image object
+ }
+ else if( operation.equals( "EMC" ) )
+ {
+ //End inline image object
+ }
+ else if( operation.equals( "ET" ) )
+ {
+ log.debug( "<ET>" );
+ textMatrix = null;
+ textLineMatrix = null;
+ }
+ else if( operation.equals( "EX" ) )
+ {
+ //(PDF 1.1) End compatibility section
+ }
+ else if( operation.equals( "f" ) )
+ {
+ //Fill the path, using the nonzero winding number rule to determine the region to .ll
+ }
+ else if( operation.equals( "F" ) )
+ {
+ }
+ else if( operation.equals( "f*" ) )
+ {
+ //Fill path using even-odd rule
+ }
+ else if( operation.equals( "g" ) )
+ {
+ }
+ else if( operation.equals( "G" ) )
+ {
+ }
+ else if( operation.equals( "gs" ) )
+ {
+ }
+ else if( operation.equals( "h" ) )
+ {
+ //close subpath
+ }
+ else if( operation.equals( "i" ) )
+ {
+ //set flatness tolerance, not sure what this does
+ }
+ else if( operation.equals( "ID" ) )
+ {
+ //begin inline image data
+ }
+ else if( operation.equals( "j" ) )
+ {
+ //Set the line join style in the graphics state
+ //System.out.println( "<j>" );
+ }
+ else if( operation.equals( "J" ) )
+ {
+ //Set the line cap style in the graphics state
+ //System.out.println( "<J>" );
+ }
+ else if( operation.equals( "k" ) )
+ {
+ //Set CMYK color for nonstroking operations
+ }
+ else if( operation.equals( "K" ) )
+ {
+ //Set CMYK color for stroking operations
+ }
+ else if( operation.equals( "l" ) )
+ {
+ //append straight line segment from the current point to the point.
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ linePath.lineTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
+ }
+ else if( operation.equals( "m" ) )
+ {
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ linePath.reset();
+ linePath.moveTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
+ //System.out.println( "<m x=\"" + x.getValue() + "\" y=\"" + y.getValue() + "\" >" );
+ }
+ else if( operation.equals( "M" ) )
+ {
+ //System.out.println( "<M>" );
+ }
+ else if( operation.equals( "MP" ) )
+ {
+ //(PDF 1.2) Define marked-content point
+ }
+ else if( operation.equals( "n" ) )
+ {
+ //End path without .lling or stroking
+ //System.out.println( "<n>" );
+ }
+ else if( operation.equals( "q" ) )
+ {
+ //save graphics state
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "<" + operation + "> - save state" );
+ }
+ graphicsStack.push(graphicsState.clone());
+ }
+ else if( operation.equals( "Q" ) )
+ {
+ //restore graphics state
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "<" + operation + "> - restore state" );
+ }
+ graphicsState = (PDGraphicsState)graphicsStack.pop();
+ }
+ else if( operation.equals( "re" ) )
+ {
+ }
+ else if( operation.equals( "rg" ) )
+ {
+ //Set RGB color for nonstroking operations
+ }
+ else if( operation.equals( "RG" ) )
+ {
+ //Set RGB color for stroking operations
+ }
+ else if( operation.equals( "ri" ) )
+ {
+ //Set color rendering intent
+ }
+ else if( operation.equals( "s" ) )
+ {
+ //Close and stroke path
+ }
+ else if( operation.equals( "S" ) )
+ {
+ graphics.draw( linePath );
+ }
+ else if( operation.equals( "sc" ) )
+ {
+ //set color for nonstroking operations
+ //System.out.println( "<sc>" );
+ }
+ else if( operation.equals( "SC" ) )
+ {
+ //set color for stroking operations
+ //System.out.println( "<SC>" );
+ }
+ else if( operation.equals( "scn" ) )
+ {
+ //set color for nonstroking operations special
+ }
+ else if( operation.equals( "SCN" ) )
+ {
+ //set color for stroking operations special
+ }
+ else if( operation.equals( "sh" ) )
+ {
+ //(PDF 1.3) Paint area de.ned by shading pattern
+ }
+ else if( operation.equals( "T*" ) )
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("<T* graphicsState.getTextState().getLeading()=\"" +
+ graphicsState.getTextState().getLeading() + "\">");
+ }
+ //move to start of next text line
+ if( graphicsState.getTextState().getLeading() == 0 )
+ {
+ graphicsState.getTextState().setLeading( -.01f );
+ }
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "Tc" ) )
+ {
+ //set character spacing
+ COSNumber characterSpacing = (COSNumber)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tc characterSpacing=\"" + characterSpacing.floatValue() + "\" />");
+ }
+ graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
+ }
+ else if( operation.equals( "Td" ) )
+ {
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Td x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
+ }
+ Matrix td = new Matrix();
+ td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
+ td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
+ //log.debug( "textLineMatrix before " + textLineMatrix );
+ textLineMatrix = textLineMatrix.multiply( td );
+ //log.debug( "textLineMatrix after " + textLineMatrix );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "TD" ) )
+ {
+ //move text position and set leading
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TD x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
+ }
+ graphicsState.getTextState().setLeading( -1 * y.floatValue() );
+ Matrix td = new Matrix();
+ td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
+ td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
+ //log.debug( "textLineMatrix before " + textLineMatrix );
+ textLineMatrix = textLineMatrix.multiply( td );
+ //log.debug( "textLineMatrix after " + textLineMatrix );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "Tf" ) )
+ {
+ //set font and size
+ COSName fontName = (COSName)arguments.get( 0 );
+ graphicsState.getTextState().setFontSize( ((COSNumber)arguments.get( 1 ) ).floatValue() );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tf font=\"" + fontName.getName() + "\" size=\"" +
+ graphicsState.getTextState().getFontSize() + "\">");
+ }
+
+ //old way
+ //graphicsState.getTextState().getFont() = (COSObject)stream.getDictionaryObject( fontName );
+ //if( graphicsState.getTextState().getFont() == null )
+ //{
+ // graphicsState.getTextState().getFont() = (COSObject)graphicsState.getTextState().getFont()
+ // Dictionary.getItem( fontName );
+ //}
+ graphicsState.getTextState().setFont( (PDFont)fonts.get( fontName.getName() ) );
+ if( graphicsState.getTextState().getFont() == null )
+ {
+ throw new IOException( "Error: Could not find font(" + fontName + ") in map=" + fonts );
+ }
+ //log.debug( "Font Resource=" + fontResource );
+ //log.debug( "Current Font=" + graphicsState.getTextState().getFont() );
+ //log.debug( "graphicsState.getTextState().getFontSize()=" + graphicsState.getTextState().getFontSize() );
+ }
+ else if( operation.equals( "Tj" ) )
+ {
+ COSString string = (COSString)arguments.get( 0 );
+ TextPosition pos = showString( string.getBytes() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tj string=\"" + string.getString() + "\">");
+ }
+ }
+ else if( operation.equals( "TJ" ) )
+ {
+ Matrix td = new Matrix();
+
+ COSArray array = (COSArray)arguments.get( 0 );
+ for( int i=0; i<array.size(); i++ )
+ {
+ COSBase next = array.get( i );
+ if( next instanceof COSNumber )
+ {
+ float value = -1*
+ (((COSNumber)next).floatValue()/1000) *
+ graphicsState.getTextState().getFontSize() *
+ textMatrix.getValue(1,1);
+
+ if (log.isDebugEnabled())
+ {
+ log.debug( "<TJ(" + i + ") value=\"" + value +
+ "\", param=\"" + ((COSNumber)next).floatValue() +
+ "\", fontsize=\"" + graphicsState.getTextState().getFontSize() + "\">" );
+ }
+ td.setValue( 2, 0, value );
+ textMatrix = textMatrix.multiply( td );
+ }
+ else if( next instanceof COSString )
+ {
+ TextPosition pos = showString( ((COSString)next).getBytes() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TJ(" + i + ") string=\"" + pos.getString() + "\">");
+ }
+ }
+ else
+ {
+ throw new IOException( "Unknown type in array for TJ operation:" + next );
+ }
+ }
+ }
+ else if( operation.equals( "TL" ) )
+ {
+ COSNumber leading = (COSNumber)arguments.get( 0 );
+ graphicsState.getTextState().setLeading( leading.floatValue() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TL leading=\"" + leading.floatValue() + "\" >");
+ }
+ }
+ else if( operation.equals( "Tm" ) )
+ {
+ //Set text matrix and text line matrix
+ COSNumber a = (COSNumber)arguments.get( 0 );
+ COSNumber b = (COSNumber)arguments.get( 1 );
+ COSNumber c = (COSNumber)arguments.get( 2 );
+ COSNumber d = (COSNumber)arguments.get( 3 );
+ COSNumber e = (COSNumber)arguments.get( 4 );
+ COSNumber f = (COSNumber)arguments.get( 5 );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tm " +
+ "a=\"" + a.floatValue() + "\" " +
+ "b=\"" + b.floatValue() + "\" " +
+ "c=\"" + c.floatValue() + "\" " +
+ "d=\"" + d.floatValue() + "\" " +
+ "e=\"" + e.floatValue() + "\" " +
+ "f=\"" + f.floatValue() + "\" >");
+ }
+
+ textMatrix = new Matrix();
+ textMatrix.setValue( 0, 0, a.floatValue() );
+ textMatrix.setValue( 0, 1, b.floatValue() );
+ textMatrix.setValue( 1, 0, c.floatValue() );
+ textMatrix.setValue( 1, 1, d.floatValue() );
+ textMatrix.setValue( 2, 0, e.floatValue() );
+ textMatrix.setValue( 2, 1, f.floatValue() );
+ textLineMatrix = textMatrix.copy();
+ }
+ else if( operation.equals( "Tr" ) )
+ {
+ //Set text rendering mode
+ //System.out.println( "<Tr>" );
+ }
+ else if( operation.equals( "Ts" ) )
+ {
+ //Set text rise
+ //System.out.println( "<Ts>" );
+ }
+ else if( operation.equals( "Tw" ) )
+ {
+ //set word spacing
+ COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tw wordSpacing=\"" + wordSpacing.floatValue() + "\" />");
+ }
+ graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
+ }
+ else if( operation.equals( "Tz" ) )
+ {
+ //Set horizontal text scaling
+ }
+ else if( operation.equals( "v" ) )
+ {
+ //Append curved segment to path (initial point replicated)
+ }
+ else if( operation.equals( "w" ) )
+ {
+ //Set the line width in the graphics state
+ //System.out.println( "<w>" );
+ }
+ else if( operation.equals( "W" ) )
+ {
+ //Set clipping path using nonzero winding number rule
+ //System.out.println( "<W>" );
+ }
+ else if( operation.equals( "W*" ) )
+ {
+ //Set clipping path using even-odd rule
+ }
+ else if( operation.equals( "y" ) )
+ {
+ //Append curved segment to path (final point replicated)
+ }
+ else if( operation.equals( "'" ) )
+ {
+ // Move to start of next text line, and show text
+ //
+ COSString string = (COSString)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<' string=\"" + string.getString() + "\">");
+ }
+
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+
+ showString( string.getBytes() );
+ }
+ else if( operation.equals( "\"" ) )
+ {
+ //Set word and character spacing, move to next line, and show text
+ //
+ COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
+ COSNumber characterSpacing = (COSNumber)arguments.get( 1 );
+ COSString string = (COSString)arguments.get( 2 );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<\" wordSpacing=\"" + wordSpacing +
+ "\", characterSpacing=\"" + characterSpacing +
+ "\", string=\"" + string.getString() + "\">");
+ }
+
+ graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
+ graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
+
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+
+ showString( string.getBytes() );
+ }*/
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/package.html b/src/main/java/org/pdfbox/pdmodel/font/package.html
new file mode 100644
index 0000000..4e8d27e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+Classes to deal with font functionality in a PDF Document.
+</body>
+</html>