Source Code Cross Referenced for Type1Font.java in  » PDF » pdf-itext » com » lowagie » text » pdf » 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 itext » com.lowagie.text.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: Type1Font.java 2509 2006-12-21 16:26:19Z psoares33 $
003:         * $Name$
004:         *
005:         * Copyright 2001-2006 Paulo Soares
006:         *
007:         * The contents of this file are subject to the Mozilla Public License Version 1.1
008:         * (the "License"); you may not use this file except in compliance with the License.
009:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010:         *
011:         * Software distributed under the License is distributed on an "AS IS" basis,
012:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013:         * for the specific language governing rights and limitations under the License.
014:         *
015:         * The Original Code is 'iText, a free JAVA-PDF library'.
016:         *
017:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019:         * All Rights Reserved.
020:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022:         *
023:         * Contributor(s): all the names of the contributors are added in the source code
024:         * where applicable.
025:         *
026:         * Alternatively, the contents of this file may be used under the terms of the
027:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
028:         * provisions of LGPL are applicable instead of those above.  If you wish to
029:         * allow use of your version of this file only under the terms of the LGPL
030:         * License and not to allow others to use your version of this file under
031:         * the MPL, indicate your decision by deleting the provisions above and
032:         * replace them with the notice and other provisions required by the LGPL.
033:         * If you do not delete the provisions above, a recipient may use your version
034:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035:         *
036:         * This library is free software; you can redistribute it and/or modify it
037:         * under the terms of the MPL as stated above or under the terms of the GNU
038:         * Library General Public License as published by the Free Software Foundation;
039:         * either version 2 of the License, or any later version.
040:         *
041:         * This library is distributed in the hope that it will be useful, but WITHOUT
042:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044:         * details.
045:         *
046:         * If you didn't download this code from the following link, you should check if
047:         * you aren't using an obsolete version:
048:         * http://www.lowagie.com/iText/
049:         */
050:
051:        package com.lowagie.text.pdf;
052:
053:        import java.io.ByteArrayOutputStream;
054:        import java.io.IOException;
055:        import java.io.InputStream;
056:        import java.util.HashMap;
057:        import java.util.StringTokenizer;
058:
059:        import com.lowagie.text.DocumentException;
060:        import com.lowagie.text.pdf.fonts.FontsResourceAnchor;
061:
062:        /** Reads a Type1 font
063:         *
064:         * @author Paulo Soares (psoares@consiste.pt)
065:         */
066:        class Type1Font extends BaseFont {
067:            private static FontsResourceAnchor resourceAnchor;
068:
069:            /** The PFB file if the input was made with a <CODE>byte</CODE> array.
070:             */
071:            protected byte pfb[];
072:            /** The Postscript font name.
073:             */
074:            private String FontName;
075:            /** The full name of the font.
076:             */
077:            private String FullName;
078:            /** The family name of the font.
079:             */
080:            private String FamilyName;
081:            /** The weight of the font: normal, bold, etc.
082:             */
083:            private String Weight = "";
084:            /** The italic angle of the font, usually 0.0 or negative.
085:             */
086:            private float ItalicAngle = 0.0f;
087:            /** <CODE>true</CODE> if all the characters have the same
088:             *  width.
089:             */
090:            private boolean IsFixedPitch = false;
091:            /** The character set of the font.
092:             */
093:            private String CharacterSet;
094:            /** The llx of the FontBox.
095:             */
096:            private int llx = -50;
097:            /** The lly of the FontBox.
098:             */
099:            private int lly = -200;
100:            /** The lurx of the FontBox.
101:             */
102:            private int urx = 1000;
103:            /** The ury of the FontBox.
104:             */
105:            private int ury = 900;
106:            /** The underline position.
107:             */
108:            private int UnderlinePosition = -100;
109:            /** The underline thickness.
110:             */
111:            private int UnderlineThickness = 50;
112:            /** The font's encoding name. This encoding is 'StandardEncoding' or
113:             *  'AdobeStandardEncoding' for a font that can be totally encoded
114:             *  according to the characters names. For all other names the
115:             *  font is treated as symbolic.
116:             */
117:            private String EncodingScheme = "FontSpecific";
118:            /** A variable.
119:             */
120:            private int CapHeight = 700;
121:            /** A variable.
122:             */
123:            private int XHeight = 480;
124:            /** A variable.
125:             */
126:            private int Ascender = 800;
127:            /** A variable.
128:             */
129:            private int Descender = -200;
130:            /** A variable.
131:             */
132:            private int StdHW;
133:            /** A variable.
134:             */
135:            private int StdVW = 80;
136:
137:            /** Represents the section CharMetrics in the AFM file. Each
138:             *  value of this array contains a <CODE>Object[4]</CODE> with an
139:             *  Integer, Integer, String and int[]. This is the code, width, name and char bbox.
140:             *  The key is the name of the char and also an Integer with the char number.
141:             */
142:            private HashMap CharMetrics = new HashMap();
143:            /** Represents the section KernPairs in the AFM file. The key is
144:             *  the name of the first character and the value is a <CODE>Object[]</CODE>
145:             *  with 2 elements for each kern pair. Position 0 is the name of
146:             *  the second character and position 1 is the kerning distance. This is
147:             *  repeated for all the pairs.
148:             */
149:            private HashMap KernPairs = new HashMap();
150:            /** The file in use.
151:             */
152:            private String fileName;
153:            /** <CODE>true</CODE> if this font is one of the 14 built in fonts.
154:             */
155:            private boolean builtinFont = false;
156:            /** Types of records in a PFB file. ASCII is 1 and BINARY is 2.
157:             *  They have to appear in the PFB file in this sequence.
158:             */
159:            private static final int PFB_TYPES[] = { 1, 2, 1 };
160:
161:            /** Creates a new Type1 font.
162:             * @param ttfAfm the AFM file if the input is made with a <CODE>byte</CODE> array
163:             * @param pfb the PFB file if the input is made with a <CODE>byte</CODE> array
164:             * @param afmFile the name of one of the 14 built-in fonts or the location of an AFM file. The file must end in '.afm'
165:             * @param enc the encoding to be applied to this font
166:             * @param emb true if the font is to be embedded in the PDF
167:             * @throws DocumentException the AFM file is invalid
168:             * @throws IOException the AFM file could not be read
169:             */
170:            Type1Font(String afmFile, String enc, boolean emb, byte ttfAfm[],
171:                    byte pfb[]) throws DocumentException, IOException {
172:                if (emb && ttfAfm != null && pfb == null)
173:                    throw new DocumentException(
174:                            "Two byte arrays are needed if the Type1 font is embedded.");
175:                if (emb && ttfAfm != null)
176:                    this .pfb = pfb;
177:                encoding = enc;
178:                embedded = emb;
179:                fileName = afmFile;
180:                fontType = FONT_TYPE_T1;
181:                RandomAccessFileOrArray rf = null;
182:                InputStream is = null;
183:                if (BuiltinFonts14.containsKey(afmFile)) {
184:                    embedded = false;
185:                    builtinFont = true;
186:                    byte buf[] = new byte[1024];
187:                    try {
188:                        if (resourceAnchor == null)
189:                            resourceAnchor = new FontsResourceAnchor();
190:                        is = getResourceStream(
191:                                RESOURCE_PATH + afmFile + ".afm",
192:                                resourceAnchor.getClass().getClassLoader());
193:                        if (is == null) {
194:                            String msg = afmFile
195:                                    + " not found as resource. (The *.afm files must exist as resources in the package com.lowagie.text.pdf.fonts)";
196:                            System.err.println(msg);
197:                            throw new DocumentException(msg);
198:                        }
199:                        ByteArrayOutputStream out = new ByteArrayOutputStream();
200:                        while (true) {
201:                            int size = is.read(buf);
202:                            if (size < 0)
203:                                break;
204:                            out.write(buf, 0, size);
205:                        }
206:                        buf = out.toByteArray();
207:                    } finally {
208:                        if (is != null) {
209:                            try {
210:                                is.close();
211:                            } catch (Exception e) {
212:                                // empty on purpose
213:                            }
214:                        }
215:                    }
216:                    try {
217:                        rf = new RandomAccessFileOrArray(buf);
218:                        process(rf);
219:                    } finally {
220:                        if (rf != null) {
221:                            try {
222:                                rf.close();
223:                            } catch (Exception e) {
224:                                // empty on purpose
225:                            }
226:                        }
227:                    }
228:                } else if (afmFile.toLowerCase().endsWith(".afm")) {
229:                    try {
230:                        if (ttfAfm == null)
231:                            rf = new RandomAccessFileOrArray(afmFile);
232:                        else
233:                            rf = new RandomAccessFileOrArray(ttfAfm);
234:                        process(rf);
235:                    } finally {
236:                        if (rf != null) {
237:                            try {
238:                                rf.close();
239:                            } catch (Exception e) {
240:                                // empty on purpose
241:                            }
242:                        }
243:                    }
244:                } else if (afmFile.toLowerCase().endsWith(".pfm")) {
245:                    try {
246:                        ByteArrayOutputStream ba = new ByteArrayOutputStream();
247:                        if (ttfAfm == null)
248:                            rf = new RandomAccessFileOrArray(afmFile);
249:                        else
250:                            rf = new RandomAccessFileOrArray(ttfAfm);
251:                        Pfm2afm.convert(rf, ba);
252:                        rf.close();
253:                        rf = new RandomAccessFileOrArray(ba.toByteArray());
254:                        process(rf);
255:                    } finally {
256:                        if (rf != null) {
257:                            try {
258:                                rf.close();
259:                            } catch (Exception e) {
260:                                // empty on purpose
261:                            }
262:                        }
263:                    }
264:                } else
265:                    throw new DocumentException(afmFile
266:                            + " is not an AFM or PFM font file.");
267:
268:                EncodingScheme = EncodingScheme.trim();
269:                if (EncodingScheme.equals("AdobeStandardEncoding")
270:                        || EncodingScheme.equals("StandardEncoding")) {
271:                    fontSpecific = false;
272:                }
273:                if (!encoding.startsWith("#"))
274:                    PdfEncodings.convertToBytes(" ", enc); // check if the encoding exists
275:                createEncoding();
276:            }
277:
278:            /** Gets the width from the font according to the <CODE>name</CODE> or,
279:             * if the <CODE>name</CODE> is null, meaning it is a symbolic font,
280:             * the char <CODE>c</CODE>.
281:             * @param c the char if the font is symbolic
282:             * @param name the glyph name
283:             * @return the width of the char
284:             */
285:            int getRawWidth(int c, String name) {
286:                Object metrics[];
287:                if (name == null) { // font specific
288:                    metrics = (Object[]) CharMetrics.get(new Integer(c));
289:                } else {
290:                    if (name.equals(".notdef"))
291:                        return 0;
292:                    metrics = (Object[]) CharMetrics.get(name);
293:                }
294:                if (metrics != null)
295:                    return ((Integer) (metrics[1])).intValue();
296:                return 0;
297:            }
298:
299:            /** Gets the kerning between two Unicode characters. The characters
300:             * are converted to names and this names are used to find the kerning
301:             * pairs in the <CODE>HashMap</CODE> <CODE>KernPairs</CODE>.
302:             * @param char1 the first char
303:             * @param char2 the second char
304:             * @return the kerning to be applied
305:             */
306:            public int getKerning(char char1, char char2) {
307:                String first = GlyphList.unicodeToName((int) char1);
308:                if (first == null)
309:                    return 0;
310:                String second = GlyphList.unicodeToName((int) char2);
311:                if (second == null)
312:                    return 0;
313:                Object obj[] = (Object[]) KernPairs.get(first);
314:                if (obj == null)
315:                    return 0;
316:                for (int k = 0; k < obj.length; k += 2) {
317:                    if (second.equals(obj[k]))
318:                        return ((Integer) obj[k + 1]).intValue();
319:                }
320:                return 0;
321:            }
322:
323:            /** Reads the font metrics
324:             * @param rf the AFM file
325:             * @throws DocumentException the AFM file is invalid
326:             * @throws IOException the AFM file could not be read
327:             */
328:            public void process(RandomAccessFileOrArray rf)
329:                    throws DocumentException, IOException {
330:                String line;
331:                boolean isMetrics = false;
332:                while ((line = rf.readLine()) != null) {
333:                    StringTokenizer tok = new StringTokenizer(line,
334:                            " ,\n\r\t\f");
335:                    if (!tok.hasMoreTokens())
336:                        continue;
337:                    String ident = tok.nextToken();
338:                    if (ident.equals("FontName"))
339:                        FontName = tok.nextToken("\u00ff").substring(1);
340:                    else if (ident.equals("FullName"))
341:                        FullName = tok.nextToken("\u00ff").substring(1);
342:                    else if (ident.equals("FamilyName"))
343:                        FamilyName = tok.nextToken("\u00ff").substring(1);
344:                    else if (ident.equals("Weight"))
345:                        Weight = tok.nextToken("\u00ff").substring(1);
346:                    else if (ident.equals("ItalicAngle"))
347:                        ItalicAngle = Float.parseFloat(tok.nextToken());
348:                    else if (ident.equals("IsFixedPitch"))
349:                        IsFixedPitch = tok.nextToken().equals("true");
350:                    else if (ident.equals("CharacterSet"))
351:                        CharacterSet = tok.nextToken("\u00ff").substring(1);
352:                    else if (ident.equals("FontBBox")) {
353:                        llx = (int) Float.parseFloat(tok.nextToken());
354:                        lly = (int) Float.parseFloat(tok.nextToken());
355:                        urx = (int) Float.parseFloat(tok.nextToken());
356:                        ury = (int) Float.parseFloat(tok.nextToken());
357:                    } else if (ident.equals("UnderlinePosition"))
358:                        UnderlinePosition = (int) Float.parseFloat(tok
359:                                .nextToken());
360:                    else if (ident.equals("UnderlineThickness"))
361:                        UnderlineThickness = (int) Float.parseFloat(tok
362:                                .nextToken());
363:                    else if (ident.equals("EncodingScheme"))
364:                        EncodingScheme = tok.nextToken("\u00ff").substring(1);
365:                    else if (ident.equals("CapHeight"))
366:                        CapHeight = (int) Float.parseFloat(tok.nextToken());
367:                    else if (ident.equals("XHeight"))
368:                        XHeight = (int) Float.parseFloat(tok.nextToken());
369:                    else if (ident.equals("Ascender"))
370:                        Ascender = (int) Float.parseFloat(tok.nextToken());
371:                    else if (ident.equals("Descender"))
372:                        Descender = (int) Float.parseFloat(tok.nextToken());
373:                    else if (ident.equals("StdHW"))
374:                        StdHW = (int) Float.parseFloat(tok.nextToken());
375:                    else if (ident.equals("StdVW"))
376:                        StdVW = (int) Float.parseFloat(tok.nextToken());
377:                    else if (ident.equals("StartCharMetrics")) {
378:                        isMetrics = true;
379:                        break;
380:                    }
381:                }
382:                if (!isMetrics)
383:                    throw new DocumentException("Missing StartCharMetrics in "
384:                            + fileName);
385:                while ((line = rf.readLine()) != null) {
386:                    StringTokenizer tok = new StringTokenizer(line);
387:                    if (!tok.hasMoreTokens())
388:                        continue;
389:                    String ident = tok.nextToken();
390:                    if (ident.equals("EndCharMetrics")) {
391:                        isMetrics = false;
392:                        break;
393:                    }
394:                    Integer C = new Integer(-1);
395:                    Integer WX = new Integer(250);
396:                    String N = "";
397:                    int B[] = null;
398:
399:                    tok = new StringTokenizer(line, ";");
400:                    while (tok.hasMoreTokens()) {
401:                        StringTokenizer tokc = new StringTokenizer(tok
402:                                .nextToken());
403:                        if (!tokc.hasMoreTokens())
404:                            continue;
405:                        ident = tokc.nextToken();
406:                        if (ident.equals("C"))
407:                            C = Integer.valueOf(tokc.nextToken());
408:                        else if (ident.equals("WX"))
409:                            WX = new Integer((int) Float.parseFloat(tokc
410:                                    .nextToken()));
411:                        else if (ident.equals("N"))
412:                            N = tokc.nextToken();
413:                        else if (ident.equals("B")) {
414:                            B = new int[] { Integer.parseInt(tokc.nextToken()),
415:                                    Integer.parseInt(tokc.nextToken()),
416:                                    Integer.parseInt(tokc.nextToken()),
417:                                    Integer.parseInt(tokc.nextToken()) };
418:                        }
419:                    }
420:                    Object metrics[] = new Object[] { C, WX, N, B };
421:                    if (C.intValue() >= 0)
422:                        CharMetrics.put(C, metrics);
423:                    CharMetrics.put(N, metrics);
424:                }
425:                if (isMetrics)
426:                    throw new DocumentException("Missing EndCharMetrics in "
427:                            + fileName);
428:                if (!CharMetrics.containsKey("nonbreakingspace")) {
429:                    Object[] space = (Object[]) CharMetrics.get("space");
430:                    if (space != null)
431:                        CharMetrics.put("nonbreakingspace", space);
432:                }
433:                while ((line = rf.readLine()) != null) {
434:                    StringTokenizer tok = new StringTokenizer(line);
435:                    if (!tok.hasMoreTokens())
436:                        continue;
437:                    String ident = tok.nextToken();
438:                    if (ident.equals("EndFontMetrics"))
439:                        return;
440:                    if (ident.equals("StartKernPairs")) {
441:                        isMetrics = true;
442:                        break;
443:                    }
444:                }
445:                if (!isMetrics)
446:                    throw new DocumentException("Missing EndFontMetrics in "
447:                            + fileName);
448:                while ((line = rf.readLine()) != null) {
449:                    StringTokenizer tok = new StringTokenizer(line);
450:                    if (!tok.hasMoreTokens())
451:                        continue;
452:                    String ident = tok.nextToken();
453:                    if (ident.equals("KPX")) {
454:                        String first = tok.nextToken();
455:                        String second = tok.nextToken();
456:                        Integer width = new Integer((int) Float.parseFloat(tok
457:                                .nextToken()));
458:                        Object relates[] = (Object[]) KernPairs.get(first);
459:                        if (relates == null)
460:                            KernPairs
461:                                    .put(first, new Object[] { second, width });
462:                        else {
463:                            int n = relates.length;
464:                            Object relates2[] = new Object[n + 2];
465:                            System.arraycopy(relates, 0, relates2, 0, n);
466:                            relates2[n] = second;
467:                            relates2[n + 1] = width;
468:                            KernPairs.put(first, relates2);
469:                        }
470:                    } else if (ident.equals("EndKernPairs")) {
471:                        isMetrics = false;
472:                        break;
473:                    }
474:                }
475:                if (isMetrics)
476:                    throw new DocumentException("Missing EndKernPairs in "
477:                            + fileName);
478:                rf.close();
479:            }
480:
481:            /** If the embedded flag is <CODE>false</CODE> or if the font is
482:             *  one of the 14 built in types, it returns <CODE>null</CODE>,
483:             * otherwise the font is read and output in a PdfStream object.
484:             * @return the PdfStream containing the font or <CODE>null</CODE>
485:             * @throws DocumentException if there is an error reading the font
486:             */
487:            private PdfStream getFontStream() throws DocumentException {
488:                if (builtinFont || !embedded)
489:                    return null;
490:                RandomAccessFileOrArray rf = null;
491:                try {
492:                    String filePfb = fileName.substring(0,
493:                            fileName.length() - 3)
494:                            + "pfb";
495:                    if (pfb == null)
496:                        rf = new RandomAccessFileOrArray(filePfb);
497:                    else
498:                        rf = new RandomAccessFileOrArray(pfb);
499:                    int fileLength = rf.length();
500:                    byte st[] = new byte[fileLength - 18];
501:                    int lengths[] = new int[3];
502:                    int bytePtr = 0;
503:                    for (int k = 0; k < 3; ++k) {
504:                        if (rf.read() != 0x80)
505:                            throw new DocumentException(
506:                                    "Start marker missing in " + filePfb);
507:                        if (rf.read() != PFB_TYPES[k])
508:                            throw new DocumentException(
509:                                    "Incorrect segment type in " + filePfb);
510:                        int size = rf.read();
511:                        size += rf.read() << 8;
512:                        size += rf.read() << 16;
513:                        size += rf.read() << 24;
514:                        lengths[k] = size;
515:                        while (size != 0) {
516:                            int got = rf.read(st, bytePtr, size);
517:                            if (got < 0)
518:                                throw new DocumentException("Premature end in "
519:                                        + filePfb);
520:                            bytePtr += got;
521:                            size -= got;
522:                        }
523:                    }
524:                    return new StreamFont(st, lengths);
525:                } catch (Exception e) {
526:                    throw new DocumentException(e);
527:                } finally {
528:                    if (rf != null) {
529:                        try {
530:                            rf.close();
531:                        } catch (Exception e) {
532:                            // empty on purpose
533:                        }
534:                    }
535:                }
536:            }
537:
538:            /** Generates the font descriptor for this font or <CODE>null</CODE> if it is
539:             * one of the 14 built in fonts.
540:             * @param fontStream the indirect reference to a PdfStream containing the font or <CODE>null</CODE>
541:             * @return the PdfDictionary containing the font descriptor or <CODE>null</CODE>
542:             */
543:            private PdfDictionary getFontDescriptor(
544:                    PdfIndirectReference fontStream) {
545:                if (builtinFont)
546:                    return null;
547:                PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR);
548:                dic.put(PdfName.ASCENT, new PdfNumber(Ascender));
549:                dic.put(PdfName.CAPHEIGHT, new PdfNumber(CapHeight));
550:                dic.put(PdfName.DESCENT, new PdfNumber(Descender));
551:                dic.put(PdfName.FONTBBOX, new PdfRectangle(llx, lly, urx, ury));
552:                dic.put(PdfName.FONTNAME, new PdfName(FontName));
553:                dic.put(PdfName.ITALICANGLE, new PdfNumber(ItalicAngle));
554:                dic.put(PdfName.STEMV, new PdfNumber(StdVW));
555:                if (fontStream != null)
556:                    dic.put(PdfName.FONTFILE, fontStream);
557:                int flags = 0;
558:                if (IsFixedPitch)
559:                    flags |= 1;
560:                flags |= fontSpecific ? 4 : 32;
561:                if (ItalicAngle < 0)
562:                    flags |= 64;
563:                if (FontName.indexOf("Caps") >= 0 || FontName.endsWith("SC"))
564:                    flags |= 131072;
565:                if (Weight.equals("Bold"))
566:                    flags |= 262144;
567:                dic.put(PdfName.FLAGS, new PdfNumber(flags));
568:
569:                return dic;
570:            }
571:
572:            /** Generates the font dictionary for this font.
573:             * @return the PdfDictionary containing the font dictionary
574:             * @param firstChar the first valid character
575:             * @param lastChar the last valid character
576:             * @param shortTag a 256 bytes long <CODE>byte</CODE> array where each unused byte is represented by 0
577:             * @param fontDescriptor the indirect reference to a PdfDictionary containing the font descriptor or <CODE>null</CODE>
578:             */
579:            private PdfDictionary getFontBaseType(
580:                    PdfIndirectReference fontDescriptor, int firstChar,
581:                    int lastChar, byte shortTag[]) {
582:                PdfDictionary dic = new PdfDictionary(PdfName.FONT);
583:                dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
584:                dic.put(PdfName.BASEFONT, new PdfName(FontName));
585:                boolean stdEncoding = encoding.equals("Cp1252")
586:                        || encoding.equals("MacRoman");
587:                if (!fontSpecific || specialMap != null) {
588:                    for (int k = firstChar; k <= lastChar; ++k) {
589:                        if (!differences[k].equals(notdef)) {
590:                            firstChar = k;
591:                            break;
592:                        }
593:                    }
594:                    if (stdEncoding)
595:                        dic
596:                                .put(
597:                                        PdfName.ENCODING,
598:                                        encoding.equals("Cp1252") ? PdfName.WIN_ANSI_ENCODING
599:                                                : PdfName.MAC_ROMAN_ENCODING);
600:                    else {
601:                        PdfDictionary enc = new PdfDictionary(PdfName.ENCODING);
602:                        PdfArray dif = new PdfArray();
603:                        boolean gap = true;
604:                        for (int k = firstChar; k <= lastChar; ++k) {
605:                            if (shortTag[k] != 0) {
606:                                if (gap) {
607:                                    dif.add(new PdfNumber(k));
608:                                    gap = false;
609:                                }
610:                                dif.add(new PdfName(differences[k]));
611:                            } else
612:                                gap = true;
613:                        }
614:                        enc.put(PdfName.DIFFERENCES, dif);
615:                        dic.put(PdfName.ENCODING, enc);
616:                    }
617:                }
618:                if (specialMap != null || forceWidthsOutput
619:                        || !(builtinFont && (fontSpecific || stdEncoding))) {
620:                    dic.put(PdfName.FIRSTCHAR, new PdfNumber(firstChar));
621:                    dic.put(PdfName.LASTCHAR, new PdfNumber(lastChar));
622:                    PdfArray wd = new PdfArray();
623:                    for (int k = firstChar; k <= lastChar; ++k) {
624:                        if (shortTag[k] == 0)
625:                            wd.add(new PdfNumber(0));
626:                        else
627:                            wd.add(new PdfNumber(widths[k]));
628:                    }
629:                    dic.put(PdfName.WIDTHS, wd);
630:                }
631:                if (!builtinFont && fontDescriptor != null)
632:                    dic.put(PdfName.FONTDESCRIPTOR, fontDescriptor);
633:                return dic;
634:            }
635:
636:            /** Outputs to the writer the font dictionaries and streams.
637:             * @param writer the writer for this document
638:             * @param ref the font indirect reference
639:             * @param params several parameters that depend on the font type
640:             * @throws IOException on error
641:             * @throws DocumentException error in generating the object
642:             */
643:            void writeFont(PdfWriter writer, PdfIndirectReference ref,
644:                    Object params[]) throws DocumentException, IOException {
645:                int firstChar = ((Integer) params[0]).intValue();
646:                int lastChar = ((Integer) params[1]).intValue();
647:                byte shortTag[] = (byte[]) params[2];
648:                boolean subsetp = ((Boolean) params[3]).booleanValue()
649:                        && subset;
650:                if (!subsetp) {
651:                    firstChar = 0;
652:                    lastChar = shortTag.length - 1;
653:                    for (int k = 0; k < shortTag.length; ++k)
654:                        shortTag[k] = 1;
655:                }
656:                PdfIndirectReference ind_font = null;
657:                PdfObject pobj = null;
658:                PdfIndirectObject obj = null;
659:                pobj = getFontStream();
660:                if (pobj != null) {
661:                    obj = writer.addToBody(pobj);
662:                    ind_font = obj.getIndirectReference();
663:                }
664:                pobj = getFontDescriptor(ind_font);
665:                if (pobj != null) {
666:                    obj = writer.addToBody(pobj);
667:                    ind_font = obj.getIndirectReference();
668:                }
669:                pobj = getFontBaseType(ind_font, firstChar, lastChar, shortTag);
670:                writer.addToBody(pobj, ref);
671:            }
672:
673:            /** Gets the font parameter identified by <CODE>key</CODE>. Valid values
674:             * for <CODE>key</CODE> are <CODE>ASCENT</CODE>, <CODE>CAPHEIGHT</CODE>, <CODE>DESCENT</CODE>,
675:             * <CODE>ITALICANGLE</CODE>, <CODE>BBOXLLX</CODE>, <CODE>BBOXLLY</CODE>, <CODE>BBOXURX</CODE>
676:             * and <CODE>BBOXURY</CODE>.
677:             * @param key the parameter to be extracted
678:             * @param fontSize the font size in points
679:             * @return the parameter in points
680:             */
681:            public float getFontDescriptor(int key, float fontSize) {
682:                switch (key) {
683:                case AWT_ASCENT:
684:                case ASCENT:
685:                    return Ascender * fontSize / 1000;
686:                case CAPHEIGHT:
687:                    return CapHeight * fontSize / 1000;
688:                case AWT_DESCENT:
689:                case DESCENT:
690:                    return Descender * fontSize / 1000;
691:                case ITALICANGLE:
692:                    return ItalicAngle;
693:                case BBOXLLX:
694:                    return llx * fontSize / 1000;
695:                case BBOXLLY:
696:                    return lly * fontSize / 1000;
697:                case BBOXURX:
698:                    return urx * fontSize / 1000;
699:                case BBOXURY:
700:                    return ury * fontSize / 1000;
701:                case AWT_LEADING:
702:                    return 0;
703:                case AWT_MAXADVANCE:
704:                    return (urx - llx) * fontSize / 1000;
705:                }
706:                return 0;
707:            }
708:
709:            /** Gets the postscript font name.
710:             * @return the postscript font name
711:             */
712:            public String getPostscriptFontName() {
713:                return FontName;
714:            }
715:
716:            /** Gets the full name of the font. If it is a True Type font
717:             * each array element will have {Platform ID, Platform Encoding ID,
718:             * Language ID, font name}. The interpretation of this values can be
719:             * found in the Open Type specification, chapter 2, in the 'name' table.<br>
720:             * For the other fonts the array has a single element with {"", "", "",
721:             * font name}.
722:             * @return the full name of the font
723:             */
724:            public String[][] getFullFontName() {
725:                return new String[][] { { "", "", "", FullName } };
726:            }
727:
728:            /** Gets the family name of the font. If it is a True Type font
729:             * each array element will have {Platform ID, Platform Encoding ID,
730:             * Language ID, font name}. The interpretation of this values can be
731:             * found in the Open Type specification, chapter 2, in the 'name' table.<br>
732:             * For the other fonts the array has a single element with {"", "", "",
733:             * font name}.
734:             * @return the family name of the font
735:             */
736:            public String[][] getFamilyFontName() {
737:                return new String[][] { { "", "", "", FamilyName } };
738:            }
739:
740:            /** Checks if the font has any kerning pairs.
741:             * @return <CODE>true</CODE> if the font has any kerning pairs
742:             */
743:            public boolean hasKernPairs() {
744:                return !KernPairs.isEmpty();
745:            }
746:
747:            /**
748:             * Sets the font name that will appear in the pdf font dictionary.
749:             * Use with care as it can easily make a font unreadable if not embedded.
750:             * @param name the new font name
751:             */
752:            public void setPostscriptFontName(String name) {
753:                FontName = name;
754:            }
755:
756:            /**
757:             * Sets the kerning between two Unicode chars.
758:             * @param char1 the first char
759:             * @param char2 the second char
760:             * @param kern the kerning to apply in normalized 1000 units
761:             * @return <code>true</code> if the kerning was applied, <code>false</code> otherwise
762:             */
763:            public boolean setKerning(char char1, char char2, int kern) {
764:                String first = GlyphList.unicodeToName((int) char1);
765:                if (first == null)
766:                    return false;
767:                String second = GlyphList.unicodeToName((int) char2);
768:                if (second == null)
769:                    return false;
770:                Object obj[] = (Object[]) KernPairs.get(first);
771:                if (obj == null) {
772:                    obj = new Object[] { second, new Integer(kern) };
773:                    KernPairs.put(first, obj);
774:                    return true;
775:                }
776:                for (int k = 0; k < obj.length; k += 2) {
777:                    if (second.equals(obj[k])) {
778:                        obj[k + 1] = new Integer(kern);
779:                        return true;
780:                    }
781:                }
782:                int size = obj.length;
783:                Object obj2[] = new Object[size + 2];
784:                System.arraycopy(obj, 0, obj2, 0, size);
785:                obj2[size] = second;
786:                obj2[size + 1] = new Integer(kern);
787:                KernPairs.put(first, obj2);
788:                return true;
789:            }
790:
791:            protected int[] getRawCharBBox(int c, String name) {
792:                Object metrics[];
793:                if (name == null) { // font specific
794:                    metrics = (Object[]) CharMetrics.get(new Integer(c));
795:                } else {
796:                    if (name.equals(".notdef"))
797:                        return null;
798:                    metrics = (Object[]) CharMetrics.get(name);
799:                }
800:                if (metrics != null)
801:                    return ((int[]) (metrics[3]));
802:                return null;
803:            }
804:
805:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.