Source Code Cross Referenced for NativeFont.java in  » PDF » PDF-Renderer » com » sun » pdfview » font » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » PDF Renderer » com.sun.pdfview.font 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: NativeFont.java,v 1.2 2007/12/20 18:33:31 rbair Exp $
003:         *
004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
006:         *
007:         * This library is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU Lesser General Public
009:         * License as published by the Free Software Foundation; either
010:         * version 2.1 of the License, or (at your option) any later version.
011:         * 
012:         * This library is distributed in the hope that it will be useful,
013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         * Lesser General Public License for more details.
016:         * 
017:         * You should have received a copy of the GNU Lesser General Public
018:         * License along with this library; if not, write to the Free Software
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020:         */
021:
022:        package com.sun.pdfview.font;
023:
024:        import java.awt.Font;
025:        import java.awt.FontFormatException;
026:        import java.awt.font.FontRenderContext;
027:        import java.awt.font.GlyphVector;
028:        import java.awt.font.OpenType;
029:        import java.awt.geom.AffineTransform;
030:        import java.awt.geom.GeneralPath;
031:        import java.io.ByteArrayInputStream;
032:        import java.io.IOException;
033:        import java.nio.ByteBuffer;
034:
035:        import com.sun.pdfview.PDFObject;
036:        import com.sun.pdfview.PDFParseException;
037:        import com.sun.pdfview.font.ttf.CMap;
038:        import com.sun.pdfview.font.ttf.CMapFormat0;
039:        import com.sun.pdfview.font.ttf.CMapFormat4;
040:        import com.sun.pdfview.font.ttf.CmapTable;
041:        import com.sun.pdfview.font.ttf.HeadTable;
042:        import com.sun.pdfview.font.ttf.HmtxTable;
043:        import com.sun.pdfview.font.ttf.NameTable;
044:        import com.sun.pdfview.font.ttf.PostTable;
045:        import com.sun.pdfview.font.ttf.TrueTypeFont;
046:        import com.sun.pdfview.font.ttf.TrueTypeTable;
047:
048:        /**
049:         * a font object derived from a true type font.
050:         *
051:         * @author Mike Wessler
052:         */
053:        public class NativeFont extends OutlineFont {
054:            /** Control characters to filter out of the underlying font */
055:            protected static final char[] controlChars = { 0x9, 0xa, 0xd };
056:
057:            /** the ids of our favorite CMaps */
058:            protected static final short[] mapIDs = { 3, 1, /* Microsoft Unicode */
059:            0, 0, /* unicode default */
060:            0, 3, /* unicode 2.0 map */
061:            1, 0 /* macintosh */
062:            };
063:
064:            /** the actual font in use */
065:            private Font f;
066:
067:            /** the font render context */
068:            private FontRenderContext basecontext = new FontRenderContext(
069:                    new AffineTransform(), true, true);
070:
071:            /** the cmap table from a TrueType font */
072:            private CmapTable cmapTable;
073:
074:            /** the post table from a TrueType font */
075:            private PostTable postTable;
076:
077:            /** the number of font units in one em */
078:            private int unitsPerEm;
079:
080:            /** the hmtx table from the TrueType font */
081:            private HmtxTable hmtxTable;
082:
083:            /**
084:             * create a new NativeFont object based on a description of the
085:             * font from the PDF file.  If the description happens to contain
086:             * an in-line true-type font file (under key "FontFile2"), use the
087:             * true type font.  Otherwise, parse the description for key information
088:             * and use that to generate an appropriate font.
089:             */
090:            public NativeFont(String baseFont, PDFObject fontObj,
091:                    PDFFontDescriptor descriptor) throws IOException {
092:                super (baseFont, fontObj, descriptor);
093:
094:                String fontName = descriptor.getFontName();
095:
096:                PDFObject ttf = descriptor.getFontFile2();
097:                if (ttf != null) {
098:                    byte[] fontdata = ttf.getStream();
099:
100:                    try {
101:                        setFont(fontdata);
102:                    } catch (FontFormatException ffe) {
103:                        throw new PDFParseException("Font format exception: "
104:                                + ffe);
105:                    }
106:                } else {
107:                    int flags = descriptor.getFlags();
108:                    int style = ((flags & (1 << 18)) != 0) ? Font.BOLD
109:                            : Font.PLAIN;
110:
111:                    if (fontName.indexOf("Bold") > 0) {
112:                        style |= Font.BOLD;
113:                    }
114:                    if (descriptor.getItalicAngle() != 0) {
115:                        style |= Font.ITALIC;
116:                    }
117:                    if ((flags & 1) != 0) { // fixed width
118:                        setFont(new Font("Monospaced", style, 1));
119:                    } else if ((flags & 1 << 1) != 0) { // serif font
120:                        setFont(new Font("Serif", style, 1));
121:                    } else {
122:                        setFont(new Font("Sans-serif", style, 1));
123:                    }
124:                }
125:            }
126:
127:            /**
128:             * Get a glyph outline by name
129:             *
130:             * @param name the name of the desired glyph
131:             * @return the glyph outline, or null if unavailable
132:             */
133:            protected GeneralPath getOutline(String name, float width) {
134:                if (postTable != null && cmapTable != null) {
135:                    // map this character name to a glyph ID
136:                    short glyphID = postTable.getGlyphNameIndex(name);
137:
138:                    if (glyphID == 0) {
139:                        // no glyph -- try by index
140:                        return null;
141:                    }
142:
143:                    // the mapped character
144:                    char mappedChar = 0;
145:
146:                    for (int i = 0; i < mapIDs.length; i += 2) {
147:                        CMap map = cmapTable.getCMap(mapIDs[i], mapIDs[i + 1]);
148:                        if (map != null) {
149:                            mappedChar = map.reverseMap(glyphID);
150:
151:                            // we found a character
152:                            if (mappedChar != 0) {
153:                                break;
154:                            }
155:                        }
156:                    }
157:
158:                    return getOutline(mappedChar, width);
159:                }
160:
161:                // no maps found, hope the font can deal
162:                return null;
163:            }
164:
165:            /**
166:             * Get a glyph outline by character code
167:             *
168:             * Note this method must always return an outline 
169:             *
170:             * @param src the character code of the desired glyph
171:             * @return the glyph outline
172:             */
173:            protected GeneralPath getOutline(char src, float width) {
174:                // some true type fonts put characters in the undefined
175:                // region of Unicode instead of as normal characters.
176:                if (!f.canDisplay(src) && f.canDisplay((char) (src + 0xf000))) {
177:                    src += 0xf000;
178:                }
179:
180:                // filter out control characters
181:                for (int i = 0; i < controlChars.length; i++) {
182:                    if (controlChars[i] == src) {
183:                        src = (char) (0xf000 | src);
184:                        break;
185:                    }
186:                }
187:
188:                char[] glyph = new char[1];
189:                glyph[0] = src;
190:
191:                GlyphVector gv = f.createGlyphVector(basecontext, glyph);
192:                GeneralPath gp = new GeneralPath(gv.getGlyphOutline(0));
193:
194:                // this should be gv.getGlyphMetrics(0).getAdvance(), but that is
195:                // broken on the Mac, so we need to read the advance from the
196:                // hmtx table in the font
197:                CMap map = cmapTable.getCMap(mapIDs[0], mapIDs[1]);
198:                int glyphID = map.map(src);
199:                float advance = (float) hmtxTable.getAdvance(glyphID)
200:                        / (float) unitsPerEm;
201:
202:                float widthfactor = width / advance;
203:                gp.transform(AffineTransform.getScaleInstance(widthfactor, -1));
204:
205:                return gp;
206:            }
207:
208:            /**
209:             * Set the font
210:             *
211:             * @param f the font to use
212:             */
213:            protected void setFont(Font f) {
214:                this .f = f;
215:
216:                // if it's an OpenType font, parse the relevant tables to get
217:                // glyph name to code mappings
218:                if (f instanceof  OpenType) {
219:                    OpenType ot = (OpenType) f;
220:
221:                    byte[] cmapData = ot.getFontTable(OpenType.TAG_CMAP);
222:                    byte[] postData = ot.getFontTable(OpenType.TAG_POST);
223:
224:                    TrueTypeFont ttf = new TrueTypeFont(0x10000);
225:
226:                    cmapTable = (CmapTable) TrueTypeTable.createTable(ttf,
227:                            "cmap", ByteBuffer.wrap(cmapData));
228:                    ttf.addTable("cmap", cmapTable);
229:
230:                    postTable = (PostTable) TrueTypeTable.createTable(ttf,
231:                            "post", ByteBuffer.wrap(postData));
232:                    ttf.addTable("post", postTable);
233:                }
234:            }
235:
236:            /**
237:             * Set the font
238:             *
239:             * @param fontdata the font data as a byte array
240:             */
241:            protected void setFont(byte[] fontdata) throws FontFormatException,
242:                    IOException {
243:
244:                // System.out.println("Loading " + getBaseFont());
245:                // FileOutputStream fos = new FileOutputStream("/tmp/" + getBaseFont() + ".ttf");
246:                // fos.write(fontdata);
247:                // fos.close();
248:
249:                try {
250:                    // read the true type information
251:                    TrueTypeFont ttf = TrueTypeFont.parseFont(fontdata);
252:
253:                    // System.out.println(ttf.toString());
254:
255:                    // get the cmap, post, and hmtx tables for later use
256:                    cmapTable = (CmapTable) ttf.getTable("cmap");
257:                    postTable = (PostTable) ttf.getTable("post");
258:                    hmtxTable = (HmtxTable) ttf.getTable("hmtx");
259:
260:                    // read the units per em from the head table
261:                    HeadTable headTable = (HeadTable) ttf.getTable("head");
262:                    unitsPerEm = headTable.getUnitsPerEm();
263:
264:                    /* Find out if we have the right info in our name table.
265:                     * This is a hack because Java can only deal with fonts that
266:                     * have a Microsoft encoded name in their name table (PlatformID 3).
267:                     * We'll 'adjust' the font to add it if not, and take our chances
268:                     * with our parsing, since it wasn't going to work anyway.
269:                     */
270:                    NameTable nameTable = null;
271:
272:                    try {
273:                        nameTable = (NameTable) ttf.getTable("name");
274:                    } catch (Exception ex) {
275:                        System.out.println("Error reading name table for font "
276:                                + getBaseFont() + ".  Repairing!");
277:                    }
278:
279:                    boolean nameFixed = fixNameTable(ttf, nameTable);
280:
281:                    /* Figure out if we need to hack the CMap table.  This might
282:                     * be the case if we use characters that Java considers control
283:                     * characters (0x9, 0xa and 0xd), that have to be re-mapped
284:                     */
285:                    boolean cmapFixed = fixCMapTable(ttf, cmapTable);
286:
287:                    // use the parsed font instead of the original
288:                    if (nameFixed || cmapFixed) {
289:                        // System.out.println("Using fixed font!");
290:                        // System.out.println(ttf.toString());
291:                        fontdata = ttf.writeFont();
292:
293:                        // FileOutputStream fos2 = new FileOutputStream("/tmp/" + getBaseFont() + ".fix");
294:                        // fos2.write(fontdata);
295:                        // fos2.close();
296:                    }
297:                } catch (Exception ex) {
298:                    System.out.println("Error parsing font : " + getBaseFont());
299:                    ex.printStackTrace();
300:                }
301:
302:                ByteArrayInputStream bais = new ByteArrayInputStream(fontdata);
303:                f = Font.createFont(Font.TRUETYPE_FONT, bais);
304:                bais.close();
305:            }
306:
307:            /**
308:             * Fix a broken font name table for a TrueType font.  Some fonts do not
309:             * have Microsoft-specific name information, but Java won't work without
310:             * it (grrr.).  This method takes a font and adds the Microsoft data into
311:             * it.
312:             *
313:             * @param ttf the font
314:             * @param name the font's name table
315:             * @return true if the table was fixed, or false if it was left as is
316:             */
317:            private boolean fixNameTable(TrueTypeFont ttf, NameTable name) {
318:                // if we didn't find the table, or there was an exception,
319:                // just create a new one
320:                if (name == null) {
321:                    name = (NameTable) TrueTypeTable.createTable(ttf, "name");
322:                    ttf.addTable("name", name);
323:                }
324:
325:                // first, figure out some info about the font
326:                String fName = this .getBaseFont();
327:                String style = "Regular";
328:
329:                if (fName.indexOf("Italic") > -1
330:                        || fName.indexOf("italic") > -1) {
331:                    style = "Italic";
332:                } else if (fName.indexOf("Bold") > -1
333:                        || fName.indexOf("bold") > -1) {
334:                    style = "Bold";
335:                }
336:
337:                if (fName.indexOf('-') > -1) {
338:                    fName = fName.substring(0, fName.indexOf('-'));
339:                }
340:
341:                short platID = NameTable.PLATFORMID_MICROSOFT;
342:                short encID = 1;
343:                short langID = 1033;
344:
345:                short[] nameIDs = { NameTable.NAMEID_COPYRIGHT,
346:                        NameTable.NAMEID_FAMILY, NameTable.NAMEID_SUBFAMILY,
347:                        NameTable.NAMEID_SUBFAMILY_UNIQUE,
348:                        NameTable.NAMEID_FULL_NAME, NameTable.NAMEID_VERSION,
349:                        NameTable.NAMEID_POSTSCRIPT_NAME,
350:                        NameTable.NAMEID_TRADEMARK };
351:
352:                String[] defaultValues = { "No copyright", fName, style,
353:                        fName + " " + style, fName + " " + style, "1.0 (Fake)",
354:                        fName, "No Trademark" };
355:
356:                boolean changed = false;
357:
358:                for (int i = 0; i < nameIDs.length; i++) {
359:                    if (name.getRecord(platID, encID, langID, nameIDs[i]) == null) {
360:                        name.addRecord(platID, encID, langID, nameIDs[i],
361:                                defaultValues[i]);
362:                        changed = true;
363:                    }
364:                }
365:
366:                return changed;
367:            }
368:
369:            /**
370:             * Fix the CMap table.  This can be necessary if characters are mapped to
371:             * control characters (0x9, 0xa, 0xd) Java will not render them, even 
372:             * though they are valid.
373:             *
374:             * Also, Java tends to not like it when there is only a Format 0 CMap,
375:             * which happens frequently when included Format 4 CMaps are broken.
376:             * Since PDF prefers the Format 0 map, while Java prefers the Format 4 map,
377:             * it is generally necessary to re-write the Format 0 map as a Format 4 map
378:             * to make most PDFs work.
379:             *
380:             * @param ttf the font
381:             * @param cmap the CMap table
382:             * @return true if the font was changed, or false if it was left as-is
383:             */
384:            private boolean fixCMapTable(TrueTypeFont ttf, CmapTable cmap) {
385:                CMapFormat4 fourMap = null;
386:                CMapFormat0 zeroMap = null;
387:
388:                for (int i = 0; i < mapIDs.length; i += 2) {
389:                    CMap map = cmapTable.getCMap(mapIDs[i], mapIDs[i + 1]);
390:                    if (map != null) {
391:                        if (fourMap == null && map instanceof  CMapFormat4) {
392:                            fourMap = (CMapFormat4) map;
393:                        } else if (zeroMap == null
394:                                && map instanceof  CMapFormat0) {
395:                            zeroMap = (CMapFormat0) map;
396:                        }
397:                    }
398:                }
399:
400:                // if there were no maps, we could have problems.  Just try creating
401:                // an identity map
402:                if (zeroMap == null && fourMap == null) {
403:                    fourMap = (CMapFormat4) CMap
404:                            .createMap((short) 4, (short) 0);
405:                    fourMap.addSegment((short) getFirstChar(),
406:                            (short) getLastChar(), (short) 0);
407:                }
408:
409:                // create our map based on the type 0 map, since PDF seems
410:                // to prefer a type 0 map (Java prefers a unicode map)
411:                if (zeroMap != null) {
412:                    fourMap = (CMapFormat4) CMap
413:                            .createMap((short) 4, (short) 0);
414:
415:                    // add the mappings from 0 to null and 1 to notdef
416:                    fourMap.addSegment((short) 0, (short) 1, (short) 0);
417:
418:                    for (int i = getFirstChar(); i <= getLastChar(); i++) {
419:                        short value = (short) (zeroMap.map((byte) i) & 0xff);
420:                        if (value != 0) {
421:                            fourMap.addSegment((short) i, (short) i,
422:                                    (short) (value - i));
423:                        }
424:                    }
425:                }
426:
427:                // now that we have a type four map, remap control characters
428:                for (int i = 0; i < controlChars.length; i++) {
429:                    short idx = (short) (0xf000 | controlChars[i]);
430:                    short value = (short) fourMap.map(controlChars[i]);
431:
432:                    fourMap.addSegment(idx, idx, (short) (value - idx));
433:                }
434:
435:                // create a whole new table with just our map
436:                cmap = (CmapTable) TrueTypeTable.createTable(ttf, "cmap");
437:                cmap.addCMap((short) 3, (short) 1, fourMap);
438:
439:                // replace the table in the font
440:                ttf.addTable("cmap", cmap);
441:
442:                // change the stored table
443:                cmapTable = cmap;
444:
445:                return true;
446:            }
447:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.