KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > CFFFont


1 /*
2  *
3  * Copyright 2003 Sivan Toledo
4  *
5  * The contents of this file are subject to the Mozilla Public License Version 1.1
6  * (the "License"); you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the License.
12  *
13  * Contributor(s): all the names of the contributors are added in the source code
14  * where applicable.
15  *
16  * Alternatively, the contents of this file may be used under the terms of the
17  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
18  * provisions of LGPL are applicable instead of those above. If you wish to
19  * allow use of your version of this file only under the terms of the LGPL
20  * License and not to allow others to use your version of this file under
21  * the MPL, indicate your decision by deleting the provisions above and
22  * replace them with the notice and other provisions required by the LGPL.
23  * If you do not delete the provisions above, a recipient may use your version
24  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
25  *
26  * This library is free software; you can redistribute it and/or modify it
27  * under the terms of the MPL as stated above or under the terms of the GNU
28  * Library General Public License as published by the Free Software Foundation;
29  * either version 2 of the License, or any later version.
30  *
31  * This library is distributed in the hope that it will be useful, but WITHOUT
32  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
33  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
34  * details.
35  *
36  */

37
38 /*
39  * Comments by Sivan Toledo:
40  * I created this class in order to add to iText the ability to utilize
41  * OpenType fonts with CFF glyphs (these usually have an .otf extension).
42  * The CFF font within the CFF table of the OT font might be either a CID
43  * or a Type1 font. (CFF fonts may also contain multiple fonts; I do not
44  * know if this is allowed in an OT table). The PDF spec, however, only
45  * allow a CID font with an Identity-H or Identity-V encoding. Otherwise,
46  * you are limited to an 8-bit encoding.
47  * Adobe fonts come in both flavors. That is, the OTFs sometimes have
48  * a CID CFF inside (for Japanese fonts), and sometimes a Type1 CFF
49  * (virtually all the others, Latin/Greek/Cyrillic). So to easily use
50  * all the glyphs in the latter, without creating multiple 8-bit encoding,
51  * I wrote this class, whose main purpose is to convert a Type1 font inside
52  * a CFF container (which might include other fonts) into a CID CFF font
53  * that can be directly embeded in the PDF.
54  *
55  * Limitations of the current version:
56  * 1. It does not extract a single CID font from a CFF that contains that
57  * particular CID along with other fonts. The Adobe Japanese OTF's that
58  * I have only have one font in the CFF table, so these can be
59  * embeded in the PDF as is.
60  * 2. It does not yet subset fonts.
61  * 3. It may or may not work on CFF fonts that are not within OTF's.
62  * I didn't try that. In any case, that would probably only be
63  * useful for subsetting CID fonts, not for CFF Type1 fonts (I don't
64  * think there are any available.
65  * I plan to extend the class to support these three features at some
66  * future time.
67  */

68
69 package com.lowagie.text.pdf;
70
71 import java.util.Iterator JavaDoc;
72 import java.util.LinkedList JavaDoc;
73
74 import com.lowagie.text.ExceptionConverter;
75
76 public class CFFFont {
77     
78     static final String JavaDoc operatorNames[] = {
79         "version", "Notice", "FullName", "FamilyName",
80         "Weight", "FontBBox", "BlueValues", "OtherBlues",
81         "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW",
82         "UNKNOWN_12", "UniqueID", "XUID", "charset",
83         "Encoding", "CharStrings", "Private", "Subrs",
84         "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23",
85         "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27",
86         "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31",
87         "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition",
88         "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix",
89         "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz",
90         "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15",
91         "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
92         "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend",
93         "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27",
94         "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion",
95         "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase",
96         "FDArray", "FDSelect", "FontName"
97     };
98     
99     static final String JavaDoc standardStrings[] = {
100         // Automatically generated from Appendix A of the CFF specification; do
101
// not edit. Size should be 391.
102
".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar",
103         "percent", "ampersand", "quoteright", "parenleft", "parenright",
104         "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
105         "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
106         "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
107         "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
108         "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
109         "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c",
110         "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
111         "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
112         "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen",
113         "florin", "section", "currency", "quotesingle", "quotedblleft",
114         "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash",
115         "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet",
116         "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright",
117         "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex",
118         "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla",
119         "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash",
120         "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe",
121         "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth",
122         "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar",
123         "degree", "thorn", "threequarters", "twosuperior", "registered", "minus",
124         "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex",
125         "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute",
126         "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
127         "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve",
128         "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave",
129         "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis",
130         "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex",
131         "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave",
132         "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde",
133         "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute",
134         "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall",
135         "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall",
136         "parenleftsuperior", "parenrightsuperior", "twodotenleader",
137         "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle",
138         "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle",
139         "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior",
140         "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
141         "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
142         "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior",
143         "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
144         "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
145         "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall",
146         "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall",
147         "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
148         "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary",
149         "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle",
150         "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall",
151         "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
152         "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
153         "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths",
154         "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior",
155         "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
156         "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
157         "threeinferior", "fourinferior", "fiveinferior", "sixinferior",
158         "seveninferior", "eightinferior", "nineinferior", "centinferior",
159         "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
160         "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
161         "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall",
162         "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall",
163         "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
164         "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
165         "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall",
166         "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall",
167         "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black",
168         "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
169     };
170     
171     //private String[] strings;
172
public String JavaDoc getString(char sid) {
173         if (sid < standardStrings.length) return standardStrings[sid];
174         if (sid >= standardStrings.length+(stringOffsets.length-1)) return null;
175         int j = sid - standardStrings.length;
176         //java.lang.System.err.println("going for "+j);
177
int p = getPosition();
178         seek(stringOffsets[j]);
179         StringBuffer JavaDoc s = new StringBuffer JavaDoc();
180         for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) {
181             s.append(getCard8());
182         }
183         seek(p);
184         return s.toString();
185     }
186     
187     char getCard8() {
188         try {
189             byte i = buf.readByte();
190             return (char)(i & 0xff);
191         }
192         catch (Exception JavaDoc e) {
193             throw new ExceptionConverter(e);
194         }
195     }
196     
197     char getCard16() {
198         try {
199             return buf.readChar();
200         }
201         catch (Exception JavaDoc e) {
202             throw new ExceptionConverter(e);
203         }
204     }
205     
206     int getOffset(int offSize) {
207         int offset = 0;
208         for (int i=0; i<offSize; i++) {
209             offset *= 256;
210             offset += getCard8();
211         }
212         return offset;
213     }
214     
215     void seek(int offset) {
216         try {
217             buf.seek(offset);
218         }
219         catch (Exception JavaDoc e) {
220             throw new ExceptionConverter(e);
221         }
222     }
223     
224     short getShort() {
225         try {
226             return buf.readShort();
227         }
228         catch (Exception JavaDoc e) {
229             throw new ExceptionConverter(e);
230         }
231     }
232     
233     int getInt() {
234         try {
235             return buf.readInt();
236         }
237         catch (Exception JavaDoc e) {
238             throw new ExceptionConverter(e);
239         }
240     }
241     
242     int getPosition() {
243         try {
244             return buf.getFilePointer();
245         }
246         catch (Exception JavaDoc e) {
247             throw new ExceptionConverter(e);
248         }
249     }
250     int nextIndexOffset;
251     // read the offsets in the next index
252
// data structure, convert to global
253
// offsets, and return them.
254
// Sets the nextIndexOffset.
255
int[] getIndex(int nextIndexOffset) {
256         int count, indexOffSize;
257         
258         seek(nextIndexOffset);
259         count = getCard16();
260         int[] offsets = new int[count+1];
261         
262         if (count==0) {
263             offsets[0] = -1;
264             nextIndexOffset += 2;
265             return offsets;
266         }
267         
268         indexOffSize = getCard8();
269         
270         for (int j=0; j<=count; j++) {
271             //nextIndexOffset = ofset to relative segment
272
offsets[j] = nextIndexOffset
273             //2-> count in the index header. 1->offset size in index header
274
+ 2+1
275             //offset array size * offset size
276
+ (count+1)*indexOffSize
277             //???zero <-> one base
278
- 1
279             // read object offset relative to object array base
280
+ getOffset(indexOffSize);
281         }
282         //nextIndexOffset = offsets[count];
283
return offsets;
284     }
285     
286     protected String JavaDoc key;
287     protected Object JavaDoc[] args = new Object JavaDoc[48];
288     protected int arg_count = 0;
289     
290     protected void getDictItem() {
291         for (int i=0; i<arg_count; i++) args[i]=null;
292         arg_count = 0;
293         key = null;
294         boolean gotKey = false;
295         
296         while (!gotKey) {
297             char b0 = getCard8();
298             if (b0 == 29) {
299                 int item = getInt();
300                 args[arg_count] = new Integer JavaDoc(item);
301                 arg_count++;
302                 //System.err.println(item+" ");
303
continue;
304             }
305             if (b0 == 28) {
306                 short item = getShort();
307                 args[arg_count] = new Integer JavaDoc(item);
308                 arg_count++;
309                 //System.err.println(item+" ");
310
continue;
311             }
312             if (b0 >= 32 && b0 <= 246) {
313                 byte item = (byte) (b0-139);
314                 args[arg_count] = new Integer JavaDoc(item);
315                 arg_count++;
316                 //System.err.println(item+" ");
317
continue;
318             }
319             if (b0 >= 247 && b0 <= 250) {
320                 char b1 = getCard8();
321                 short item = (short) ((b0-247)*256+b1+108);
322                 args[arg_count] = new Integer JavaDoc(item);
323                 arg_count++;
324                 //System.err.println(item+" ");
325
continue;
326             }
327             if (b0 >= 251 && b0 <= 254) {
328                 char b1 = getCard8();
329                 short item = (short) (-(b0-251)*256-b1-108);
330                 args[arg_count] = new Integer JavaDoc(item);
331                 arg_count++;
332                 //System.err.println(item+" ");
333
continue;
334             }
335             if (b0 == 30) {
336                 String JavaDoc item = "";
337                 boolean done = false;
338                 char buffer = 0;
339                 byte avail = 0;
340                 int nibble = 0;
341                 while (!done) {
342                     // get a nibble
343
if (avail==0) { buffer = getCard8(); avail=2; }
344                     if (avail==1) { nibble = (buffer / 16); avail--; }
345                     if (avail==2) { nibble = (buffer % 16); avail--; }
346                     switch (nibble) {
347                         case 0xa: item += "." ; break;
348                         case 0xb: item += "E" ; break;
349                         case 0xc: item += "E-"; break;
350                         case 0xe: item += "-" ; break;
351                         case 0xf: done=true ; break;
352                         default:
353                             if (nibble >= 0 && nibble <= 9)
354                                 item += String.valueOf(nibble);
355                             else {
356                                 item += "<NIBBLE ERROR: " + nibble + '>';
357                                 done = true;
358                             }
359                             break;
360                     }
361                 }
362                 args[arg_count] = item;
363                 arg_count++;
364                 //System.err.println(" real=["+item+"]");
365
continue;
366             }
367             if (b0 <= 21) {
368                 gotKey=true;
369                 if (b0 != 12) key = operatorNames[b0];
370                 else key = operatorNames[32 + getCard8()];
371                 //for (int i=0; i<arg_count; i++)
372
// System.err.print(args[i].toString()+" ");
373
//System.err.println(key+" ;");
374
continue;
375             }
376         }
377     }
378     
379     /** List items for the linked list that builds the new CID font.
380      */

381     
382     protected static abstract class Item {
383         protected int myOffset = -1;
384         /** remember the current offset and increment by item's size in bytes. */
385         public void increment(int[] currentOffset) {
386             myOffset = currentOffset[0];
387         }
388         /** Emit the byte stream for this item. */
389         public void emit(byte[] buffer) {}
390         /** Fix up cross references to this item (applies only to markers). */
391         public void xref() {}
392     }
393     
394     protected static abstract class OffsetItem extends Item {
395         public int value;
396         /** set the value of an offset item that was initially unknown.
397          * It will be fixed up latex by a call to xref on some marker.
398          */

399         public void set(int offset) { this.value = offset; }
400     }
401     
402     
403     /** A range item.
404      */

405     
406     protected static final class RangeItem extends Item {
407         public int offset, length;
408         private RandomAccessFileOrArray buf;
409         public RangeItem(RandomAccessFileOrArray buf, int offset, int length) {
410             this.offset = offset;
411             this.length = length;
412             this.buf = buf;
413         }
414         public void increment(int[] currentOffset) {
415             super.increment(currentOffset);
416             currentOffset[0] += length;
417         }
418         public void emit(byte[] buffer) {
419             //System.err.println("range emit offset "+offset+" size="+length);
420
try {
421                 buf.seek(offset);
422                 for (int i=myOffset; i<myOffset+length; i++)
423                     buffer[i] = buf.readByte();
424             }
425             catch (Exception JavaDoc e) {
426                 throw new ExceptionConverter(e);
427             }
428             //System.err.println("finished range emit");
429
}
430     }
431     
432     /** An index-offset item for the list.
433      * The size denotes the required size in the CFF. A positive
434      * value means that we need a specific size in bytes (for offset arrays)
435      * and a negative value means that this is a dict item that uses a
436      * variable-size representation.
437      */

438     static protected final class IndexOffsetItem extends OffsetItem {
439         public final int size;
440         public IndexOffsetItem(int size, int value) {this.size=size; this.value=value;}
441         public IndexOffsetItem(int size) {this.size=size; }
442         
443         public void increment(int[] currentOffset) {
444             super.increment(currentOffset);
445             currentOffset[0] += size;
446         }
447         public void emit(byte[] buffer) {
448             int i=0;
449             switch (size) {
450                 case 4:
451                     buffer[myOffset+i] = (byte) ((value >>> 24) & 0xff);
452                     i++;
453                 case 3:
454                     buffer[myOffset+i] = (byte) ((value >>> 16) & 0xff);
455                     i++;
456                 case 2:
457                     buffer[myOffset+i] = (byte) ((value >>> 8) & 0xff);
458                     i++;
459                 case 1:
460                     buffer[myOffset+i] = (byte) ((value >>> 0) & 0xff);
461                     i++;
462             }
463             /*
464             int mask = 0xff;
465             for (int i=size-1; i>=0; i--) {
466                 buffer[myOffset+i] = (byte) (value & mask);
467                 mask <<= 8;
468             }
469              */

470         }
471     }
472     
473     static protected final class IndexBaseItem extends Item {
474         public IndexBaseItem() {}
475     }
476     
477     static protected final class IndexMarkerItem extends Item {
478         private OffsetItem offItem;
479         private IndexBaseItem indexBase;
480         public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) {
481             this.offItem = offItem;
482             this.indexBase = indexBase;
483         }
484         public void xref() {
485             //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
486
offItem.set(this.myOffset-indexBase.myOffset+1);
487         }
488     }
489     /**
490      * TODO To change the template for this generated type comment go to
491      * Window - Preferences - Java - Code Generation - Code and Comments
492      */

493     static protected final class SubrMarkerItem extends Item {
494         private OffsetItem offItem;
495         private IndexBaseItem indexBase;
496         public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) {
497             this.offItem = offItem;
498             this.indexBase = indexBase;
499         }
500         public void xref() {
501             //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
502
offItem.set(this.myOffset-indexBase.myOffset);
503         }
504     }
505     
506     
507     /** an unknown offset in a dictionary for the list.
508      * We will fix up the offset later; for now, assume it's large.
509      */

510     static protected final class DictOffsetItem extends OffsetItem {
511         public final int size;
512         public DictOffsetItem() {this.size=5; }
513         
514         public void increment(int[] currentOffset) {
515             super.increment(currentOffset);
516             currentOffset[0] += size;
517         }
518         // this is incomplete!
519
public void emit(byte[] buffer) {
520             if (size==5) {
521                 buffer[myOffset] = 29;
522                 buffer[myOffset+1] = (byte) ((value >>> 24) & 0xff);
523                 buffer[myOffset+2] = (byte) ((value >>> 16) & 0xff);
524                 buffer[myOffset+3] = (byte) ((value >>> 8) & 0xff);
525                 buffer[myOffset+4] = (byte) ((value >>> 0) & 0xff);
526             }
527         }
528     }
529     
530     /** Card24 item.
531      */

532     
533     static protected final class UInt24Item extends Item {
534         public int value;
535         public UInt24Item(int value) {this.value=value;}
536         
537         public void increment(int[] currentOffset) {
538             super.increment(currentOffset);
539             currentOffset[0] += 3;
540         }
541         // this is incomplete!
542
public void emit(byte[] buffer) {
543             buffer[myOffset+0] = (byte) ((value >>> 16) & 0xff);
544             buffer[myOffset+1] = (byte) ((value >>> 8) & 0xff);
545             buffer[myOffset+2] = (byte) ((value >>> 0) & 0xff);
546         }
547     }
548     
549     /** Card32 item.
550      */

551     
552     static protected final class UInt32Item extends Item {
553         public int value;
554         public UInt32Item(int value) {this.value=value;}
555         
556         public void increment(int[] currentOffset) {
557             super.increment(currentOffset);
558             currentOffset[0] += 4;
559         }
560         // this is incomplete!
561
public void emit(byte[] buffer) {
562             buffer[myOffset+0] = (byte) ((value >>> 24) & 0xff);
563             buffer[myOffset+1] = (byte) ((value >>> 16) & 0xff);
564             buffer[myOffset+2] = (byte) ((value >>> 8) & 0xff);
565             buffer[myOffset+3] = (byte) ((value >>> 0) & 0xff);
566         }
567     }
568
569     /** A SID or Card16 item.
570      */

571     
572     static protected final class UInt16Item extends Item {
573         public char value;
574         public UInt16Item(char value) {this.value=value;}
575         
576         public void increment(int[] currentOffset) {
577             super.increment(currentOffset);
578             currentOffset[0] += 2;
579         }
580         // this is incomplete!
581
public void emit(byte[] buffer) {
582             buffer[myOffset+0] = (byte) ((value >>> 8) & 0xff);
583             buffer[myOffset+1] = (byte) ((value >>> 0) & 0xff);
584         }
585     }
586     
587     /** A Card8 item.
588      */

589     
590     static protected final class UInt8Item extends Item {
591         public char value;
592         public UInt8Item(char value) {this.value=value;}
593         
594         public void increment(int[] currentOffset) {
595             super.increment(currentOffset);
596             currentOffset[0] += 1;
597         }
598         // this is incomplete!
599
public void emit(byte[] buffer) {
600             buffer[myOffset+0] = (byte) ((value >>> 0) & 0xff);
601         }
602     }
603     
604     static protected final class StringItem extends Item {
605         public String JavaDoc s;
606         public StringItem(String JavaDoc s) {this.s=s;}
607         
608         public void increment(int[] currentOffset) {
609             super.increment(currentOffset);
610             currentOffset[0] += s.length();
611         }
612         public void emit(byte[] buffer) {
613             for (int i=0; i<s.length(); i++)
614                 buffer[myOffset+i] = (byte) (s.charAt(i) & 0xff);
615         }
616     }
617     
618     
619     /** A dictionary number on the list.
620      * This implementation is inefficient: it doesn't use the variable-length
621      * representation.
622      */

623     
624     static protected final class DictNumberItem extends Item {
625         public final int value;
626         public int size = 5;
627         public DictNumberItem(int value) {this.value=value;}
628         public void increment(int[] currentOffset) {
629             super.increment(currentOffset);
630             currentOffset[0] += size;
631         }
632         // this is imcomplete!
633
public void emit(byte[] buffer) {
634             if (size==5) {
635                 buffer[myOffset] = 29;
636                 buffer[myOffset+1] = (byte) ((value >>> 24) & 0xff);
637                 buffer[myOffset+2] = (byte) ((value >>> 16) & 0xff);
638                 buffer[myOffset+3] = (byte) ((value >>> 8) & 0xff);
639                 buffer[myOffset+4] = (byte) ((value >>> 0) & 0xff);
640             }
641         }
642     }
643     
644     /** An offset-marker item for the list.
645      * It is used to mark an offset and to set the offset list item.
646      */

647     
648     static protected final class MarkerItem extends Item {
649         OffsetItem p;
650         public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;}
651         public void xref() {
652             p.set(this.myOffset);
653         }
654     }
655     
656     /** a utility that creates a range item for an entire index
657      *
658      * @param indexOffset where the index is
659      * @return a range item representing the entire index
660      */

661     
662     protected RangeItem getEntireIndexRange(int indexOffset) {
663         seek(indexOffset);
664         int count = getCard16();
665         if (count==0) {
666             return new RangeItem(buf,indexOffset,2);
667         } else {
668             int indexOffSize = getCard8();
669             seek(indexOffset+2+1+count*indexOffSize);
670             int size = getOffset(indexOffSize)-1;
671             return new RangeItem(buf,indexOffset,
672             2+1+(count+1)*indexOffSize+size);
673         }
674     }
675     
676     
677     /** get a single CID font. The PDF architecture (1.4)
678      * supports 16-bit strings only with CID CFF fonts, not
679      * in Type-1 CFF fonts, so we convert the font to CID if
680      * it is in the Type-1 format.
681      * Two other tasks that we need to do are to select
682      * only a single font from the CFF package (this again is
683      * a PDF restriction) and to subset the CharStrings glyph
684      * description.
685      */

686     
687     
688     public byte[] getCID(String JavaDoc fontName)
689     //throws java.io.FileNotFoundException
690
{
691         int j;
692         for (j=0; j<fonts.length; j++)
693             if (fontName.equals(fonts[j].name)) break;
694         if (j==fonts.length) return null;
695         
696         LinkedList JavaDoc l = new LinkedList JavaDoc();
697         
698         // copy the header
699

700         seek(0);
701         
702         int major = getCard8();
703         int minor = getCard8();
704         int hdrSize = getCard8();
705         int offSize = getCard8();
706         nextIndexOffset = hdrSize;
707         
708         l.addLast(new RangeItem(buf,0,hdrSize));
709         
710         int nglyphs=-1, nstrings=-1;
711         if ( ! fonts[j].isCID ) {
712             // count the glyphs
713
seek(fonts[j].charstringsOffset);
714             nglyphs = getCard16();
715             seek(stringIndexOffset);
716             nstrings = getCard16()+standardStrings.length;
717             //System.err.println("number of glyphs = "+nglyphs);
718
}
719         
720         // create a name index
721

722         l.addLast(new UInt16Item((char)1)); // count
723
l.addLast(new UInt8Item((char)1)); // offSize
724
l.addLast(new UInt8Item((char)1)); // first offset
725
l.addLast(new UInt8Item((char)( 1+fonts[j].name.length() )));
726         l.addLast(new StringItem(fonts[j].name));
727         
728         // create the topdict Index
729

730         
731         l.addLast(new UInt16Item((char)1)); // count
732
l.addLast(new UInt8Item((char)2)); // offSize
733
l.addLast(new UInt16Item((char)1)); // first offset
734
OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
735         l.addLast(topdictIndex1Ref);
736         IndexBaseItem topdictBase = new IndexBaseItem();
737         l.addLast(topdictBase);
738         
739         /*
740         int maxTopdictLen = (topdictOffsets[j+1]-topdictOffsets[j])
741                             + 9*2 // at most 9 new keys
742                             + 8*5 // 8 new integer arguments
743                             + 3*2;// 3 new SID arguments
744          */

745         
746         //int topdictNext = 0;
747
//byte[] topdict = new byte[maxTopdictLen];
748

749         OffsetItem charsetRef = new DictOffsetItem();
750         OffsetItem charstringsRef = new DictOffsetItem();
751         OffsetItem fdarrayRef = new DictOffsetItem();
752         OffsetItem fdselectRef = new DictOffsetItem();
753         
754         if ( !fonts[j].isCID ) {
755             // create a ROS key
756
l.addLast(new DictNumberItem(nstrings));
757             l.addLast(new DictNumberItem(nstrings+1));
758             l.addLast(new DictNumberItem(0));
759             l.addLast(new UInt8Item((char)12));
760             l.addLast(new UInt8Item((char)30));
761             // create a CIDCount key
762
l.addLast(new DictNumberItem(nglyphs));
763             l.addLast(new UInt8Item((char)12));
764             l.addLast(new UInt8Item((char)34));
765             // What about UIDBase (12,35)? Don't know what is it.
766
// I don't think we need FontName; the font I looked at didn't have it.
767
}
768         
769         // create an FDArray key
770
l.addLast(fdarrayRef);
771         l.addLast(new UInt8Item((char)12));
772         l.addLast(new UInt8Item((char)36));
773         // create an FDSelect key
774
l.addLast(fdselectRef);
775         l.addLast(new UInt8Item((char)12));
776         l.addLast(new UInt8Item((char)37));
777         // create an charset key
778
l.addLast(charsetRef);
779         l.addLast(new UInt8Item((char)15));
780         // create a CharStrings key
781
l.addLast(charstringsRef);
782         l.addLast(new UInt8Item((char)17));
783         
784         seek(topdictOffsets[j]);
785         while (getPosition() < topdictOffsets[j+1]) {
786             int p1 = getPosition();
787             getDictItem();
788             int p2 = getPosition();
789             if (key=="Encoding"
790             || key=="Private"
791             || key=="FDSelect"
792             || key=="FDArray"
793             || key=="charset"
794             || key=="CharStrings"
795             ) {
796                 // just drop them
797
} else {
798                 l.add(new RangeItem(buf,p1,p2-p1));
799             }
800         }
801         
802         l.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase));
803         
804         // Copy the string index and append new strings.
805
// We need 3 more strings: Registry, Ordering, and a FontName for one FD.
806
// The total length is at most "Adobe"+"Identity"+63 = 76
807

808         if (fonts[j].isCID) {
809             l.addLast(getEntireIndexRange(stringIndexOffset));
810         } else {
811             String JavaDoc fdFontName = fonts[j].name+"-OneRange";
812             if (fdFontName.length() > 127)
813                 fdFontName = fdFontName.substring(0,127);
814             String JavaDoc extraStrings = "Adobe"+"Identity"+fdFontName;
815             
816             int origStringsLen = stringOffsets[stringOffsets.length-1]
817             - stringOffsets[0];
818             int stringsBaseOffset = stringOffsets[0]-1;
819             
820             byte stringsIndexOffSize;
821             if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1;
822             else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2;
823             else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3;
824             else stringsIndexOffSize = 4;
825             
826             l.addLast(new UInt16Item((char)((stringOffsets.length-1)+3))); // count
827
l.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize
828
for (int i=0; i<stringOffsets.length; i++)
829                 l.addLast(new IndexOffsetItem(stringsIndexOffSize,
830                 stringOffsets[i]-stringsBaseOffset));
831             int currentStringsOffset = stringOffsets[stringOffsets.length-1]
832             - stringsBaseOffset;
833             //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
834
currentStringsOffset += ("Adobe").length();
835             l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
836             currentStringsOffset += ("Identity").length();
837             l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
838             currentStringsOffset += fdFontName.length();
839             l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
840             
841             l.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen));
842             l.addLast(new StringItem(extraStrings));
843         }
844         
845         // copy the global subroutine index
846

847         l.addLast(getEntireIndexRange(gsubrIndexOffset));
848         
849         // deal with fdarray, fdselect, and the font descriptors
850

851         if (fonts[j].isCID) {
852             // copy the FDArray, FDSelect, charset
853
} else {
854             // create FDSelect
855
l.addLast(new MarkerItem(fdselectRef));
856             l.addLast(new UInt8Item((char)3)); // format identifier
857
l.addLast(new UInt16Item((char)1)); // nRanges
858

859             l.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph
860
l.addLast(new UInt8Item((char)0)); // Range[0].fd
861

862             l.addLast(new UInt16Item((char)nglyphs)); // sentinel
863

864             // recreate a new charset
865
// This format is suitable only for fonts without subsetting
866

867             l.addLast(new MarkerItem(charsetRef));
868             l.addLast(new UInt8Item((char)2)); // format identifier
869

870             l.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef)
871
l.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft
872
// now all are covered, the data structure is complete.
873

874             // create a font dict index (fdarray)
875

876             l.addLast(new MarkerItem(fdarrayRef));
877             l.addLast(new UInt16Item((char)1));
878             l.addLast(new UInt8Item((char)1)); // offSize
879
l.addLast(new UInt8Item((char)1)); // first offset
880

881             OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
882             l.addLast(privateIndex1Ref);
883             IndexBaseItem privateBase = new IndexBaseItem();
884             l.addLast(privateBase);
885             
886             // looking at the PS that acrobat generates from a PDF with
887
// a CFF opentype font embeded with an identity-H encoding,
888
// it seems that it does not need a FontName.
889
//l.addLast(new DictNumberItem((standardStrings.length+(stringOffsets.length-1)+2)));
890
//l.addLast(new UInt8Item((char)12));
891
//l.addLast(new UInt8Item((char)38)); // FontName
892

893             l.addLast(new DictNumberItem(fonts[j].privateLength));
894             OffsetItem privateRef = new DictOffsetItem();
895             l.addLast(privateRef);
896             l.addLast(new UInt8Item((char)18)); // Private
897

898             l.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase));
899             
900             // copy the private index & local subroutines
901

902             l.addLast(new MarkerItem(privateRef));
903             // copy the private dict and the local subroutines.
904
// the length of the private dict seems to NOT include
905
// the local subroutines.
906
l.addLast(new RangeItem(buf,fonts[j].privateOffset,fonts[j].privateLength));
907             if (fonts[j].privateSubrs >= 0) {
908                 //System.err.println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength);
909
l.addLast(getEntireIndexRange(fonts[j].privateSubrs));
910             }
911         }
912         
913         // copy the charstring index
914

915         l.addLast(new MarkerItem(charstringsRef));
916         l.addLast(getEntireIndexRange(fonts[j].charstringsOffset));
917         
918         // now create the new CFF font
919

920         int[] currentOffset = new int[1];
921         currentOffset[0] = 0;
922         
923         Iterator JavaDoc listIter = l.iterator();
924         while ( listIter.hasNext() ) {
925             Item item = (Item) listIter.next();
926             item.increment(currentOffset);
927         }
928         
929         listIter = l.iterator();
930         while ( listIter.hasNext() ) {
931             Item item = (Item) listIter.next();
932             item.xref();
933         }
934         
935         int size = currentOffset[0];
936         byte[] b = new byte[size];
937         
938         listIter = l.iterator();
939         while ( listIter.hasNext() ) {
940             Item item = (Item) listIter.next();
941             item.emit(b);
942         }
943         
944         return b;
945     }
946     
947     
948     public boolean isCID(String JavaDoc fontName) {
949         int j;
950         for (j=0; j<fonts.length; j++)
951             if (fontName.equals(fonts[j].name)) return fonts[j].isCID;
952         return false;
953     }
954     
955     public boolean exists(String JavaDoc fontName) {
956         int j;
957         for (j=0; j<fonts.length; j++)
958             if (fontName.equals(fonts[j].name)) return true;
959         return false;
960     }
961     
962     
963     public String JavaDoc[] getNames() {
964         String JavaDoc[] names = new String JavaDoc[ fonts.length ];
965         for (int i=0; i<fonts.length; i++)
966             names[i] = fonts[i].name;
967         return names;
968     }
969     /**
970      * A random Access File or an array
971      */

972     protected RandomAccessFileOrArray buf;
973     private int offSize;
974     
975     protected int nameIndexOffset;
976     protected int topdictIndexOffset;
977     protected int stringIndexOffset;
978     protected int gsubrIndexOffset;
979     protected int[] nameOffsets;
980     protected int[] topdictOffsets;
981     protected int[] stringOffsets;
982     protected int[] gsubrOffsets;
983     
984     /**
985      * TODO Changed from private to protected by Ygal&Oren
986      */

987     protected final class Font {
988         public String JavaDoc name;
989         public String JavaDoc fullName;
990         public boolean isCID = false;
991         public int privateOffset = -1; // only if not CID
992
public int privateLength = -1; // only if not CID
993
public int privateSubrs = -1;
994         public int charstringsOffset = -1;
995         public int encodingOffset = -1;
996         public int charsetOffset = -1;
997         public int fdarrayOffset = -1; // only if CID
998
public int fdselectOffset = -1; // only if CID
999
public int[] fdprivateOffsets;
1000        public int[] fdprivateLengths;
1001        public int[] fdprivateSubrs;
1002        
1003        // Added by Oren & Ygal
1004
public int nglyphs;
1005        public int nstrings;
1006        public int CharsetLength;
1007        public int[] charstringsOffsets;
1008        public int[] charset;
1009        public int[] FDSelect;
1010        public int FDSelectLength;
1011        public int FDSelectFormat;
1012        public int CharstringType = 2;
1013        public int FDArrayCount;
1014        public int FDArrayOffsize;
1015        public int[] FDArrayOffsets;
1016        public int[] PrivateSubrsOffset;
1017        public int[][] PrivateSubrsOffsetsArray;
1018        public int[] SubrsOffsets;
1019    }
1020    // Changed from private to protected by Ygal&Oren
1021
protected Font[] fonts;
1022    
1023    public CFFFont(RandomAccessFileOrArray inputbuffer) {
1024        
1025        //System.err.println("CFF: nStdString = "+standardStrings.length);
1026
buf = inputbuffer;
1027        seek(0);
1028        
1029        int major, minor;
1030        major = getCard8();
1031        minor = getCard8();
1032        
1033        //System.err.println("CFF Major-Minor = "+major+"-"+minor);
1034

1035        int hdrSize = getCard8();
1036        
1037        offSize = getCard8();
1038        
1039        //System.err.println("offSize = "+offSize);
1040

1041        //int count, indexOffSize, indexOffset, nextOffset;
1042

1043        nameIndexOffset = hdrSize;
1044        nameOffsets = getIndex(nameIndexOffset);
1045        topdictIndexOffset = nameOffsets[nameOffsets.length-1];
1046        topdictOffsets = getIndex(topdictIndexOffset);
1047        stringIndexOffset = topdictOffsets[topdictOffsets.length-1];
1048        stringOffsets = getIndex(stringIndexOffset);
1049        gsubrIndexOffset = stringOffsets[stringOffsets.length-1];
1050        gsubrOffsets = getIndex(gsubrIndexOffset);
1051        
1052        fonts = new Font[nameOffsets.length-1];
1053        
1054        // now get the name index
1055

1056        /*
1057        names = new String[nfonts];
1058        privateOffset = new int[nfonts];
1059        charsetOffset = new int[nfonts];
1060        encodingOffset = new int[nfonts];
1061        charstringsOffset = new int[nfonts];
1062        fdarrayOffset = new int[nfonts];
1063        fdselectOffset = new int[nfonts];
1064         */

1065        
1066        for (int j=0; j<nameOffsets.length-1; j++) {
1067            fonts[j] = new Font();
1068            seek(nameOffsets[j]);
1069            fonts[j].name = "";
1070            for (int k=nameOffsets[j]; k<nameOffsets[j+1]; k++) {
1071                fonts[j].name += (char)getCard8();
1072            }
1073            //System.err.println("name["+j+"]=<"+fonts[j].name+">");
1074
}
1075        
1076        // string index
1077

1078        //strings = new String[stringOffsets.length-1];
1079
/*
1080        System.err.println("std strings = "+standardStrings.length);
1081        System.err.println("fnt strings = "+(stringOffsets.length-1));
1082        for (char j=0; j<standardStrings.length+(stringOffsets.length-1); j++) {
1083            //seek(stringOffsets[j]);
1084            //strings[j] = "";
1085            //for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) {
1086            // strings[j] += (char)getCard8();
1087            //}
1088            System.err.println("j="+(int)j+" <? "+(standardStrings.length+(stringOffsets.length-1)));
1089            System.err.println("strings["+(int)j+"]=<"+getString(j)+">");
1090        }
1091         */

1092        
1093        // top dict
1094

1095        for (int j=0; j<topdictOffsets.length-1; j++) {
1096            seek(topdictOffsets[j]);
1097            while (getPosition() < topdictOffsets[j+1]) {
1098                getDictItem();
1099                if (key=="FullName") {
1100                    //System.err.println("getting fullname sid = "+((Integer)args[0]).intValue());
1101
fonts[j].fullName = getString((char)((Integer JavaDoc)args[0]).intValue());
1102                    //System.err.println("got it");
1103
} else if (key=="ROS")
1104                    fonts[j].isCID = true;
1105                else if (key=="Private") {
1106                    fonts[j].privateLength = ((Integer JavaDoc)args[0]).intValue();
1107                    fonts[j].privateOffset = ((Integer JavaDoc)args[1]).intValue();
1108                }
1109                else if (key=="charset"){
1110                    fonts[j].charsetOffset = ((Integer JavaDoc)args[0]).intValue();
1111                    
1112                }
1113                else if (key=="Encoding"){
1114                    fonts[j].encodingOffset = ((Integer JavaDoc)args[0]).intValue();
1115                    ReadEncoding(fonts[j].encodingOffset);
1116                }
1117                else if (key=="CharStrings") {
1118                    fonts[j].charstringsOffset = ((Integer JavaDoc)args[0]).intValue();
1119                    //System.err.println("charstrings "+fonts[j].charstringsOffset);
1120
// Added by Oren & Ygal
1121
int p = getPosition();
1122                    fonts[j].charstringsOffsets = getIndex(fonts[j].charstringsOffset);
1123                    seek(p);
1124                } else if (key=="FDArray")
1125                    fonts[j].fdarrayOffset = ((Integer JavaDoc)args[0]).intValue();
1126                else if (key=="FDSelect")
1127                    fonts[j].fdselectOffset = ((Integer JavaDoc)args[0]).intValue();
1128                else if (key=="CharstringType")
1129                    fonts[j].CharstringType = ((Integer JavaDoc)args[0]).intValue();
1130            }
1131            
1132            // private dict
1133
if (fonts[j].privateOffset >= 0) {
1134                //System.err.println("PRIVATE::");
1135
seek(fonts[j].privateOffset);
1136                while (getPosition() < fonts[j].privateOffset+fonts[j].privateLength) {
1137                    getDictItem();
1138                    if (key=="Subrs")
1139                        //Add the private offset to the lsubrs since the offset is
1140
// relative to the begining of the PrivateDict
1141
fonts[j].privateSubrs = ((Integer JavaDoc)args[0]).intValue()+fonts[j].privateOffset;
1142                }
1143            }
1144            
1145            // fdarray index
1146
if (fonts[j].fdarrayOffset >= 0) {
1147                int[] fdarrayOffsets = getIndex(fonts[j].fdarrayOffset);
1148                
1149                fonts[j].fdprivateOffsets = new int[fdarrayOffsets.length-1];
1150                fonts[j].fdprivateLengths = new int[fdarrayOffsets.length-1];
1151                
1152                //System.err.println("FD Font::");
1153

1154                for (int k=0; k<fdarrayOffsets.length-1; k++) {
1155                    seek(fdarrayOffsets[k]);
1156                    while (getPosition() < fdarrayOffsets[k+1])
1157                        getDictItem();
1158                    if (key=="Private") {
1159                        fonts[j].fdprivateLengths[k] = ((Integer JavaDoc)args[0]).intValue();
1160                        fonts[j].fdprivateOffsets[k] = ((Integer JavaDoc)args[1]).intValue();
1161                    }
1162                    
1163                }
1164            }
1165        }
1166        //System.err.println("CFF: done");
1167
}
1168    
1169    // ADDED BY Oren & Ygal
1170

1171    void ReadEncoding(int nextIndexOffset){
1172        int format;
1173        seek(nextIndexOffset);
1174        format = getCard8();
1175    }
1176}
Popular Tags