Source Code Cross Referenced for PDFont.java in  » PDF » PDFBox-0.7.3 » org » pdfbox » pdmodel » 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 » PDFBox 0.7.3 » org.pdfbox.pdmodel.font 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * Copyright (c) 2003-2006, www.pdfbox.org
003:         * All rights reserved.
004:         *
005:         * Redistribution and use in source and binary forms, with or without
006:         * modification, are permitted provided that the following conditions are met:
007:         *
008:         * 1. Redistributions of source code must retain the above copyright notice,
009:         *    this list of conditions and the following disclaimer.
010:         * 2. Redistributions in binary form must reproduce the above copyright notice,
011:         *    this list of conditions and the following disclaimer in the documentation
012:         *    and/or other materials provided with the distribution.
013:         * 3. Neither the name of pdfbox; nor the names of its
014:         *    contributors may be used to endorse or promote products derived from this
015:         *    software without specific prior written permission.
016:         *
017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020:         * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022:         * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024:         * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027:         *
028:         * http://www.pdfbox.org
029:         *
030:         */package org.pdfbox.pdmodel.font;
031:
032:        import org.fontbox.afm.AFMParser;
033:
034:        import org.fontbox.afm.FontMetric;
035:
036:        import org.fontbox.cmap.CMapParser;
037:
038:        import org.fontbox.cmap.CMap;
039:
040:        import org.pdfbox.encoding.AFMEncoding;
041:        import org.pdfbox.encoding.DictionaryEncoding;
042:        import org.pdfbox.encoding.Encoding;
043:        import org.pdfbox.encoding.EncodingManager;
044:
045:        import org.pdfbox.cos.COSArray;
046:        import org.pdfbox.cos.COSBase;
047:        import org.pdfbox.cos.COSDictionary;
048:        import org.pdfbox.cos.COSFloat;
049:        import org.pdfbox.cos.COSName;
050:        import org.pdfbox.cos.COSNumber;
051:        import org.pdfbox.cos.COSStream;
052:
053:        import org.pdfbox.pdmodel.common.COSArrayList;
054:        import org.pdfbox.pdmodel.common.COSObjectable;
055:        import org.pdfbox.pdmodel.common.PDMatrix;
056:        import org.pdfbox.pdmodel.common.PDRectangle;
057:
058:        import org.pdfbox.util.ResourceLoader;
059:
060:        import java.awt.Graphics;
061:
062:        import java.io.BufferedReader;
063:        import java.io.InputStream;
064:        import java.io.InputStreamReader;
065:        import java.io.IOException;
066:
067:        import java.util.Collections;
068:        import java.util.HashMap;
069:        import java.util.List;
070:        import java.util.Map;
071:        import java.util.StringTokenizer;
072:
073:        /**
074:         * This is the base class for all PDF fonts.
075:         *
076:         * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
077:         * @version $Revision: 1.43 $
078:         */
079:        public abstract class PDFont implements  COSObjectable {
080:
081:            /**
082:             * The cos dictionary for this font.
083:             */
084:            protected COSDictionary font;
085:
086:            /**
087:             * This is only used if this is a font object and it has an encoding.
088:             */
089:            private Encoding fontEncoding = null;
090:            /**
091:             * This is only used if this is a font object and it has an encoding and it is
092:             * a type0 font with a cmap.
093:             */
094:            private CMap cmap = null;
095:
096:            private static Map afmResources = null;
097:            private static Map cmapObjects = null;
098:            private static Map afmObjects = null;
099:            private static Map cmapSubstitutions = null;
100:
101:            static {
102:                //these are read-only once they are created
103:                afmResources = new HashMap();
104:                cmapSubstitutions = new HashMap();
105:
106:                //these are read-write
107:                cmapObjects = Collections.synchronizedMap(new HashMap());
108:                afmObjects = Collections.synchronizedMap(new HashMap());
109:
110:                afmResources.put(COSName.getPDFName("Courier-Bold"),
111:                        "Resources/afm/Courier-Bold.afm");
112:                afmResources.put(COSName.getPDFName("Courier-BoldOblique"),
113:                        "Resources/afm/Courier-BoldOblique.afm");
114:                afmResources.put(COSName.getPDFName("Courier"),
115:                        "Resources/afm/Courier.afm");
116:                afmResources.put(COSName.getPDFName("Courier-Oblique"),
117:                        "Resources/afm/Courier-Oblique.afm");
118:                afmResources.put(COSName.getPDFName("Helvetica"),
119:                        "Resources/afm/Helvetica.afm");
120:                afmResources.put(COSName.getPDFName("Helvetica-Bold"),
121:                        "Resources/afm/Helvetica-Bold.afm");
122:                afmResources.put(COSName.getPDFName("Helvetica-BoldOblique"),
123:                        "Resources/afm/Helvetica-BoldOblique.afm");
124:                afmResources.put(COSName.getPDFName("Helvetica-Oblique"),
125:                        "Resources/afm/Helvetica-Oblique.afm");
126:                afmResources.put(COSName.getPDFName("Symbol"),
127:                        "Resources/afm/Symbol.afm");
128:                afmResources.put(COSName.getPDFName("Times-Bold"),
129:                        "Resources/afm/Times-Bold.afm");
130:                afmResources.put(COSName.getPDFName("Times-BoldItalic"),
131:                        "Resources/afm/Times-BoldItalic.afm");
132:                afmResources.put(COSName.getPDFName("Times-Italic"),
133:                        "Resources/afm/Times-Italic.afm");
134:                afmResources.put(COSName.getPDFName("Times-Roman"),
135:                        "Resources/afm/Times-Roman.afm");
136:                afmResources.put(COSName.getPDFName("ZapfDingbats"),
137:                        "Resources/afm/ZapfDingbats.afm");
138:
139:                cmapSubstitutions.put("ETen-B5-H", "ETen-B5-UCS2");
140:                cmapSubstitutions.put("ETen-B5-V", "ETen-B5-UCS2");
141:                cmapSubstitutions.put("ETenms-B5-H", "ETen-B5-UCS2");
142:                cmapSubstitutions.put("ETenms-B5-V", "ETen-B5-UCS2");
143:
144:                cmapSubstitutions.put("90ms-RKSJ-H", "90ms-RKSJ-UCS2");
145:                cmapSubstitutions.put("90ms-RKSJ-V", "90ms-RKSJ-UCS2");
146:                cmapSubstitutions.put("90msp-RKSJ-H", "90ms-RKSJ-UCS2");
147:                cmapSubstitutions.put("90msp-RKSJ-V", "90ms-RKSJ-UCS2");
148:                cmapSubstitutions.put("GBK-EUC-H", "GBK-EUC-UCS2");
149:                cmapSubstitutions.put("GBK-EUC-V", "GBK-EUC-UCS2");
150:                cmapSubstitutions.put("GBpc-EUC-H", "GBpc-EUC-UCS2C");
151:                cmapSubstitutions.put("GBpc-EUC-V", "GBpc-EUC-UCS2C");
152:
153:                cmapSubstitutions.put("UniJIS-UCS2-HW-H", "UniJIS-UCS2-H");
154:            }
155:
156:            /**
157:             * This will clear AFM resources that are stored statically.
158:             * This is usually not a problem unless you want to reclaim
159:             * resources for a long running process.
160:             *
161:             * SPECIAL NOTE: The font calculations are currently in COSObject, which
162:             * is where they will reside until PDFont is mature enough to take them over.
163:             * PDFont is the appropriate place for them and not in COSObject but we need font
164:             * calculations for text extractaion.  THIS METHOD WILL BE MOVED OR REMOVED
165:             * TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX.
166:             */
167:            public static void clearResources() {
168:                afmObjects.clear();
169:                cmapObjects.clear();
170:            }
171:
172:            /**
173:             * Constructor.
174:             */
175:            public PDFont() {
176:                font = new COSDictionary();
177:                font.setItem(COSName.TYPE, COSName.FONT);
178:            }
179:
180:            /**
181:             * Constructor.
182:             *
183:             * @param fontDictionary The font dictionary according to the PDF specification.
184:             */
185:            public PDFont(COSDictionary fontDictionary) {
186:                font = fontDictionary;
187:            }
188:
189:            /**
190:             * {@inheritDoc}
191:             */
192:            public COSBase getCOSObject() {
193:                return font;
194:            }
195:
196:            /**
197:             * This will get the font width for a character.
198:             *
199:             * @param c The character code to get the width for.
200:             * @param offset The offset into the array.
201:             * @param length The length of the data.
202:             *
203:             * @return The width is in 1000 unit of text space, ie 333 or 777
204:             *
205:             * @throws IOException If an error occurs while parsing.
206:             */
207:            public abstract float getFontWidth(byte[] c, int offset, int length)
208:                    throws IOException;
209:
210:            /**
211:             * This will get the font width for a character.
212:             *
213:             * @param c The character code to get the width for.
214:             * @param offset The offset into the array.
215:             * @param length The length of the data.
216:             *
217:             * @return The width is in 1000 unit of text space, ie 333 or 777
218:             *
219:             * @throws IOException If an error occurs while parsing.
220:             */
221:            public abstract float getFontHeight(byte[] c, int offset, int length)
222:                    throws IOException;
223:
224:            /**
225:             * This will get the width of this string for this font.
226:             *
227:             * @param string The string to get the width of.
228:             *
229:             * @return The width of the string in 1000 units of text space, ie 333 567...
230:             *
231:             * @throws IOException If there is an error getting the width information.
232:             */
233:            public float getStringWidth(String string) throws IOException {
234:                byte[] data = string.getBytes();
235:                float totalWidth = 0;
236:                for (int i = 0; i < data.length; i++) {
237:                    totalWidth += getFontWidth(data, i, 1);
238:                }
239:                return totalWidth;
240:            }
241:
242:            /**
243:             * This will get the average font width for all characters.
244:             *
245:             * @return The width is in 1000 unit of text space, ie 333 or 777
246:             *
247:             * @throws IOException If an error occurs while parsing.
248:             */
249:            public abstract float getAverageFontWidth() throws IOException;
250:
251:            /**
252:             * This will draw a string on a canvas using the font.
253:             *
254:             * @param string The string to draw.
255:             * @param g The graphics to draw onto.
256:             * @param fontSize The size of the font to draw.
257:             * @param xScale The x scaling percent.
258:             * @param yScale The y scaling percent.
259:             * @param x The x coordinate to draw at.
260:             * @param y The y coordinate to draw at.
261:             *
262:             * @throws IOException If there is an error drawing the specific string.
263:             */
264:            public abstract void drawString(String string, Graphics g,
265:                    float fontSize, float xScale, float yScale, float x, float y)
266:                    throws IOException;
267:
268:            /**
269:             * Used for multibyte encodings.
270:             *
271:             * @param data The array of data.
272:             * @param offset The offset into the array.
273:             * @param length The number of bytes to use.
274:             *
275:             * @return The int value of data from the array.
276:             */
277:            protected int getCodeFromArray(byte[] data, int offset, int length) {
278:                int code = 0;
279:                for (int i = 0; i < length; i++) {
280:                    code <<= 8;
281:                    code |= (data[offset + i] + 256) % 256;
282:                }
283:                return code;
284:            }
285:
286:            /**
287:             * This will attempt to get the font width from an AFM file.
288:             *
289:             * @param code The character code we are trying to get.
290:             *
291:             * @return The font width from the AFM file.
292:             *
293:             * @throws IOException if we cannot find the width.
294:             */
295:            protected float getFontWidthFromAFMFile(int code)
296:                    throws IOException {
297:                float retval = 0;
298:                FontMetric metric = getAFM();
299:                if (metric != null) {
300:                    Encoding encoding = getEncoding();
301:                    COSName characterName = encoding.getName(code);
302:                    retval = metric.getCharacterWidth(characterName.getName());
303:                }
304:                return retval;
305:            }
306:
307:            /**
308:             * This will attempt to get the average font width from an AFM file.
309:             *
310:             * @return The average font width from the AFM file.
311:             *
312:             * @throws IOException if we cannot find the width.
313:             */
314:            protected float getAverageFontWidthFromAFMFile() throws IOException {
315:                float retval = 0;
316:                FontMetric metric = getAFM();
317:                if (metric != null) {
318:                    retval = metric.getAverageCharacterWidth();
319:                }
320:                return retval;
321:            }
322:
323:            /**
324:             * This will get an AFM object if one exists.
325:             *
326:             * @return The afm object from the name.
327:             *
328:             * @throws IOException If there is an error getting the AFM object.
329:             */
330:            protected FontMetric getAFM() throws IOException {
331:                COSName name = (COSName) font
332:                        .getDictionaryObject(COSName.BASE_FONT);
333:                FontMetric result = null;
334:                if (name != null) {
335:                    result = (FontMetric) afmObjects.get(name);
336:                    if (result == null) {
337:                        String resource = (String) afmResources.get(name);
338:                        if (resource == null) {
339:                            //ok for now
340:                            //throw new IOException( "Unknown AFM font '" + name.getName() + "'" );
341:                        } else {
342:                            InputStream afmStream = ResourceLoader
343:                                    .loadResource(resource);
344:                            if (afmStream == null) {
345:                                throw new IOException(
346:                                        "Can't handle font width:" + resource);
347:                            }
348:                            AFMParser parser = new AFMParser(afmStream);
349:                            parser.parse();
350:                            result = parser.getResult();
351:                            afmObjects.put(name, result);
352:                        }
353:                    }
354:                }
355:                return result;
356:            }
357:
358:            /**
359:             * This will perform the encoding of a character if needed.
360:             *
361:             * @param c The character to encode.
362:             * @param offset The offset into the array to get the data
363:             * @param length The number of bytes to read.
364:             *
365:             * @return The value of the encoded character.
366:             *
367:             * @throws IOException If there is an error during the encoding.
368:             */
369:            public String encode(byte[] c, int offset, int length)
370:                    throws IOException {
371:                String retval = null;
372:                COSName fontSubtype = (COSName) font
373:                        .getDictionaryObject(COSName.SUBTYPE);
374:                String fontSubtypeName = fontSubtype.getName();
375:                if (fontSubtypeName.equals("Type0")
376:                        || fontSubtypeName.equals("Type1")
377:                        || fontSubtypeName.equals("TrueType")) {
378:                    if (cmap == null) {
379:                        if (font.getDictionaryObject(COSName.TO_UNICODE) != null) {
380:                            COSStream toUnicode = (COSStream) font
381:                                    .getDictionaryObject(COSName.TO_UNICODE);
382:                            if (toUnicode != null) {
383:                                parseCmap(toUnicode.getUnfilteredStream(), null);
384:                            }
385:                        } else {
386:                            COSBase encoding = font
387:                                    .getDictionaryObject(COSName.ENCODING);
388:                            if (encoding instanceof  COSStream) {
389:                                COSStream encodingStream = (COSStream) encoding;
390:                                parseCmap(encodingStream.getUnfilteredStream(),
391:                                        null);
392:                            } else if (fontSubtypeName.equals("Type0")
393:                                    && encoding instanceof  COSName) {
394:                                COSName encodingName = (COSName) encoding;
395:                                cmap = (CMap) cmapObjects.get(encodingName);
396:                                if (cmap != null) {
397:                                    cmap = (CMap) cmapObjects.get(encodingName);
398:                                } else {
399:                                    String cmapName = encodingName.getName();
400:                                    cmapName = performCMAPSubstitution(cmapName);
401:                                    String resourceName = "Resources/cmap/"
402:                                            + cmapName;
403:                                    parseCmap(ResourceLoader
404:                                            .loadResource(resourceName),
405:                                            encodingName);
406:                                    if (cmap == null
407:                                            && !encodingName.getName().equals(
408:                                                    COSName.IDENTITY_H
409:                                                            .getName())) {
410:                                        throw new IOException(
411:                                                "Error: Could not find predefined "
412:                                                        + "CMAP file for '"
413:                                                        + encodingName
414:                                                                .getName()
415:                                                        + "'");
416:                                    }
417:                                }
418:                            } else if (encoding instanceof  COSName
419:                                    || encoding instanceof  COSDictionary) {
420:                                Encoding currentFontEncoding = getEncoding();
421:                                if (currentFontEncoding != null) {
422:                                    retval = currentFontEncoding
423:                                            .getCharacter(getCodeFromArray(c,
424:                                                    offset, length));
425:                                }
426:                            } else {
427:                                COSDictionary fontDescriptor = (COSDictionary) font
428:                                        .getDictionaryObject(COSName.FONT_DESC);
429:                                if (fontSubtypeName.equals("TrueType")
430:                                        && fontDescriptor != null
431:                                        && (fontDescriptor
432:                                                .getDictionaryObject(COSName.FONT_FILE) != null
433:                                                || fontDescriptor
434:                                                        .getDictionaryObject(COSName.FONT_FILE2) != null || fontDescriptor
435:                                                .getDictionaryObject(COSName.FONT_FILE3) != null)) {
436:                                    //If we are using an embedded font then there is not much we can do besides
437:                                    //return the same character codes.
438:                                    //retval = new String( c,offset, length );
439:                                    retval = getStringFromArray(c, offset,
440:                                            length);
441:                                } else {
442:                                    //this case will be handled below after checking the cmap
443:                                }
444:                            }
445:                        }
446:
447:                    }
448:                }
449:                if (retval == null && cmap != null) {
450:                    retval = cmap.lookup(c, offset, length);
451:                }
452:                //if we havn't found a value yet and 
453:                //we are still on the first byte and
454:                //there is no cmap or the cmap does not have 2 byte mappings then try to encode
455:                //using fallback methods.
456:                if (retval == null && length == 1
457:                        && (cmap == null || !cmap.hasTwoByteMappings())) {
458:                    Encoding encoding = getEncoding();
459:                    if (encoding != null) {
460:                        retval = encoding.getCharacter(getCodeFromArray(c,
461:                                offset, length));
462:                    }
463:                    if (retval == null) {
464:                        retval = getStringFromArray(c, offset, length);
465:                    }
466:                }
467:                return retval;
468:            }
469:
470:            private static final String[] SINGLE_CHAR_STRING = new String[256];
471:            private static final String[][] DOUBLE_CHAR_STRING = new String[256][256];
472:            static {
473:                for (int i = 0; i < 256; i++) {
474:                    SINGLE_CHAR_STRING[i] = new String(new byte[] { (byte) i });
475:                    for (int j = 0; j < 256; j++) {
476:                        DOUBLE_CHAR_STRING[i][j] = new String(new byte[] {
477:                                (byte) i, (byte) j });
478:                    }
479:                }
480:            }
481:
482:            private static String getStringFromArray(byte[] c, int offset,
483:                    int length) throws IOException {
484:                String retval = null;
485:                if (length == 1) {
486:                    retval = SINGLE_CHAR_STRING[(c[offset] + 256) % 256];
487:                } else if (length == 2) {
488:                    retval = DOUBLE_CHAR_STRING[(c[offset] + 256) % 256][(c[offset + 1] + 256) % 256];
489:                } else {
490:                    throw new IOException("Error:Unknown character length:"
491:                            + length);
492:                }
493:                return retval;
494:            }
495:
496:            /**
497:             * Some cmap names are synonyms for other CMAPs.  If that is the case
498:             * then this method will perform that substitution.
499:             *
500:             * @param cmapName The name of the cmap to attempt to look up.
501:             *
502:             * @return Either the original name or the substituted name.
503:             */
504:            private String performCMAPSubstitution(String cmapName) {
505:                String retval = (String) cmapSubstitutions.get(cmapName);
506:                if (retval == null) {
507:                    //if there is no substitution then just return the same value.
508:                    retval = cmapName;
509:                }
510:                return retval;
511:            }
512:
513:            private void parseCmap(InputStream cmapStream, COSName encodingName)
514:                    throws IOException {
515:                if (cmapStream != null) {
516:                    CMapParser parser = new CMapParser();
517:                    cmap = parser.parse(cmapStream);
518:                    if (encodingName != null) {
519:                        cmapObjects.put(encodingName, cmap);
520:                    }
521:                }
522:            }
523:
524:            /**
525:             * The will set the encoding for this font.
526:             * 
527:             * @param enc The font encoding.
528:             */
529:            public void setEncoding(Encoding enc) {
530:                font.setItem(COSName.ENCODING, enc);
531:                fontEncoding = enc;
532:            }
533:
534:            /**
535:             * This will get or create the encoder.
536:             *
537:             * modified by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
538:             *
539:             * @return The encoding to use.
540:             *
541:             * @throws IOException If there is an error getting the encoding.
542:             */
543:            public Encoding getEncoding() throws IOException {
544:                EncodingManager manager = new EncodingManager();
545:                if (fontEncoding == null) {
546:                    COSBase encoding = font
547:                            .getDictionaryObject(COSName.ENCODING);
548:                    if (encoding == null) {
549:                        FontMetric metric = getAFM();
550:                        if (metric != null) {
551:                            fontEncoding = new AFMEncoding(metric);
552:                        }
553:                        if (fontEncoding == null) {
554:                            fontEncoding = manager.getStandardEncoding();
555:                        }
556:                    }
557:                    /**
558:                     * Si la clé /Encoding existe dans le dictionnaire fonte il y a deux possibilités :
559:                     * 1er cas : elle est associé à une reference contenant un dictionnaire de type encoding.
560:                     * Ce dictionnaire PDF est représenté par un DictionaryEncoding.
561:                     * If the /Encoding Key does exist in the font dictionary, there are two cases :
562:                     * case one : The value associated with /Encoding is a reference to a dictionary.
563:                     * This dictionary is represented by an instance of DictionaryEncoding class
564:                     */
565:                    else if (encoding instanceof  COSDictionary) {
566:                        COSDictionary encodingDic = (COSDictionary) encoding;
567:                        //Let's see if the encoding dictionary has a base encoding
568:                        //If it does not then we will attempt to get it from the font
569:                        //file
570:                        COSName baseEncodingName = (COSName) encodingDic
571:                                .getDictionaryObject(COSName.BASE_ENCODING);
572:                        //on ajoute une entrée /BaseEncoding dans /Encoding uniquement si elle en est absente
573:                        //if not find in Encoding dictinary target, we try to find it from else where
574:                        if (baseEncodingName == null) {
575:                            COSName fontEncodingFromFile = getEncodingFromFont();
576:                            encodingDic.setItem(COSName.BASE_ENCODING,
577:                                    fontEncodingFromFile);
578:                        }
579:                        fontEncoding = new DictionaryEncoding(encodingDic);
580:                    } else if (encoding instanceof  COSName) {
581:                        if (!encoding.equals(COSName.IDENTITY_H)) {
582:                            fontEncoding = manager
583:                                    .getEncoding((COSName) encoding);
584:                        }
585:                    } else {
586:                        throw new IOException("Unexpected encoding type:"
587:                                + encoding.getClass().getName());
588:                    }
589:                }
590:                return fontEncoding;
591:            }
592:
593:            /**
594:             * This will always return "Font" for fonts.
595:             * 
596:             * @return The type of object that this is.
597:             */
598:            public String getType() {
599:                return font.getNameAsString(COSName.TYPE);
600:            }
601:
602:            /**
603:             * This will get the subtype of font, Type1, Type3, ...
604:             * 
605:             * @return The type of font that this is.
606:             */
607:            public String getSubType() {
608:                return font.getNameAsString(COSName.SUBTYPE);
609:            }
610:
611:            /**
612:             * The PostScript name of the font.
613:             * 
614:             * @return The postscript name of the font.
615:             */
616:            public String getBaseFont() {
617:                return font.getNameAsString(COSName.BASE_FONT);
618:            }
619:
620:            /**
621:             * Set the PostScript name of the font.
622:             * 
623:             * @param baseFont The postscript name for the font.
624:             */
625:            public void setBaseFont(String baseFont) {
626:                font.setName(COSName.BASE_FONT, baseFont);
627:            }
628:
629:            /**
630:             * The code for the first char or -1 if there is none.
631:             * 
632:             * @return The code for the first character.
633:             */
634:            public int getFirstChar() {
635:                return font.getInt(COSName.FIRST_CHAR, -1);
636:            }
637:
638:            /**
639:             * Set the first character this font supports.
640:             * 
641:             * @param firstChar The first character.
642:             */
643:            public void setFirstChar(int firstChar) {
644:                font.setInt(COSName.FIRST_CHAR, firstChar);
645:            }
646:
647:            /**
648:             * The code for the last char or -1 if there is none.
649:             * 
650:             * @return The code for the last character.
651:             */
652:            public int getLastChar() {
653:                return font.getInt(COSName.LAST_CHAR, -1);
654:            }
655:
656:            /**
657:             * Set the last character this font supports.
658:             * 
659:             * @param lastChar The last character.
660:             */
661:            public void setLastChar(int lastChar) {
662:                font.setInt(COSName.LAST_CHAR, lastChar);
663:            }
664:
665:            /**
666:             * The widths of the characters.  This will be null for the standard 14 fonts.
667:             * 
668:             * @return The widths of the characters.
669:             */
670:            public List getWidths() {
671:                COSArray array = (COSArray) font
672:                        .getDictionaryObject(COSName.WIDTHS);
673:                return COSArrayList.convertFloatCOSArrayToList(array);
674:            }
675:
676:            /**
677:             * Set the widths of the characters code.
678:             * 
679:             * @param widths The widths of the character codes.
680:             */
681:            public void setWidths(List widths) {
682:                font.setItem(COSName.WIDTHS, COSArrayList
683:                        .converterToCOSArray(widths));
684:            }
685:
686:            /**
687:             * This will get the matrix that is used to transform glyph space to
688:             * text space.  By default there are 1000 glyph units to 1 text space
689:             * unit, but type3 fonts can use any value.  
690:             * 
691:             * Note:If this is a type3 font then it can be modified via the PDType3Font.setFontMatrix, otherwise this
692:             * is a read-only property.
693:             * 
694:             * @return The matrix to transform from glyph space to text space.
695:             */
696:            public PDMatrix getFontMatrix() {
697:                PDMatrix matrix = null;
698:                COSArray array = (COSArray) font
699:                        .getDictionaryObject(COSName.FONT_MATRIX);
700:                if (array == null) {
701:                    array = new COSArray();
702:                    array.add(new COSFloat(0.001f));
703:                    array.add(COSNumber.ZERO);
704:                    array.add(COSNumber.ZERO);
705:                    array.add(new COSFloat(0.001f));
706:                    array.add(COSNumber.ZERO);
707:                    array.add(COSNumber.ZERO);
708:                }
709:                matrix = new PDMatrix(array);
710:
711:                return matrix;
712:            }
713:
714:            /**
715:             * Try to get the encoding for the font and add it to the target
716:             * the target must be an an Encoding Dictionary.
717:             *
718:             * added by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
719:             *
720:             * @return The encoding from the font.
721:             * 
722:             * @throws IOException If there is an error reading the file.
723:             */
724:            private COSName getEncodingFromFont() throws IOException {
725:                //This whole section of code needs to be replaced with an actual
726:                //type1 font parser!!
727:
728:                COSName retvalue = null;
729:                //recuperer le programme de fonte dans son stream qui doit se trouver
730:                //dans le flux référencé par à la clé FileFont lui même situé dans
731:                //le dictionnaire associé à /FontDescriptor du dictionnaire de type /Font courrant
732:                //get the font program in the stream which should be located in
733:                //the /FileFont Stream object himself in the /FontDescriptior of the current
734:                //font dictionary
735:                COSDictionary fontDescriptor = (COSDictionary) font
736:                        .getDictionaryObject(COSName.FONT_DESC);
737:                if (fontDescriptor != null) {
738:                    COSStream fontFile = (COSStream) fontDescriptor
739:                            .getDictionaryObject(COSName.FONT_FILE);
740:                    if (fontFile != null) {
741:                        BufferedReader in = new BufferedReader(
742:                                new InputStreamReader(fontFile
743:                                        .getUnfilteredStream()));
744:                        /**
745:                         * this section parse the FileProgram stream searching for a /Encoding entry
746:                         * the research stop if the entry "currentdict end" is reach or after 100 lignes
747:                         */
748:                        StringTokenizer st = null;
749:                        boolean found = false;
750:                        String line = "";
751:                        String key = null;
752:                        for (int i = 0; null != (line = in.readLine())
753:                                && i < 40 && !line.equals("currentdict end")
754:                                && !found; i++) {
755:                            st = new StringTokenizer(line);
756:                            if (st.hasMoreTokens()) {
757:                                key = st.nextToken();
758:                                if (key.equals("/Encoding")
759:                                        && st.hasMoreTokens()) {
760:                                    COSName value = COSName.getPDFName(st
761:                                            .nextToken());
762:                                    found = true;
763:                                    if (value
764:                                            .equals(COSName.MAC_ROMAN_ENCODING)
765:                                            || value
766:                                                    .equals(COSName.PDF_DOC_ENCODING)
767:                                            || value
768:                                                    .equals(COSName.STANDARD_ENCODING)
769:                                            || value
770:                                                    .equals(COSName.WIN_ANSI_ENCODING)) {
771:                                        //value is expected to be one of the encodings
772:                                        //ie. StandardEncoding,WinAnsiEncoding,MacRomanEncoding,PDFDocEncoding
773:                                        retvalue = value;
774:                                    }
775:                                }
776:                            }
777:                        }
778:                    }
779:                }
780:                return retvalue;
781:            }
782:
783:            /**
784:             * This will get the fonts bouding box.
785:             *
786:             * @return The fonts bouding box.
787:             * 
788:             * @throws IOException If there is an error getting the bounding box.
789:             */
790:            public abstract PDRectangle getFontBoundingBox() throws IOException;
791:
792:            /**
793:             * {@inheritDoc}
794:             */
795:            public boolean equals(Object other) {
796:                return other instanceof  PDFont
797:                        && ((PDFont) other).getCOSObject() == this 
798:                                .getCOSObject();
799:            }
800:
801:            /**
802:             * {@inheritDoc}
803:             */
804:            public int hashCode() {
805:                return this.getCOSObject().hashCode();
806:            }
807:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.