Source Code Cross Referenced for TrueTypeFontSubSet.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: TrueTypeFontSubSet.java 2366 2006-09-14 23:10:58Z xlv $
003:         * $Name$
004:         *
005:         * Copyright 2001, 2002 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.IOException;
054:        import java.util.ArrayList;
055:        import java.util.Arrays;
056:        import java.util.HashMap;
057:
058:        import com.lowagie.text.DocumentException;
059:        import com.lowagie.text.ExceptionConverter;
060:
061:        /** Subsets a True Type font by removing the unneeded glyphs from
062:         * the font.
063:         *
064:         * @author  Paulo Soares (psoares@consiste.pt)
065:         */
066:        class TrueTypeFontSubSet {
067:            static final String tableNamesSimple[] = { "cvt ", "fpgm", "glyf",
068:                    "head", "hhea", "hmtx", "loca", "maxp", "prep" };
069:            static final String tableNamesCmap[] = { "cmap", "cvt ", "fpgm",
070:                    "glyf", "head", "hhea", "hmtx", "loca", "maxp", "prep" };
071:            static final String tableNamesExtra[] = { "OS/2", "cmap", "cvt ",
072:                    "fpgm", "glyf", "head", "hhea", "hmtx", "loca", "maxp",
073:                    "name, prep" };
074:            static final int entrySelectors[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3,
075:                    3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 };
076:            static final int TABLE_CHECKSUM = 0;
077:            static final int TABLE_OFFSET = 1;
078:            static final int TABLE_LENGTH = 2;
079:            static final int HEAD_LOCA_FORMAT_OFFSET = 51;
080:
081:            static final int ARG_1_AND_2_ARE_WORDS = 1;
082:            static final int WE_HAVE_A_SCALE = 8;
083:            static final int MORE_COMPONENTS = 32;
084:            static final int WE_HAVE_AN_X_AND_Y_SCALE = 64;
085:            static final int WE_HAVE_A_TWO_BY_TWO = 128;
086:
087:            /** Contains the location of the several tables. The key is the name of
088:             * the table and the value is an <CODE>int[3]</CODE> where position 0
089:             * is the checksum, position 1 is the offset from the start of the file
090:             * and position 2 is the length of the table.
091:             */
092:            protected HashMap tableDirectory;
093:            /** The file in use.
094:             */
095:            protected RandomAccessFileOrArray rf;
096:            /** The file name.
097:             */
098:            protected String fileName;
099:            protected boolean includeCmap;
100:            protected boolean includeExtras;
101:            protected boolean locaShortTable;
102:            protected int locaTable[];
103:            protected HashMap glyphsUsed;
104:            protected ArrayList glyphsInList;
105:            protected int tableGlyphOffset;
106:            protected int newLocaTable[];
107:            protected byte newLocaTableOut[];
108:            protected byte newGlyfTable[];
109:            protected int glyfTableRealSize;
110:            protected int locaTableRealSize;
111:            protected byte outFont[];
112:            protected int fontPtr;
113:            protected int directoryOffset;
114:
115:            /** Creates a new TrueTypeFontSubSet
116:             * @param directoryOffset The offset from the start of the file to the table directory
117:             * @param fileName the file name of the font
118:             * @param glyphsUsed the glyphs used
119:             * @param includeCmap <CODE>true</CODE> if the table cmap is to be included in the generated font
120:             */
121:            TrueTypeFontSubSet(String fileName, RandomAccessFileOrArray rf,
122:                    HashMap glyphsUsed, int directoryOffset,
123:                    boolean includeCmap, boolean includeExtras) {
124:                this .fileName = fileName;
125:                this .rf = rf;
126:                this .glyphsUsed = glyphsUsed;
127:                this .includeCmap = includeCmap;
128:                this .includeExtras = includeExtras;
129:                this .directoryOffset = directoryOffset;
130:                glyphsInList = new ArrayList(glyphsUsed.keySet());
131:            }
132:
133:            /** Does the actual work of subsetting the font.
134:             * @throws IOException on error
135:             * @throws DocumentException on error
136:             * @return the subset font
137:             */
138:            byte[] process() throws IOException, DocumentException {
139:                try {
140:                    rf.reOpen();
141:                    createTableDirectory();
142:                    readLoca();
143:                    flatGlyphs();
144:                    createNewGlyphTables();
145:                    locaTobytes();
146:                    assembleFont();
147:                    return outFont;
148:                } finally {
149:                    try {
150:                        rf.close();
151:                    } catch (Exception e) {
152:                        // empty on purpose
153:                    }
154:                }
155:            }
156:
157:            protected void assembleFont() throws IOException {
158:                int tableLocation[];
159:                int fullFontSize = 0;
160:                String tableNames[];
161:                if (includeExtras)
162:                    tableNames = tableNamesExtra;
163:                else {
164:                    if (includeCmap)
165:                        tableNames = tableNamesCmap;
166:                    else
167:                        tableNames = tableNamesSimple;
168:                }
169:                int tablesUsed = 2;
170:                int len = 0;
171:                for (int k = 0; k < tableNames.length; ++k) {
172:                    String name = tableNames[k];
173:                    if (name.equals("glyf") || name.equals("loca"))
174:                        continue;
175:                    tableLocation = (int[]) tableDirectory.get(name);
176:                    if (tableLocation == null)
177:                        continue;
178:                    ++tablesUsed;
179:                    fullFontSize += (tableLocation[TABLE_LENGTH] + 3) & (~3);
180:                }
181:                fullFontSize += newLocaTableOut.length;
182:                fullFontSize += newGlyfTable.length;
183:                int ref = 16 * tablesUsed + 12;
184:                fullFontSize += ref;
185:                outFont = new byte[fullFontSize];
186:                fontPtr = 0;
187:                writeFontInt(0x00010000);
188:                writeFontShort(tablesUsed);
189:                int selector = entrySelectors[tablesUsed];
190:                writeFontShort((1 << selector) * 16);
191:                writeFontShort(selector);
192:                writeFontShort((tablesUsed - (1 << selector)) * 16);
193:                for (int k = 0; k < tableNames.length; ++k) {
194:                    String name = tableNames[k];
195:                    tableLocation = (int[]) tableDirectory.get(name);
196:                    if (tableLocation == null)
197:                        continue;
198:                    writeFontString(name);
199:                    if (name.equals("glyf")) {
200:                        writeFontInt(calculateChecksum(newGlyfTable));
201:                        len = glyfTableRealSize;
202:                    } else if (name.equals("loca")) {
203:                        writeFontInt(calculateChecksum(newLocaTableOut));
204:                        len = locaTableRealSize;
205:                    } else {
206:                        writeFontInt(tableLocation[TABLE_CHECKSUM]);
207:                        len = tableLocation[TABLE_LENGTH];
208:                    }
209:                    writeFontInt(ref);
210:                    writeFontInt(len);
211:                    ref += (len + 3) & (~3);
212:                }
213:                for (int k = 0; k < tableNames.length; ++k) {
214:                    String name = tableNames[k];
215:                    tableLocation = (int[]) tableDirectory.get(name);
216:                    if (tableLocation == null)
217:                        continue;
218:                    if (name.equals("glyf")) {
219:                        System.arraycopy(newGlyfTable, 0, outFont, fontPtr,
220:                                newGlyfTable.length);
221:                        fontPtr += newGlyfTable.length;
222:                        newGlyfTable = null;
223:                    } else if (name.equals("loca")) {
224:                        System.arraycopy(newLocaTableOut, 0, outFont, fontPtr,
225:                                newLocaTableOut.length);
226:                        fontPtr += newLocaTableOut.length;
227:                        newLocaTableOut = null;
228:                    } else {
229:                        rf.seek(tableLocation[TABLE_OFFSET]);
230:                        rf.readFully(outFont, fontPtr,
231:                                tableLocation[TABLE_LENGTH]);
232:                        fontPtr += (tableLocation[TABLE_LENGTH] + 3) & (~3);
233:                    }
234:                }
235:            }
236:
237:            protected void createTableDirectory() throws IOException,
238:                    DocumentException {
239:                tableDirectory = new HashMap();
240:                rf.seek(directoryOffset);
241:                int id = rf.readInt();
242:                if (id != 0x00010000)
243:                    throw new DocumentException(fileName
244:                            + " is not a true type file.");
245:                int num_tables = rf.readUnsignedShort();
246:                rf.skipBytes(6);
247:                for (int k = 0; k < num_tables; ++k) {
248:                    String tag = readStandardString(4);
249:                    int tableLocation[] = new int[3];
250:                    tableLocation[TABLE_CHECKSUM] = rf.readInt();
251:                    tableLocation[TABLE_OFFSET] = rf.readInt();
252:                    tableLocation[TABLE_LENGTH] = rf.readInt();
253:                    tableDirectory.put(tag, tableLocation);
254:                }
255:            }
256:
257:            protected void readLoca() throws IOException, DocumentException {
258:                int tableLocation[];
259:                tableLocation = (int[]) tableDirectory.get("head");
260:                if (tableLocation == null)
261:                    throw new DocumentException(
262:                            "Table 'head' does not exist in " + fileName);
263:                rf.seek(tableLocation[TABLE_OFFSET] + HEAD_LOCA_FORMAT_OFFSET);
264:                locaShortTable = (rf.readUnsignedShort() == 0);
265:                tableLocation = (int[]) tableDirectory.get("loca");
266:                if (tableLocation == null)
267:                    throw new DocumentException(
268:                            "Table 'loca' does not exist in " + fileName);
269:                rf.seek(tableLocation[TABLE_OFFSET]);
270:                if (locaShortTable) {
271:                    int entries = tableLocation[TABLE_LENGTH] / 2;
272:                    locaTable = new int[entries];
273:                    for (int k = 0; k < entries; ++k)
274:                        locaTable[k] = rf.readUnsignedShort() * 2;
275:                } else {
276:                    int entries = tableLocation[TABLE_LENGTH] / 4;
277:                    locaTable = new int[entries];
278:                    for (int k = 0; k < entries; ++k)
279:                        locaTable[k] = rf.readInt();
280:                }
281:            }
282:
283:            protected void createNewGlyphTables() throws IOException {
284:                newLocaTable = new int[locaTable.length];
285:                int activeGlyphs[] = new int[glyphsInList.size()];
286:                for (int k = 0; k < activeGlyphs.length; ++k)
287:                    activeGlyphs[k] = ((Integer) glyphsInList.get(k))
288:                            .intValue();
289:                Arrays.sort(activeGlyphs);
290:                int glyfSize = 0;
291:                for (int k = 0; k < activeGlyphs.length; ++k) {
292:                    int glyph = activeGlyphs[k];
293:                    glyfSize += locaTable[glyph + 1] - locaTable[glyph];
294:                }
295:                glyfTableRealSize = glyfSize;
296:                glyfSize = (glyfSize + 3) & (~3);
297:                newGlyfTable = new byte[glyfSize];
298:                int glyfPtr = 0;
299:                int listGlyf = 0;
300:                for (int k = 0; k < newLocaTable.length; ++k) {
301:                    newLocaTable[k] = glyfPtr;
302:                    if (listGlyf < activeGlyphs.length
303:                            && activeGlyphs[listGlyf] == k) {
304:                        ++listGlyf;
305:                        newLocaTable[k] = glyfPtr;
306:                        int start = locaTable[k];
307:                        int len = locaTable[k + 1] - start;
308:                        if (len > 0) {
309:                            rf.seek(tableGlyphOffset + start);
310:                            rf.readFully(newGlyfTable, glyfPtr, len);
311:                            glyfPtr += len;
312:                        }
313:                    }
314:                }
315:            }
316:
317:            protected void locaTobytes() {
318:                if (locaShortTable)
319:                    locaTableRealSize = newLocaTable.length * 2;
320:                else
321:                    locaTableRealSize = newLocaTable.length * 4;
322:                newLocaTableOut = new byte[(locaTableRealSize + 3) & (~3)];
323:                outFont = newLocaTableOut;
324:                fontPtr = 0;
325:                for (int k = 0; k < newLocaTable.length; ++k) {
326:                    if (locaShortTable)
327:                        writeFontShort(newLocaTable[k] / 2);
328:                    else
329:                        writeFontInt(newLocaTable[k]);
330:                }
331:
332:            }
333:
334:            protected void flatGlyphs() throws IOException, DocumentException {
335:                int tableLocation[];
336:                tableLocation = (int[]) tableDirectory.get("glyf");
337:                if (tableLocation == null)
338:                    throw new DocumentException(
339:                            "Table 'glyf' does not exist in " + fileName);
340:                Integer glyph0 = new Integer(0);
341:                if (!glyphsUsed.containsKey(glyph0)) {
342:                    glyphsUsed.put(glyph0, null);
343:                    glyphsInList.add(glyph0);
344:                }
345:                tableGlyphOffset = tableLocation[TABLE_OFFSET];
346:                for (int k = 0; k < glyphsInList.size(); ++k) {
347:                    int glyph = ((Integer) glyphsInList.get(k)).intValue();
348:                    checkGlyphComposite(glyph);
349:                }
350:            }
351:
352:            protected void checkGlyphComposite(int glyph) throws IOException {
353:                int start = locaTable[glyph];
354:                if (start == locaTable[glyph + 1]) // no contour
355:                    return;
356:                rf.seek(tableGlyphOffset + start);
357:                int numContours = rf.readShort();
358:                if (numContours >= 0)
359:                    return;
360:                rf.skipBytes(8);
361:                for (;;) {
362:                    int flags = rf.readUnsignedShort();
363:                    Integer cGlyph = new Integer(rf.readUnsignedShort());
364:                    if (!glyphsUsed.containsKey(cGlyph)) {
365:                        glyphsUsed.put(cGlyph, null);
366:                        glyphsInList.add(cGlyph);
367:                    }
368:                    if ((flags & MORE_COMPONENTS) == 0)
369:                        return;
370:                    int skip;
371:                    if ((flags & ARG_1_AND_2_ARE_WORDS) != 0)
372:                        skip = 4;
373:                    else
374:                        skip = 2;
375:                    if ((flags & WE_HAVE_A_SCALE) != 0)
376:                        skip += 2;
377:                    else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0)
378:                        skip += 4;
379:                    if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0)
380:                        skip += 8;
381:                    rf.skipBytes(skip);
382:                }
383:            }
384:
385:            /** Reads a <CODE>String</CODE> from the font file as bytes using the Cp1252
386:             *  encoding.
387:             * @param length the length of bytes to read
388:             * @return the <CODE>String</CODE> read
389:             * @throws IOException the font file could not be read
390:             */
391:            protected String readStandardString(int length) throws IOException {
392:                byte buf[] = new byte[length];
393:                rf.readFully(buf);
394:                try {
395:                    return new String(buf, BaseFont.WINANSI);
396:                } catch (Exception e) {
397:                    throw new ExceptionConverter(e);
398:                }
399:            }
400:
401:            protected void writeFontShort(int n) {
402:                outFont[fontPtr++] = (byte) (n >> 8);
403:                outFont[fontPtr++] = (byte) (n);
404:            }
405:
406:            protected void writeFontInt(int n) {
407:                outFont[fontPtr++] = (byte) (n >> 24);
408:                outFont[fontPtr++] = (byte) (n >> 16);
409:                outFont[fontPtr++] = (byte) (n >> 8);
410:                outFont[fontPtr++] = (byte) (n);
411:            }
412:
413:            protected void writeFontString(String s) {
414:                byte b[] = PdfEncodings.convertToBytes(s, BaseFont.WINANSI);
415:                System.arraycopy(b, 0, outFont, fontPtr, b.length);
416:                fontPtr += b.length;
417:            }
418:
419:            protected int calculateChecksum(byte b[]) {
420:                int len = b.length / 4;
421:                int v0 = 0;
422:                int v1 = 0;
423:                int v2 = 0;
424:                int v3 = 0;
425:                int ptr = 0;
426:                for (int k = 0; k < len; ++k) {
427:                    v3 += (int) b[ptr++] & 0xff;
428:                    v2 += (int) b[ptr++] & 0xff;
429:                    v1 += (int) b[ptr++] & 0xff;
430:                    v0 += (int) b[ptr++] & 0xff;
431:                }
432:                return v0 + (v1 << 8) + (v2 << 16) + (v3 << 24);
433:            }
434:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.