You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2012/07/03 20:42:35 UTC
svn commit: r1356866 -
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Author: lehmi
Date: Tue Jul 3 18:42:34 2012
New Revision: 1356866
URL: http://svn.apache.org/viewvc?rev=1356866&view=rev
Log:
PDFBOX-954: fixed calculation of witdh values as proposed by Wolfgang Glas
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1356866&r1=1356865&r2=1356866&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Tue Jul 3 18:42:34 2012
@@ -16,6 +16,20 @@
*/
package org.apache.pdfbox.pdmodel.font;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fontbox.ttf.CMAPEncodingEntry;
@@ -25,35 +39,21 @@ import org.apache.fontbox.ttf.GlyphTable
import org.apache.fontbox.ttf.HeaderTable;
import org.apache.fontbox.ttf.HorizontalHeaderTable;
import org.apache.fontbox.ttf.HorizontalMetricsTable;
-import org.apache.fontbox.ttf.NamingTable;
import org.apache.fontbox.ttf.NameRecord;
+import org.apache.fontbox.ttf.NamingTable;
import org.apache.fontbox.ttf.OS2WindowsMetricsTable;
import org.apache.fontbox.ttf.PostScriptTable;
import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeFont;
-
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.encoding.WinAnsiEncoding;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
-import org.apache.pdfbox.encoding.WinAnsiEncoding;
import org.apache.pdfbox.util.ResourceLoader;
-import java.awt.Font;
-import java.awt.FontFormatException;
-
-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.
*
@@ -152,15 +152,47 @@ public class PDTrueTypeFont extends PDSi
*/
public static PDTrueTypeFont loadTTF( PDDocument doc, InputStream stream ) throws IOException
{
- PDTrueTypeFont retval = new PDTrueTypeFont();
- PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
- retval.setFontDescriptor( fd );
+ return PDTrueTypeFont.loadTTF(doc,stream,new WinAnsiEncoding());
+ }
+
+ /**
+ * This will load a TTF to be embedded into a document.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param stream a ttf input stream.
+ * @param enc The font encoding.
+ * @return a PDTrueTypeFont instance.
+ * @throws IOException If there is an error loading the data.
+ */
+ public static PDTrueTypeFont loadTTF( PDDocument doc, InputStream stream, Encoding enc ) throws IOException
+ {
PDStream fontStream = new PDStream(doc, stream, false );
fontStream.getStream().setInt( COSName.LENGTH1, fontStream.getByteArray().length );
fontStream.addCompression();
+ //only support winansi encoding right now, should really
+ //just use Identity-H with unicode mapping
+ return PDTrueTypeFont.loadTTF(fontStream,enc);
+ }
+
+ /**
+ * This will load a TTF to be embedded into a document.
+ *
+ * @param fontStream a ttf input stream.
+ * @param enc The font encoding.
+ * @return a PDTrueTypeFont instance.
+ * @throws IOException If there is an error loading the data.
+ */
+ public static PDTrueTypeFont loadTTF( PDStream fontStream, Encoding enc ) throws IOException
+ {
+ PDTrueTypeFont retval = new PDTrueTypeFont();
+ retval.setFontEncoding( enc );
+ retval.setEncoding(enc.getCOSObject());
+
+ PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
+ retval.setFontDescriptor( fd );
fd.setFontFile2( fontStream );
// As the stream was close within the PDStream constructor, we have to recreate it
- stream = fontStream.createInputStream();
+ InputStream stream = fontStream.createInputStream();
try
{
retval.loadDescriptorDictionary(fd, stream);
@@ -169,10 +201,6 @@ public class PDTrueTypeFont extends PDSi
{
stream.close();
}
- //only support winansi encoding right now, should really
- //just use Identity-H with unicode mapping
- retval.setFontEncoding( new WinAnsiEncoding() );
- retval.setEncoding(COSName.WIN_ANSI_ENCODING);
return retval;
}
@@ -285,15 +313,15 @@ public class PDTrueTypeFont extends PDSi
HeaderTable header = ttf.getHeader();
PDRectangle rect = new PDRectangle();
float scaling = 1000f/header.getUnitsPerEm();
- 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() );
+ rect.setLowerLeftX( header.getXMin() * scaling );
+ rect.setLowerLeftY( header.getYMin() * scaling );
+ rect.setUpperRightX( header.getXMax() * scaling );
+ rect.setUpperRightY( header.getYMax() * scaling );
fd.setFontBoundingBox( rect );
HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
- fd.setAscent( hHeader.getAscender() * 1000f/header.getUnitsPerEm() );
- fd.setDescent( hHeader.getDescender() * 1000f/header.getUnitsPerEm() );
+ fd.setAscent( hHeader.getAscender() * scaling );
+ fd.setDescent( hHeader.getDescender() * scaling );
GlyphTable glyphTable = ttf.getGlyph();
GlyphData[] glyphs = glyphTable.getGlyphs();
@@ -303,20 +331,20 @@ public class PDTrueTypeFont extends PDSi
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
+ //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() );
+ fd.setCapHeight( glyphs[i].getBoundingBox().getUpperRightY()/scaling );
}
if( names[i].equals( "x" ) )
{
- fd.setXHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/header.getUnitsPerEm() );
+ fd.setXHeight( glyphs[i].getBoundingBox().getUpperRightY()/scaling );
}
}
}
@@ -325,44 +353,62 @@ public class PDTrueTypeFont extends PDSi
//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;
+ CMAPEncodingEntry uniMap = null;
+
for( int i=0; i<cmaps.length; i++ )
{
if( cmaps[i].getPlatformId() == CMAPTable.PLATFORM_WINDOWS)
{
int platformEncoding = cmaps[i].getPlatformEncodingId();
- if ( (isSymbolic && CMAPTable.ENCODING_SYMBOL == platformEncoding)
- ||CMAPTable.ENCODING_UNICODE == platformEncoding )
+ if ( CMAPTable.ENCODING_UNICODE == platformEncoding )
{
- glyphToCCode = cmaps[i].getGlyphIdToCharacterCode();
+ uniMap = cmaps[i];
break;
}
}
}
- int firstChar = os2.getFirstCharIndex();
- int maxWidths = glyphToCCode.length;
+
+ Map<Integer, String> codeToName = this.getFontEncoding().getCodeToNameMap();
+
+ int firstChar = Collections.min(codeToName.keySet());
+ int lastChar = Collections.max(codeToName.keySet());
+
HorizontalMetricsTable hMet = ttf.getHorizontalMetrics();
int[] widthValues = hMet.getAdvanceWidth();
- List<Float> widths = new ArrayList<Float>(maxWidths);
- float zero = 250;
- for( int i=0; i<maxWidths; i++ )
+ int nWidths=lastChar-firstChar+1;
+ List<Float> widths = new ArrayList<Float>(nWidths);
+ // width of the .notdef character.
+ Float zero = Float.valueOf(widthValues[0]*scaling);
+ for( int i=0; i<nWidths; i++ )
{
widths.add( zero );
}
- for( int i=0; i<maxWidths; i++ )
- {
- if(glyphToCCode[i]-firstChar < widths.size() && glyphToCCode[i]-firstChar >= 0
- && widths.get( glyphToCCode[i]-firstChar) == zero )
+ // Encoding singleton to have acces to the chglyph name to
+ // unicode cpoint point mapping of Adobe's glyphlist.txt
+ Encoding glyphlist = WinAnsiEncoding.INSTANCE;
+
+ // A character code is mapped to a glyph name via the provided
+ // font encoding. Afterwards, the glyph name is translated to a
+ // glyph ID.
+ // For details, see PDFReference16.pdf, Section 5.5.5, p.401
+ //
+ for (Entry<Integer, String> e : codeToName.entrySet())
+ {
+ String name = e.getValue();
+ // pdf code to unicode by glyph list.
+ String c = glyphlist.getCharacter(name);
+ int charCode = c.codePointAt(0);
+ int gid = uniMap.getGlyphId(charCode);
+ if (gid != 0)
{
- widths.set( glyphToCCode[i]-firstChar, widthValues[i]*scaling );
+ widths.set( e.getKey().intValue()-firstChar,widthValues[gid]*scaling );
}
}
setWidths( widths );
- setFirstChar( isSymbolic ? 0 : firstChar );
- setLastChar( isSymbolic ? widths.size() : firstChar + widths.size()-1 );
+ setFirstChar( firstChar );
+ setLastChar( lastChar );
}
finally
{