KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > pdmodel > font > PDTrueTypeFont


1 /**
2  * Copyright (c) 2003-2006, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.pdmodel.font;
32
33 import org.fontbox.ttf.CMAPEncodingEntry;
34 import org.fontbox.ttf.CMAPTable;
35 import org.fontbox.ttf.GlyphData;
36 import org.fontbox.ttf.GlyphTable;
37 import org.fontbox.ttf.HeaderTable;
38 import org.fontbox.ttf.HorizontalHeaderTable;
39 import org.fontbox.ttf.HorizontalMetricsTable;
40 import org.fontbox.ttf.NamingTable;
41 import org.fontbox.ttf.NameRecord;
42 import org.fontbox.ttf.OS2WindowsMetricsTable;
43 import org.fontbox.ttf.PostScriptTable;
44 import org.fontbox.ttf.TTFParser;
45 import org.fontbox.ttf.TrueTypeFont;
46
47 import org.pdfbox.cos.COSDictionary;
48 import org.pdfbox.cos.COSName;
49
50 import org.pdfbox.pdmodel.PDDocument;
51
52 import org.pdfbox.pdmodel.common.PDRectangle;
53 import org.pdfbox.pdmodel.common.PDStream;
54
55 import org.pdfbox.encoding.WinAnsiEncoding;
56 import org.pdfbox.exceptions.WrappedIOException;
57
58 import org.pdfbox.util.ResourceLoader;
59
60 import java.awt.Font JavaDoc;
61 import java.awt.FontFormatException JavaDoc;
62 import java.awt.Graphics JavaDoc;
63 import java.awt.Graphics2D JavaDoc;
64 import java.awt.RenderingHints JavaDoc;
65 import java.awt.geom.AffineTransform JavaDoc;
66
67 import java.util.ArrayList JavaDoc;
68 import java.util.HashMap JavaDoc;
69 import java.util.List JavaDoc;
70 import java.util.Map JavaDoc;
71 import java.util.Properties JavaDoc;
72
73 import java.io.File JavaDoc;
74 import java.io.FileInputStream JavaDoc;
75 import java.io.IOException JavaDoc;
76 import java.io.InputStream JavaDoc;
77
78 /**
79  * This is the TrueType implementation of fonts.
80  *
81  * @author <a HREF="mailto:ben@benlitchfield.com">Ben Litchfield</a>
82  * @version $Revision: 1.17 $
83  */

84 public class PDTrueTypeFont extends PDSimpleFont
85 {
86     /**
87      * This is the key to a property in the Resources/PDFBox_External_Fonts.properties file
88      * to load a Font when a mapping does not exist for the current font.
89      */

90     public static final String JavaDoc UNKNOWN_FONT = "UNKNOWN_FONT";
91     
92     private Font awtFont = null;
93     
94     private static Properties JavaDoc externalFonts = new Properties JavaDoc();
95     private static Map JavaDoc loadedExternalFonts = new HashMap JavaDoc();
96     
97     static
98     {
99         try
100         {
101             ResourceLoader.loadProperties( "Resources/PDFBox_External_Fonts.properties", externalFonts );
102         }
103         catch( IOException io )
104         {
105             io.printStackTrace();
106             throw new RuntimeException JavaDoc( "Error loading font resources" );
107         }
108     }
109     
110     
111     /**
112      * Constructor.
113      */

114     public PDTrueTypeFont()
115     {
116         super();
117         font.setItem( COSName.SUBTYPE, COSName.TRUE_TYPE );
118     }
119
120     /**
121      * Constructor.
122      *
123      * @param fontDictionary The font dictionary according to the PDF specification.
124      */

125     public PDTrueTypeFont( COSDictionary fontDictionary )
126     {
127         super( fontDictionary );
128     }
129     
130     /**
131      * This will load a TTF font from a font file.
132      *
133      * @param doc The PDF document that will hold the embedded font.
134      * @param file The file on the filesystem that holds the font file.
135      * @return A true type font.
136      * @throws IOException If there is an error loading the file data.
137      */

138     public static PDTrueTypeFont loadTTF( PDDocument doc, String JavaDoc file ) throws IOException
139     {
140         return loadTTF( doc, new File JavaDoc( file ) );
141     }
142     
143     /**
144      * This will load a TTF to be embedding into a document.
145      *
146      * @param doc The PDF document that will hold the embedded font.
147      * @param file A TTF file stream.
148      * @return A PDF TTF.
149      * @throws IOException If there is an error loading the data.
150      */

151     public static PDTrueTypeFont loadTTF( PDDocument doc, File JavaDoc file ) throws IOException
152     {
153         PDTrueTypeFont retval = new PDTrueTypeFont();
154         PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
155         PDStream fontStream = new PDStream(doc, new FileInputStream JavaDoc( file ), false );
156         fontStream.getStream().setInt( COSName.LENGTH1, (int)file.length() );
157         fontStream.addCompression();
158         fd.setFontFile2( fontStream );
159         retval.setFontDescriptor( fd );
160         //only support winansi encoding right now, should really
161
//just use Identity-H with unicode mapping
162
retval.setEncoding( new WinAnsiEncoding() );
163         TrueTypeFont ttf = null;
164         try
165         {
166             TTFParser parser = new TTFParser();
167             ttf = parser.parseTTF( file );
168             NamingTable naming = ttf.getNaming();
169             List JavaDoc records = naming.getNameRecords();
170             for( int i=0; i<records.size(); i++ )
171             {
172                 NameRecord nr = (NameRecord)records.get( i );
173                 if( nr.getNameId() == NameRecord.NAME_POSTSCRIPT_NAME )
174                 {
175                     retval.setBaseFont( nr.getString() );
176                     fd.setFontName( nr.getString() );
177                 }
178                 else if( nr.getNameId() == NameRecord.NAME_FONT_FAMILY_NAME )
179                 {
180                     fd.setFontFamily( nr.getString() );
181                 }
182             }
183             
184             OS2WindowsMetricsTable os2 = ttf.getOS2Windows();
185             fd.setNonSymbolic( true );
186             switch( os2.getFamilyClass() )
187             {
188                 case OS2WindowsMetricsTable.FAMILY_CLASS_SYMBOLIC:
189                     fd.setSymbolic( true );
190                     fd.setNonSymbolic( false );
191                     break;
192                 case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS:
193                     fd.setScript( true );
194                     break;
195                 case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS:
196                 case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS:
197                 case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS:
198                 case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS:
199                 case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS:
200                     fd.setSerif( true );
201                     break;
202                 default:
203                     //do nothing
204
}
205             switch( os2.getWidthClass() )
206             {
207                 case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_CONDENSED:
208                     fd.setFontStretch( "UltraCondensed" );
209                     break;
210                 case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_CONDENSED:
211                     fd.setFontStretch( "ExtraCondensed" );
212                     break;
213                 case OS2WindowsMetricsTable.WIDTH_CLASS_CONDENSED:
214                     fd.setFontStretch( "Condensed" );
215                     break;
216                 case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_CONDENSED:
217                     fd.setFontStretch( "SemiCondensed" );
218                     break;
219                 case OS2WindowsMetricsTable.WIDTH_CLASS_MEDIUM:
220                     fd.setFontStretch( "Normal" );
221                     break;
222                 case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_EXPANDED:
223                     fd.setFontStretch( "SemiExpanded" );
224                     break;
225                 case OS2WindowsMetricsTable.WIDTH_CLASS_EXPANDED:
226                     fd.setFontStretch( "Expanded" );
227                     break;
228                 case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_EXPANDED:
229                     fd.setFontStretch( "ExtraExpanded" );
230                     break;
231                 case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_EXPANDED:
232                     fd.setFontStretch( "UltraExpanded" );
233                     break;
234                 default:
235                     //do nothing
236
}
237             fd.setFontWeight( os2.getWeightClass() );
238             
239             //todo retval.setFixedPitch
240
//todo retval.setNonSymbolic
241
//todo retval.setItalic
242
//todo retval.setAllCap
243
//todo retval.setSmallCap
244
//todo retval.setForceBold
245

246             HeaderTable header = ttf.getHeader();
247             PDRectangle rect = new PDRectangle();
248             rect.setLowerLeftX( header.getXMin() * 1000f/header.getUnitsPerEm() );
249             rect.setLowerLeftY( header.getYMin() * 1000f/header.getUnitsPerEm() );
250             rect.setUpperRightX( header.getXMax() * 1000f/header.getUnitsPerEm() );
251             rect.setUpperRightY( header.getYMax() * 1000f/header.getUnitsPerEm() );
252             fd.setFontBoundingBox( rect );
253             
254             HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
255             fd.setAscent( hHeader.getAscender() * 1000f/header.getUnitsPerEm() );
256             fd.setDescent( hHeader.getDescender() * 1000f/header.getUnitsPerEm() );
257             
258             GlyphTable glyphTable = ttf.getGlyph();
259             GlyphData[] glyphs = glyphTable.getGlyphs();
260             
261             PostScriptTable ps = ttf.getPostScript();
262             fd.setFixedPitch( ps.getIsFixedPitch() > 0 );
263             fd.setItalicAngle( ps.getItalicAngle() );
264             
265             String JavaDoc[] names = ps.getGlyphNames();
266             if( names != null )
267             {
268                 for( int i=0; i<names.length; i++ )
269                 {
270                     //if we have a capital H then use that, otherwise use the
271
//tallest letter
272
if( names[i].equals( "H" ) )
273                     {
274                         fd.setCapHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/
275                                          header.getUnitsPerEm() );
276                     }
277                     if( names[i].equals( "x" ) )
278                     {
279                         fd.setXHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/header.getUnitsPerEm() );
280                     }
281                 }
282             }
283             
284             //hmm there does not seem to be a clear definition for StemV,
285
//this is close enough and I am told it doesn't usually get used.
286
fd.setStemV( (fd.getFontBoundingBox().getWidth() * .13f) );
287             
288
289             CMAPTable cmapTable = ttf.getCMAP();
290             CMAPEncodingEntry[] cmaps = cmapTable.getCmaps();
291             int[] glyphToCCode = null;
292             for( int i=0; i<cmaps.length; i++ )
293             {
294                 if( cmaps[i].getPlatformId() == CMAPTable.PLATFORM_WINDOWS &&
295                     cmaps[i].getPlatformEncodingId() == CMAPTable.ENCODING_UNICODE )
296                 {
297                     glyphToCCode = cmaps[i].getGlyphIdToCharacterCode();
298                 }
299             }
300             int firstChar = 0;
301             /**
302             for( int i=0; i<glyphToCCode.length; i++ )
303             {
304                 if( glyphToCCode[i] != 0 )
305                 {
306                     firstChar = Math.min( glyphToCCode[i], firstChar );
307                 }
308             }*/

309             
310             int maxWidths=256;
311             HorizontalMetricsTable hMet = ttf.getHorizontalMetrics();
312             int[] widthValues = hMet.getAdvanceWidth();
313             List JavaDoc widths = new ArrayList JavaDoc( widthValues.length );
314             Integer JavaDoc zero = new Integer JavaDoc( 250 );
315             for( int i=0; i<widthValues.length && i<maxWidths; i++ )
316             {
317                 widths.add( zero );
318             }
319             for( int i=0; i<widthValues.length; i++ )
320             {
321                 if(glyphToCCode[i]-firstChar < widths.size() &&
322                    glyphToCCode[i]-firstChar >= 0 &&
323                    widths.get( glyphToCCode[i]-firstChar) == zero )
324                 {
325                     widths.set( glyphToCCode[i]-firstChar,
326                         new Integer JavaDoc( (int)(widthValues[i]* 1000f)/header.getUnitsPerEm() ) );
327                 }
328             }
329             retval.setWidths( widths );
330
331             retval.setFirstChar( firstChar );
332             retval.setLastChar( firstChar + widths.size()-1 );
333
334         }
335         finally
336         {
337             if( ttf != null )
338             {
339                 ttf.close();
340             }
341         }
342         
343         return retval;
344     }
345
346     /**
347      * {@inheritDoc}
348      */

349     public void drawString( String JavaDoc string, Graphics JavaDoc g, float fontSize,
350         float xScale, float yScale, float x, float y ) throws IOException
351     {
352         PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary)getFontDescriptor();
353         if( awtFont == null )
354         {
355             try
356             {
357                 PDStream ff2Stream = fd.getFontFile2();
358                 String JavaDoc fontName = fd.getFontName();
359                 if( ff2Stream != null )
360                 {
361                     awtFont = Font.createFont( Font.TRUETYPE_FONT, ff2Stream.createInputStream() );
362                 }
363                 else
364                 {
365                     //throw new IOException( "Error:TTF Stream is null");
366
// Embedded true type programs are optional,
367
// if there is no stream, we must use an external
368
// file.
369
TrueTypeFont ttf = getExternalFontFile2( fd );
370                     if( ttf != null )
371                     {
372                         awtFont = Font.createFont( Font.TRUETYPE_FONT, ttf.getOriginalData() );
373                     }
374                     else
375                     {
376                         awtFont = Font.getFont( fontName, null );
377                     }
378                 }
379             }
380             catch( FontFormatException JavaDoc f )
381             {
382                 throw new WrappedIOException( f );
383             }
384         }
385         AffineTransform JavaDoc at = new AffineTransform JavaDoc();
386         at.scale( xScale, yScale );
387         Graphics2D JavaDoc g2d = (Graphics2D JavaDoc)g;
388         g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
389         g2d.setFont( awtFont.deriveFont( at ).deriveFont( fontSize ) );
390         g2d.drawString( string, (int)x, (int)y );
391     }
392     
393     /**
394      * Permit to load an external TTF Font program file
395      *
396      * Created by Pascal Allain
397      * Vertical7 Inc.
398      *
399      * @param fd The font descriptor currently used
400      *
401      * @return A PDStream with the Font File program, null if fd is null
402      *
403      * @throws IOException If the font is not found
404      */

405     private TrueTypeFont getExternalFontFile2(PDFontDescriptorDictionary fd)
406         throws IOException
407     {
408         TrueTypeFont retval = null;
409         
410         if ( fd != null )
411         {
412             String JavaDoc baseFont = getBaseFont();
413             String JavaDoc fontResource = externalFonts.getProperty( UNKNOWN_FONT );
414             if( (baseFont != null) &&
415                  (externalFonts.containsKey(baseFont)) )
416             {
417                 fontResource = externalFonts.getProperty(baseFont);
418             }
419             if( fontResource != null )
420             {
421                 retval = (TrueTypeFont)loadedExternalFonts.get( baseFont );
422                 if( retval == null )
423                 {
424                     TTFParser ttfParser = new TTFParser();
425                     InputStream JavaDoc fontStream = ResourceLoader.loadResource( fontResource );
426                     if( fontStream == null )
427                     {
428                         throw new IOException( "Error missing font resource '" + externalFonts.get(baseFont) + "'" );
429                     }
430                     retval = ttfParser.parseTTF( fontStream );
431                     loadedExternalFonts.put( baseFont, retval );
432                 }
433             }
434         }
435         
436         return retval;
437     }
438 }
Popular Tags