0001: /*
0002: *
0003: * Copyright 2003 Sivan Toledo
0004: *
0005: * The contents of this file are subject to the Mozilla Public License Version 1.1
0006: * (the "License"); you may not use this file except in compliance with the License.
0007: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0008: *
0009: * Software distributed under the License is distributed on an "AS IS" basis,
0010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0011: * for the specific language governing rights and limitations under the License.
0012: *
0013: * Contributor(s): all the names of the contributors are added in the source code
0014: * where applicable.
0015: *
0016: * Alternatively, the contents of this file may be used under the terms of the
0017: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0018: * provisions of LGPL are applicable instead of those above. If you wish to
0019: * allow use of your version of this file only under the terms of the LGPL
0020: * License and not to allow others to use your version of this file under
0021: * the MPL, indicate your decision by deleting the provisions above and
0022: * replace them with the notice and other provisions required by the LGPL.
0023: * If you do not delete the provisions above, a recipient may use your version
0024: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0025: *
0026: * This library is free software; you can redistribute it and/or modify it
0027: * under the terms of the MPL as stated above or under the terms of the GNU
0028: * Library General Public License as published by the Free Software Foundation;
0029: * either version 2 of the License, or any later version.
0030: *
0031: * This library is distributed in the hope that it will be useful, but WITHOUT
0032: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0033: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0034: * details.
0035: *
0036: */
0037:
0038: /*
0039: * Comments by Sivan Toledo:
0040: * I created this class in order to add to iText the ability to utilize
0041: * OpenType fonts with CFF glyphs (these usually have an .otf extension).
0042: * The CFF font within the CFF table of the OT font might be either a CID
0043: * or a Type1 font. (CFF fonts may also contain multiple fonts; I do not
0044: * know if this is allowed in an OT table). The PDF spec, however, only
0045: * allow a CID font with an Identity-H or Identity-V encoding. Otherwise,
0046: * you are limited to an 8-bit encoding.
0047: * Adobe fonts come in both flavors. That is, the OTFs sometimes have
0048: * a CID CFF inside (for Japanese fonts), and sometimes a Type1 CFF
0049: * (virtually all the others, Latin/Greek/Cyrillic). So to easily use
0050: * all the glyphs in the latter, without creating multiple 8-bit encoding,
0051: * I wrote this class, whose main purpose is to convert a Type1 font inside
0052: * a CFF container (which might include other fonts) into a CID CFF font
0053: * that can be directly embeded in the PDF.
0054: *
0055: * Limitations of the current version:
0056: * 1. It does not extract a single CID font from a CFF that contains that
0057: * particular CID along with other fonts. The Adobe Japanese OTF's that
0058: * I have only have one font in the CFF table, so these can be
0059: * embeded in the PDF as is.
0060: * 2. It does not yet subset fonts.
0061: * 3. It may or may not work on CFF fonts that are not within OTF's.
0062: * I didn't try that. In any case, that would probably only be
0063: * useful for subsetting CID fonts, not for CFF Type1 fonts (I don't
0064: * think there are any available.
0065: * I plan to extend the class to support these three features at some
0066: * future time.
0067: */
0068:
0069: package com.lowagie.text.pdf;
0070:
0071: import java.util.Iterator;
0072: import java.util.LinkedList;
0073:
0074: import com.lowagie.text.ExceptionConverter;
0075:
0076: public class CFFFont {
0077:
0078: static final String operatorNames[] = { "version", "Notice",
0079: "FullName", "FamilyName", "Weight", "FontBBox",
0080: "BlueValues", "OtherBlues", "FamilyBlues",
0081: "FamilyOtherBlues", "StdHW", "StdVW", "UNKNOWN_12",
0082: "UniqueID", "XUID", "charset", "Encoding", "CharStrings",
0083: "Private", "Subrs", "defaultWidthX", "nominalWidthX",
0084: "UNKNOWN_22", "UNKNOWN_23", "UNKNOWN_24", "UNKNOWN_25",
0085: "UNKNOWN_26", "UNKNOWN_27", "UNKNOWN_28", "UNKNOWN_29",
0086: "UNKNOWN_30", "UNKNOWN_31", "Copyright", "isFixedPitch",
0087: "ItalicAngle", "UnderlinePosition", "UnderlineThickness",
0088: "PaintType", "CharstringType", "FontMatrix", "StrokeWidth",
0089: "BlueScale", "BlueShift", "BlueFuzz", "StemSnapH",
0090: "StemSnapV", "ForceBold", "UNKNOWN_12_15", "UNKNOWN_12_16",
0091: "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
0092: "SyntheticBase", "PostScript", "BaseFontName",
0093: "BaseFontBlend", "UNKNOWN_12_24", "UNKNOWN_12_25",
0094: "UNKNOWN_12_26", "UNKNOWN_12_27", "UNKNOWN_12_28",
0095: "UNKNOWN_12_29", "ROS", "CIDFontVersion",
0096: "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase",
0097: "FDArray", "FDSelect", "FontName" };
0098:
0099: static final String standardStrings[] = {
0100: // Automatically generated from Appendix A of the CFF specification; do
0101: // not edit. Size should be 391.
0102: ".notdef", "space", "exclam", "quotedbl", "numbersign",
0103: "dollar", "percent", "ampersand", "quoteright",
0104: "parenleft", "parenright", "asterisk", "plus", "comma",
0105: "hyphen", "period", "slash", "zero", "one", "two", "three",
0106: "four", "five", "six", "seven", "eight", "nine", "colon",
0107: "semicolon", "less", "equal", "greater", "question", "at",
0108: "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
0109: "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
0110: "Y", "Z", "bracketleft", "backslash", "bracketright",
0111: "asciicircum", "underscore", "quoteleft", "a", "b", "c",
0112: "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
0113: "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
0114: "braceleft", "bar", "braceright", "asciitilde",
0115: "exclamdown", "cent", "sterling", "fraction", "yen",
0116: "florin", "section", "currency", "quotesingle",
0117: "quotedblleft", "guillemotleft", "guilsinglleft",
0118: "guilsinglright", "fi", "fl", "endash", "dagger",
0119: "daggerdbl", "periodcentered", "paragraph", "bullet",
0120: "quotesinglbase", "quotedblbase", "quotedblright",
0121: "guillemotright", "ellipsis", "perthousand",
0122: "questiondown", "grave", "acute", "circumflex", "tilde",
0123: "macron", "breve", "dotaccent", "dieresis", "ring",
0124: "cedilla", "hungarumlaut", "ogonek", "caron", "emdash",
0125: "AE", "ordfeminine", "Lslash", "Oslash", "OE",
0126: "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe",
0127: "germandbls", "onesuperior", "logicalnot", "mu",
0128: "trademark", "Eth", "onehalf", "plusminus", "Thorn",
0129: "onequarter", "divide", "brokenbar", "degree", "thorn",
0130: "threequarters", "twosuperior", "registered", "minus",
0131: "eth", "multiply", "threesuperior", "copyright", "Aacute",
0132: "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde",
0133: "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave",
0134: "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde",
0135: "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde",
0136: "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave",
0137: "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex",
0138: "adieresis", "agrave", "aring", "atilde", "ccedilla",
0139: "eacute", "ecircumflex", "edieresis", "egrave", "iacute",
0140: "icircumflex", "idieresis", "igrave", "ntilde", "oacute",
0141: "ocircumflex", "odieresis", "ograve", "otilde", "scaron",
0142: "uacute", "ucircumflex", "udieresis", "ugrave", "yacute",
0143: "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall",
0144: "dollaroldstyle", "dollarsuperior", "ampersandsmall",
0145: "Acutesmall", "parenleftsuperior", "parenrightsuperior",
0146: "twodotenleader", "onedotenleader", "zerooldstyle",
0147: "oneoldstyle", "twooldstyle", "threeoldstyle",
0148: "fouroldstyle", "fiveoldstyle", "sixoldstyle",
0149: "sevenoldstyle", "eightoldstyle", "nineoldstyle",
0150: "commasuperior", "threequartersemdash", "periodsuperior",
0151: "questionsmall", "asuperior", "bsuperior", "centsuperior",
0152: "dsuperior", "esuperior", "isuperior", "lsuperior",
0153: "msuperior", "nsuperior", "osuperior", "rsuperior",
0154: "ssuperior", "tsuperior", "ff", "ffi", "ffl",
0155: "parenleftinferior", "parenrightinferior",
0156: "Circumflexsmall", "hyphensuperior", "Gravesmall",
0157: "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
0158: "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall",
0159: "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall",
0160: "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall",
0161: "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah",
0162: "Tildesmall", "exclamdownsmall", "centoldstyle",
0163: "Lslashsmall", "Scaronsmall", "Zcaronsmall",
0164: "Dieresissmall", "Brevesmall", "Caronsmall",
0165: "Dotaccentsmall", "Macronsmall", "figuredash",
0166: "hypheninferior", "Ogoneksmall", "Ringsmall",
0167: "Cedillasmall", "questiondownsmall", "oneeighth",
0168: "threeeighths", "fiveeighths", "seveneighths", "onethird",
0169: "twothirds", "zerosuperior", "foursuperior",
0170: "fivesuperior", "sixsuperior", "sevensuperior",
0171: "eightsuperior", "ninesuperior", "zeroinferior",
0172: "oneinferior", "twoinferior", "threeinferior",
0173: "fourinferior", "fiveinferior", "sixinferior",
0174: "seveninferior", "eightinferior", "nineinferior",
0175: "centinferior", "dollarinferior", "periodinferior",
0176: "commainferior", "Agravesmall", "Aacutesmall",
0177: "Acircumflexsmall", "Atildesmall", "Adieresissmall",
0178: "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
0179: "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
0180: "Igravesmall", "Iacutesmall", "Icircumflexsmall",
0181: "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall",
0182: "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
0183: "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall",
0184: "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
0185: "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
0186: "001.001", "001.002", "001.003", "Black", "Bold", "Book",
0187: "Light", "Medium", "Regular", "Roman", "Semibold" };
0188:
0189: //private String[] strings;
0190: public String getString(char sid) {
0191: if (sid < standardStrings.length)
0192: return standardStrings[sid];
0193: if (sid >= standardStrings.length + (stringOffsets.length - 1))
0194: return null;
0195: int j = sid - standardStrings.length;
0196: //java.lang.System.err.println("going for "+j);
0197: int p = getPosition();
0198: seek(stringOffsets[j]);
0199: StringBuffer s = new StringBuffer();
0200: for (int k = stringOffsets[j]; k < stringOffsets[j + 1]; k++) {
0201: s.append(getCard8());
0202: }
0203: seek(p);
0204: return s.toString();
0205: }
0206:
0207: char getCard8() {
0208: try {
0209: byte i = buf.readByte();
0210: return (char) (i & 0xff);
0211: } catch (Exception e) {
0212: throw new ExceptionConverter(e);
0213: }
0214: }
0215:
0216: char getCard16() {
0217: try {
0218: return buf.readChar();
0219: } catch (Exception e) {
0220: throw new ExceptionConverter(e);
0221: }
0222: }
0223:
0224: int getOffset(int offSize) {
0225: int offset = 0;
0226: for (int i = 0; i < offSize; i++) {
0227: offset *= 256;
0228: offset += getCard8();
0229: }
0230: return offset;
0231: }
0232:
0233: void seek(int offset) {
0234: try {
0235: buf.seek(offset);
0236: } catch (Exception e) {
0237: throw new ExceptionConverter(e);
0238: }
0239: }
0240:
0241: short getShort() {
0242: try {
0243: return buf.readShort();
0244: } catch (Exception e) {
0245: throw new ExceptionConverter(e);
0246: }
0247: }
0248:
0249: int getInt() {
0250: try {
0251: return buf.readInt();
0252: } catch (Exception e) {
0253: throw new ExceptionConverter(e);
0254: }
0255: }
0256:
0257: int getPosition() {
0258: try {
0259: return buf.getFilePointer();
0260: } catch (Exception e) {
0261: throw new ExceptionConverter(e);
0262: }
0263: }
0264:
0265: int nextIndexOffset;
0266:
0267: // read the offsets in the next index
0268: // data structure, convert to global
0269: // offsets, and return them.
0270: // Sets the nextIndexOffset.
0271: int[] getIndex(int nextIndexOffset) {
0272: int count, indexOffSize;
0273:
0274: seek(nextIndexOffset);
0275: count = getCard16();
0276: int[] offsets = new int[count + 1];
0277:
0278: if (count == 0) {
0279: offsets[0] = -1;
0280: nextIndexOffset += 2;
0281: return offsets;
0282: }
0283:
0284: indexOffSize = getCard8();
0285:
0286: for (int j = 0; j <= count; j++) {
0287: //nextIndexOffset = ofset to relative segment
0288: offsets[j] = nextIndexOffset
0289: //2-> count in the index header. 1->offset size in index header
0290: + 2 + 1
0291: //offset array size * offset size
0292: + (count + 1) * indexOffSize
0293: //???zero <-> one base
0294: - 1
0295: // read object offset relative to object array base
0296: + getOffset(indexOffSize);
0297: }
0298: //nextIndexOffset = offsets[count];
0299: return offsets;
0300: }
0301:
0302: protected String key;
0303: protected Object[] args = new Object[48];
0304: protected int arg_count = 0;
0305:
0306: protected void getDictItem() {
0307: for (int i = 0; i < arg_count; i++)
0308: args[i] = null;
0309: arg_count = 0;
0310: key = null;
0311: boolean gotKey = false;
0312:
0313: while (!gotKey) {
0314: char b0 = getCard8();
0315: if (b0 == 29) {
0316: int item = getInt();
0317: args[arg_count] = new Integer(item);
0318: arg_count++;
0319: //System.err.println(item+" ");
0320: continue;
0321: }
0322: if (b0 == 28) {
0323: short item = getShort();
0324: args[arg_count] = new Integer(item);
0325: arg_count++;
0326: //System.err.println(item+" ");
0327: continue;
0328: }
0329: if (b0 >= 32 && b0 <= 246) {
0330: byte item = (byte) (b0 - 139);
0331: args[arg_count] = new Integer(item);
0332: arg_count++;
0333: //System.err.println(item+" ");
0334: continue;
0335: }
0336: if (b0 >= 247 && b0 <= 250) {
0337: char b1 = getCard8();
0338: short item = (short) ((b0 - 247) * 256 + b1 + 108);
0339: args[arg_count] = new Integer(item);
0340: arg_count++;
0341: //System.err.println(item+" ");
0342: continue;
0343: }
0344: if (b0 >= 251 && b0 <= 254) {
0345: char b1 = getCard8();
0346: short item = (short) (-(b0 - 251) * 256 - b1 - 108);
0347: args[arg_count] = new Integer(item);
0348: arg_count++;
0349: //System.err.println(item+" ");
0350: continue;
0351: }
0352: if (b0 == 30) {
0353: String item = "";
0354: boolean done = false;
0355: char buffer = 0;
0356: byte avail = 0;
0357: int nibble = 0;
0358: while (!done) {
0359: // get a nibble
0360: if (avail == 0) {
0361: buffer = getCard8();
0362: avail = 2;
0363: }
0364: if (avail == 1) {
0365: nibble = (buffer / 16);
0366: avail--;
0367: }
0368: if (avail == 2) {
0369: nibble = (buffer % 16);
0370: avail--;
0371: }
0372: switch (nibble) {
0373: case 0xa:
0374: item += ".";
0375: break;
0376: case 0xb:
0377: item += "E";
0378: break;
0379: case 0xc:
0380: item += "E-";
0381: break;
0382: case 0xe:
0383: item += "-";
0384: break;
0385: case 0xf:
0386: done = true;
0387: break;
0388: default:
0389: if (nibble >= 0 && nibble <= 9)
0390: item += String.valueOf(nibble);
0391: else {
0392: item += "<NIBBLE ERROR: " + nibble + '>';
0393: done = true;
0394: }
0395: break;
0396: }
0397: }
0398: args[arg_count] = item;
0399: arg_count++;
0400: //System.err.println(" real=["+item+"]");
0401: continue;
0402: }
0403: if (b0 <= 21) {
0404: gotKey = true;
0405: if (b0 != 12)
0406: key = operatorNames[b0];
0407: else
0408: key = operatorNames[32 + getCard8()];
0409: //for (int i=0; i<arg_count; i++)
0410: // System.err.print(args[i].toString()+" ");
0411: //System.err.println(key+" ;");
0412: continue;
0413: }
0414: }
0415: }
0416:
0417: /** List items for the linked list that builds the new CID font.
0418: */
0419:
0420: protected static abstract class Item {
0421: protected int myOffset = -1;
0422:
0423: /** remember the current offset and increment by item's size in bytes. */
0424: public void increment(int[] currentOffset) {
0425: myOffset = currentOffset[0];
0426: }
0427:
0428: /** Emit the byte stream for this item. */
0429: public void emit(byte[] buffer) {
0430: }
0431:
0432: /** Fix up cross references to this item (applies only to markers). */
0433: public void xref() {
0434: }
0435: }
0436:
0437: protected static abstract class OffsetItem extends Item {
0438: public int value;
0439:
0440: /** set the value of an offset item that was initially unknown.
0441: * It will be fixed up latex by a call to xref on some marker.
0442: */
0443: public void set(int offset) {
0444: this .value = offset;
0445: }
0446: }
0447:
0448: /** A range item.
0449: */
0450:
0451: protected static final class RangeItem extends Item {
0452: public int offset, length;
0453: private RandomAccessFileOrArray buf;
0454:
0455: public RangeItem(RandomAccessFileOrArray buf, int offset,
0456: int length) {
0457: this .offset = offset;
0458: this .length = length;
0459: this .buf = buf;
0460: }
0461:
0462: public void increment(int[] currentOffset) {
0463: super .increment(currentOffset);
0464: currentOffset[0] += length;
0465: }
0466:
0467: public void emit(byte[] buffer) {
0468: //System.err.println("range emit offset "+offset+" size="+length);
0469: try {
0470: buf.seek(offset);
0471: for (int i = myOffset; i < myOffset + length; i++)
0472: buffer[i] = buf.readByte();
0473: } catch (Exception e) {
0474: throw new ExceptionConverter(e);
0475: }
0476: //System.err.println("finished range emit");
0477: }
0478: }
0479:
0480: /** An index-offset item for the list.
0481: * The size denotes the required size in the CFF. A positive
0482: * value means that we need a specific size in bytes (for offset arrays)
0483: * and a negative value means that this is a dict item that uses a
0484: * variable-size representation.
0485: */
0486: static protected final class IndexOffsetItem extends OffsetItem {
0487: public final int size;
0488:
0489: public IndexOffsetItem(int size, int value) {
0490: this .size = size;
0491: this .value = value;
0492: }
0493:
0494: public IndexOffsetItem(int size) {
0495: this .size = size;
0496: }
0497:
0498: public void increment(int[] currentOffset) {
0499: super .increment(currentOffset);
0500: currentOffset[0] += size;
0501: }
0502:
0503: public void emit(byte[] buffer) {
0504: int i = 0;
0505: switch (size) {
0506: case 4:
0507: buffer[myOffset + i] = (byte) ((value >>> 24) & 0xff);
0508: i++;
0509: case 3:
0510: buffer[myOffset + i] = (byte) ((value >>> 16) & 0xff);
0511: i++;
0512: case 2:
0513: buffer[myOffset + i] = (byte) ((value >>> 8) & 0xff);
0514: i++;
0515: case 1:
0516: buffer[myOffset + i] = (byte) ((value >>> 0) & 0xff);
0517: i++;
0518: }
0519: /*
0520: int mask = 0xff;
0521: for (int i=size-1; i>=0; i--) {
0522: buffer[myOffset+i] = (byte) (value & mask);
0523: mask <<= 8;
0524: }
0525: */
0526: }
0527: }
0528:
0529: static protected final class IndexBaseItem extends Item {
0530: public IndexBaseItem() {
0531: }
0532: }
0533:
0534: static protected final class IndexMarkerItem extends Item {
0535: private OffsetItem offItem;
0536: private IndexBaseItem indexBase;
0537:
0538: public IndexMarkerItem(OffsetItem offItem,
0539: IndexBaseItem indexBase) {
0540: this .offItem = offItem;
0541: this .indexBase = indexBase;
0542: }
0543:
0544: public void xref() {
0545: //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
0546: offItem.set(this .myOffset - indexBase.myOffset + 1);
0547: }
0548: }
0549:
0550: /**
0551: * TODO To change the template for this generated type comment go to
0552: * Window - Preferences - Java - Code Generation - Code and Comments
0553: */
0554: static protected final class SubrMarkerItem extends Item {
0555: private OffsetItem offItem;
0556: private IndexBaseItem indexBase;
0557:
0558: public SubrMarkerItem(OffsetItem offItem,
0559: IndexBaseItem indexBase) {
0560: this .offItem = offItem;
0561: this .indexBase = indexBase;
0562: }
0563:
0564: public void xref() {
0565: //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
0566: offItem.set(this .myOffset - indexBase.myOffset);
0567: }
0568: }
0569:
0570: /** an unknown offset in a dictionary for the list.
0571: * We will fix up the offset later; for now, assume it's large.
0572: */
0573: static protected final class DictOffsetItem extends OffsetItem {
0574: public final int size;
0575:
0576: public DictOffsetItem() {
0577: this .size = 5;
0578: }
0579:
0580: public void increment(int[] currentOffset) {
0581: super .increment(currentOffset);
0582: currentOffset[0] += size;
0583: }
0584:
0585: // this is incomplete!
0586: public void emit(byte[] buffer) {
0587: if (size == 5) {
0588: buffer[myOffset] = 29;
0589: buffer[myOffset + 1] = (byte) ((value >>> 24) & 0xff);
0590: buffer[myOffset + 2] = (byte) ((value >>> 16) & 0xff);
0591: buffer[myOffset + 3] = (byte) ((value >>> 8) & 0xff);
0592: buffer[myOffset + 4] = (byte) ((value >>> 0) & 0xff);
0593: }
0594: }
0595: }
0596:
0597: /** Card24 item.
0598: */
0599:
0600: static protected final class UInt24Item extends Item {
0601: public int value;
0602:
0603: public UInt24Item(int value) {
0604: this .value = value;
0605: }
0606:
0607: public void increment(int[] currentOffset) {
0608: super .increment(currentOffset);
0609: currentOffset[0] += 3;
0610: }
0611:
0612: // this is incomplete!
0613: public void emit(byte[] buffer) {
0614: buffer[myOffset + 0] = (byte) ((value >>> 16) & 0xff);
0615: buffer[myOffset + 1] = (byte) ((value >>> 8) & 0xff);
0616: buffer[myOffset + 2] = (byte) ((value >>> 0) & 0xff);
0617: }
0618: }
0619:
0620: /** Card32 item.
0621: */
0622:
0623: static protected final class UInt32Item extends Item {
0624: public int value;
0625:
0626: public UInt32Item(int value) {
0627: this .value = value;
0628: }
0629:
0630: public void increment(int[] currentOffset) {
0631: super .increment(currentOffset);
0632: currentOffset[0] += 4;
0633: }
0634:
0635: // this is incomplete!
0636: public void emit(byte[] buffer) {
0637: buffer[myOffset + 0] = (byte) ((value >>> 24) & 0xff);
0638: buffer[myOffset + 1] = (byte) ((value >>> 16) & 0xff);
0639: buffer[myOffset + 2] = (byte) ((value >>> 8) & 0xff);
0640: buffer[myOffset + 3] = (byte) ((value >>> 0) & 0xff);
0641: }
0642: }
0643:
0644: /** A SID or Card16 item.
0645: */
0646:
0647: static protected final class UInt16Item extends Item {
0648: public char value;
0649:
0650: public UInt16Item(char value) {
0651: this .value = value;
0652: }
0653:
0654: public void increment(int[] currentOffset) {
0655: super .increment(currentOffset);
0656: currentOffset[0] += 2;
0657: }
0658:
0659: // this is incomplete!
0660: public void emit(byte[] buffer) {
0661: buffer[myOffset + 0] = (byte) ((value >>> 8) & 0xff);
0662: buffer[myOffset + 1] = (byte) ((value >>> 0) & 0xff);
0663: }
0664: }
0665:
0666: /** A Card8 item.
0667: */
0668:
0669: static protected final class UInt8Item extends Item {
0670: public char value;
0671:
0672: public UInt8Item(char value) {
0673: this .value = value;
0674: }
0675:
0676: public void increment(int[] currentOffset) {
0677: super .increment(currentOffset);
0678: currentOffset[0] += 1;
0679: }
0680:
0681: // this is incomplete!
0682: public void emit(byte[] buffer) {
0683: buffer[myOffset + 0] = (byte) ((value >>> 0) & 0xff);
0684: }
0685: }
0686:
0687: static protected final class StringItem extends Item {
0688: public String s;
0689:
0690: public StringItem(String s) {
0691: this .s = s;
0692: }
0693:
0694: public void increment(int[] currentOffset) {
0695: super .increment(currentOffset);
0696: currentOffset[0] += s.length();
0697: }
0698:
0699: public void emit(byte[] buffer) {
0700: for (int i = 0; i < s.length(); i++)
0701: buffer[myOffset + i] = (byte) (s.charAt(i) & 0xff);
0702: }
0703: }
0704:
0705: /** A dictionary number on the list.
0706: * This implementation is inefficient: it doesn't use the variable-length
0707: * representation.
0708: */
0709:
0710: static protected final class DictNumberItem extends Item {
0711: public final int value;
0712: public int size = 5;
0713:
0714: public DictNumberItem(int value) {
0715: this .value = value;
0716: }
0717:
0718: public void increment(int[] currentOffset) {
0719: super .increment(currentOffset);
0720: currentOffset[0] += size;
0721: }
0722:
0723: // this is imcomplete!
0724: public void emit(byte[] buffer) {
0725: if (size == 5) {
0726: buffer[myOffset] = 29;
0727: buffer[myOffset + 1] = (byte) ((value >>> 24) & 0xff);
0728: buffer[myOffset + 2] = (byte) ((value >>> 16) & 0xff);
0729: buffer[myOffset + 3] = (byte) ((value >>> 8) & 0xff);
0730: buffer[myOffset + 4] = (byte) ((value >>> 0) & 0xff);
0731: }
0732: }
0733: }
0734:
0735: /** An offset-marker item for the list.
0736: * It is used to mark an offset and to set the offset list item.
0737: */
0738:
0739: static protected final class MarkerItem extends Item {
0740: OffsetItem p;
0741:
0742: public MarkerItem(OffsetItem pointerToMarker) {
0743: p = pointerToMarker;
0744: }
0745:
0746: public void xref() {
0747: p.set(this .myOffset);
0748: }
0749: }
0750:
0751: /** a utility that creates a range item for an entire index
0752: *
0753: * @param indexOffset where the index is
0754: * @return a range item representing the entire index
0755: */
0756:
0757: protected RangeItem getEntireIndexRange(int indexOffset) {
0758: seek(indexOffset);
0759: int count = getCard16();
0760: if (count == 0) {
0761: return new RangeItem(buf, indexOffset, 2);
0762: } else {
0763: int indexOffSize = getCard8();
0764: seek(indexOffset + 2 + 1 + count * indexOffSize);
0765: int size = getOffset(indexOffSize) - 1;
0766: return new RangeItem(buf, indexOffset, 2 + 1 + (count + 1)
0767: * indexOffSize + size);
0768: }
0769: }
0770:
0771: /** get a single CID font. The PDF architecture (1.4)
0772: * supports 16-bit strings only with CID CFF fonts, not
0773: * in Type-1 CFF fonts, so we convert the font to CID if
0774: * it is in the Type-1 format.
0775: * Two other tasks that we need to do are to select
0776: * only a single font from the CFF package (this again is
0777: * a PDF restriction) and to subset the CharStrings glyph
0778: * description.
0779: */
0780:
0781: public byte[] getCID(String fontName)
0782: //throws java.io.FileNotFoundException
0783: {
0784: int j;
0785: for (j = 0; j < fonts.length; j++)
0786: if (fontName.equals(fonts[j].name))
0787: break;
0788: if (j == fonts.length)
0789: return null;
0790:
0791: LinkedList l = new LinkedList();
0792:
0793: // copy the header
0794:
0795: seek(0);
0796:
0797: int major = getCard8();
0798: int minor = getCard8();
0799: int hdrSize = getCard8();
0800: int offSize = getCard8();
0801: nextIndexOffset = hdrSize;
0802:
0803: l.addLast(new RangeItem(buf, 0, hdrSize));
0804:
0805: int nglyphs = -1, nstrings = -1;
0806: if (!fonts[j].isCID) {
0807: // count the glyphs
0808: seek(fonts[j].charstringsOffset);
0809: nglyphs = getCard16();
0810: seek(stringIndexOffset);
0811: nstrings = getCard16() + standardStrings.length;
0812: //System.err.println("number of glyphs = "+nglyphs);
0813: }
0814:
0815: // create a name index
0816:
0817: l.addLast(new UInt16Item((char) 1)); // count
0818: l.addLast(new UInt8Item((char) 1)); // offSize
0819: l.addLast(new UInt8Item((char) 1)); // first offset
0820: l.addLast(new UInt8Item((char) (1 + fonts[j].name.length())));
0821: l.addLast(new StringItem(fonts[j].name));
0822:
0823: // create the topdict Index
0824:
0825: l.addLast(new UInt16Item((char) 1)); // count
0826: l.addLast(new UInt8Item((char) 2)); // offSize
0827: l.addLast(new UInt16Item((char) 1)); // first offset
0828: OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
0829: l.addLast(topdictIndex1Ref);
0830: IndexBaseItem topdictBase = new IndexBaseItem();
0831: l.addLast(topdictBase);
0832:
0833: /*
0834: int maxTopdictLen = (topdictOffsets[j+1]-topdictOffsets[j])
0835: + 9*2 // at most 9 new keys
0836: + 8*5 // 8 new integer arguments
0837: + 3*2;// 3 new SID arguments
0838: */
0839:
0840: //int topdictNext = 0;
0841: //byte[] topdict = new byte[maxTopdictLen];
0842: OffsetItem charsetRef = new DictOffsetItem();
0843: OffsetItem charstringsRef = new DictOffsetItem();
0844: OffsetItem fdarrayRef = new DictOffsetItem();
0845: OffsetItem fdselectRef = new DictOffsetItem();
0846:
0847: if (!fonts[j].isCID) {
0848: // create a ROS key
0849: l.addLast(new DictNumberItem(nstrings));
0850: l.addLast(new DictNumberItem(nstrings + 1));
0851: l.addLast(new DictNumberItem(0));
0852: l.addLast(new UInt8Item((char) 12));
0853: l.addLast(new UInt8Item((char) 30));
0854: // create a CIDCount key
0855: l.addLast(new DictNumberItem(nglyphs));
0856: l.addLast(new UInt8Item((char) 12));
0857: l.addLast(new UInt8Item((char) 34));
0858: // What about UIDBase (12,35)? Don't know what is it.
0859: // I don't think we need FontName; the font I looked at didn't have it.
0860: }
0861:
0862: // create an FDArray key
0863: l.addLast(fdarrayRef);
0864: l.addLast(new UInt8Item((char) 12));
0865: l.addLast(new UInt8Item((char) 36));
0866: // create an FDSelect key
0867: l.addLast(fdselectRef);
0868: l.addLast(new UInt8Item((char) 12));
0869: l.addLast(new UInt8Item((char) 37));
0870: // create an charset key
0871: l.addLast(charsetRef);
0872: l.addLast(new UInt8Item((char) 15));
0873: // create a CharStrings key
0874: l.addLast(charstringsRef);
0875: l.addLast(new UInt8Item((char) 17));
0876:
0877: seek(topdictOffsets[j]);
0878: while (getPosition() < topdictOffsets[j + 1]) {
0879: int p1 = getPosition();
0880: getDictItem();
0881: int p2 = getPosition();
0882: if (key == "Encoding" || key == "Private"
0883: || key == "FDSelect" || key == "FDArray"
0884: || key == "charset" || key == "CharStrings") {
0885: // just drop them
0886: } else {
0887: l.add(new RangeItem(buf, p1, p2 - p1));
0888: }
0889: }
0890:
0891: l.addLast(new IndexMarkerItem(topdictIndex1Ref, topdictBase));
0892:
0893: // Copy the string index and append new strings.
0894: // We need 3 more strings: Registry, Ordering, and a FontName for one FD.
0895: // The total length is at most "Adobe"+"Identity"+63 = 76
0896:
0897: if (fonts[j].isCID) {
0898: l.addLast(getEntireIndexRange(stringIndexOffset));
0899: } else {
0900: String fdFontName = fonts[j].name + "-OneRange";
0901: if (fdFontName.length() > 127)
0902: fdFontName = fdFontName.substring(0, 127);
0903: String extraStrings = "Adobe" + "Identity" + fdFontName;
0904:
0905: int origStringsLen = stringOffsets[stringOffsets.length - 1]
0906: - stringOffsets[0];
0907: int stringsBaseOffset = stringOffsets[0] - 1;
0908:
0909: byte stringsIndexOffSize;
0910: if (origStringsLen + extraStrings.length() <= 0xff)
0911: stringsIndexOffSize = 1;
0912: else if (origStringsLen + extraStrings.length() <= 0xffff)
0913: stringsIndexOffSize = 2;
0914: else if (origStringsLen + extraStrings.length() <= 0xffffff)
0915: stringsIndexOffSize = 3;
0916: else
0917: stringsIndexOffSize = 4;
0918:
0919: l.addLast(new UInt16Item(
0920: (char) ((stringOffsets.length - 1) + 3))); // count
0921: l.addLast(new UInt8Item((char) stringsIndexOffSize)); // offSize
0922: for (int i = 0; i < stringOffsets.length; i++)
0923: l.addLast(new IndexOffsetItem(stringsIndexOffSize,
0924: stringOffsets[i] - stringsBaseOffset));
0925: int currentStringsOffset = stringOffsets[stringOffsets.length - 1]
0926: - stringsBaseOffset;
0927: //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
0928: currentStringsOffset += ("Adobe").length();
0929: l.addLast(new IndexOffsetItem(stringsIndexOffSize,
0930: currentStringsOffset));
0931: currentStringsOffset += ("Identity").length();
0932: l.addLast(new IndexOffsetItem(stringsIndexOffSize,
0933: currentStringsOffset));
0934: currentStringsOffset += fdFontName.length();
0935: l.addLast(new IndexOffsetItem(stringsIndexOffSize,
0936: currentStringsOffset));
0937:
0938: l.addLast(new RangeItem(buf, stringOffsets[0],
0939: origStringsLen));
0940: l.addLast(new StringItem(extraStrings));
0941: }
0942:
0943: // copy the global subroutine index
0944:
0945: l.addLast(getEntireIndexRange(gsubrIndexOffset));
0946:
0947: // deal with fdarray, fdselect, and the font descriptors
0948:
0949: if (fonts[j].isCID) {
0950: // copy the FDArray, FDSelect, charset
0951: } else {
0952: // create FDSelect
0953: l.addLast(new MarkerItem(fdselectRef));
0954: l.addLast(new UInt8Item((char) 3)); // format identifier
0955: l.addLast(new UInt16Item((char) 1)); // nRanges
0956:
0957: l.addLast(new UInt16Item((char) 0)); // Range[0].firstGlyph
0958: l.addLast(new UInt8Item((char) 0)); // Range[0].fd
0959:
0960: l.addLast(new UInt16Item((char) nglyphs)); // sentinel
0961:
0962: // recreate a new charset
0963: // This format is suitable only for fonts without subsetting
0964:
0965: l.addLast(new MarkerItem(charsetRef));
0966: l.addLast(new UInt8Item((char) 2)); // format identifier
0967:
0968: l.addLast(new UInt16Item((char) 1)); // first glyph in range (ignore .notdef)
0969: l.addLast(new UInt16Item((char) (nglyphs - 1))); // nLeft
0970: // now all are covered, the data structure is complete.
0971:
0972: // create a font dict index (fdarray)
0973:
0974: l.addLast(new MarkerItem(fdarrayRef));
0975: l.addLast(new UInt16Item((char) 1));
0976: l.addLast(new UInt8Item((char) 1)); // offSize
0977: l.addLast(new UInt8Item((char) 1)); // first offset
0978:
0979: OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
0980: l.addLast(privateIndex1Ref);
0981: IndexBaseItem privateBase = new IndexBaseItem();
0982: l.addLast(privateBase);
0983:
0984: // looking at the PS that acrobat generates from a PDF with
0985: // a CFF opentype font embeded with an identity-H encoding,
0986: // it seems that it does not need a FontName.
0987: //l.addLast(new DictNumberItem((standardStrings.length+(stringOffsets.length-1)+2)));
0988: //l.addLast(new UInt8Item((char)12));
0989: //l.addLast(new UInt8Item((char)38)); // FontName
0990:
0991: l.addLast(new DictNumberItem(fonts[j].privateLength));
0992: OffsetItem privateRef = new DictOffsetItem();
0993: l.addLast(privateRef);
0994: l.addLast(new UInt8Item((char) 18)); // Private
0995:
0996: l
0997: .addLast(new IndexMarkerItem(privateIndex1Ref,
0998: privateBase));
0999:
1000: // copy the private index & local subroutines
1001:
1002: l.addLast(new MarkerItem(privateRef));
1003: // copy the private dict and the local subroutines.
1004: // the length of the private dict seems to NOT include
1005: // the local subroutines.
1006: l.addLast(new RangeItem(buf, fonts[j].privateOffset,
1007: fonts[j].privateLength));
1008: if (fonts[j].privateSubrs >= 0) {
1009: //System.err.println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength);
1010: l.addLast(getEntireIndexRange(fonts[j].privateSubrs));
1011: }
1012: }
1013:
1014: // copy the charstring index
1015:
1016: l.addLast(new MarkerItem(charstringsRef));
1017: l.addLast(getEntireIndexRange(fonts[j].charstringsOffset));
1018:
1019: // now create the new CFF font
1020:
1021: int[] currentOffset = new int[1];
1022: currentOffset[0] = 0;
1023:
1024: Iterator listIter = l.iterator();
1025: while (listIter.hasNext()) {
1026: Item item = (Item) listIter.next();
1027: item.increment(currentOffset);
1028: }
1029:
1030: listIter = l.iterator();
1031: while (listIter.hasNext()) {
1032: Item item = (Item) listIter.next();
1033: item.xref();
1034: }
1035:
1036: int size = currentOffset[0];
1037: byte[] b = new byte[size];
1038:
1039: listIter = l.iterator();
1040: while (listIter.hasNext()) {
1041: Item item = (Item) listIter.next();
1042: item.emit(b);
1043: }
1044:
1045: return b;
1046: }
1047:
1048: public boolean isCID(String fontName) {
1049: int j;
1050: for (j = 0; j < fonts.length; j++)
1051: if (fontName.equals(fonts[j].name))
1052: return fonts[j].isCID;
1053: return false;
1054: }
1055:
1056: public boolean exists(String fontName) {
1057: int j;
1058: for (j = 0; j < fonts.length; j++)
1059: if (fontName.equals(fonts[j].name))
1060: return true;
1061: return false;
1062: }
1063:
1064: public String[] getNames() {
1065: String[] names = new String[fonts.length];
1066: for (int i = 0; i < fonts.length; i++)
1067: names[i] = fonts[i].name;
1068: return names;
1069: }
1070:
1071: /**
1072: * A random Access File or an array
1073: */
1074: protected RandomAccessFileOrArray buf;
1075: private int offSize;
1076:
1077: protected int nameIndexOffset;
1078: protected int topdictIndexOffset;
1079: protected int stringIndexOffset;
1080: protected int gsubrIndexOffset;
1081: protected int[] nameOffsets;
1082: protected int[] topdictOffsets;
1083: protected int[] stringOffsets;
1084: protected int[] gsubrOffsets;
1085:
1086: /**
1087: * TODO Changed from private to protected by Ygal&Oren
1088: */
1089: protected final class Font {
1090: public String name;
1091: public String fullName;
1092: public boolean isCID = false;
1093: public int privateOffset = -1; // only if not CID
1094: public int privateLength = -1; // only if not CID
1095: public int privateSubrs = -1;
1096: public int charstringsOffset = -1;
1097: public int encodingOffset = -1;
1098: public int charsetOffset = -1;
1099: public int fdarrayOffset = -1; // only if CID
1100: public int fdselectOffset = -1; // only if CID
1101: public int[] fdprivateOffsets;
1102: public int[] fdprivateLengths;
1103: public int[] fdprivateSubrs;
1104:
1105: // Added by Oren & Ygal
1106: public int nglyphs;
1107: public int nstrings;
1108: public int CharsetLength;
1109: public int[] charstringsOffsets;
1110: public int[] charset;
1111: public int[] FDSelect;
1112: public int FDSelectLength;
1113: public int FDSelectFormat;
1114: public int CharstringType = 2;
1115: public int FDArrayCount;
1116: public int FDArrayOffsize;
1117: public int[] FDArrayOffsets;
1118: public int[] PrivateSubrsOffset;
1119: public int[][] PrivateSubrsOffsetsArray;
1120: public int[] SubrsOffsets;
1121: }
1122:
1123: // Changed from private to protected by Ygal&Oren
1124: protected Font[] fonts;
1125:
1126: public CFFFont(RandomAccessFileOrArray inputbuffer) {
1127:
1128: //System.err.println("CFF: nStdString = "+standardStrings.length);
1129: buf = inputbuffer;
1130: seek(0);
1131:
1132: int major, minor;
1133: major = getCard8();
1134: minor = getCard8();
1135:
1136: //System.err.println("CFF Major-Minor = "+major+"-"+minor);
1137:
1138: int hdrSize = getCard8();
1139:
1140: offSize = getCard8();
1141:
1142: //System.err.println("offSize = "+offSize);
1143:
1144: //int count, indexOffSize, indexOffset, nextOffset;
1145:
1146: nameIndexOffset = hdrSize;
1147: nameOffsets = getIndex(nameIndexOffset);
1148: topdictIndexOffset = nameOffsets[nameOffsets.length - 1];
1149: topdictOffsets = getIndex(topdictIndexOffset);
1150: stringIndexOffset = topdictOffsets[topdictOffsets.length - 1];
1151: stringOffsets = getIndex(stringIndexOffset);
1152: gsubrIndexOffset = stringOffsets[stringOffsets.length - 1];
1153: gsubrOffsets = getIndex(gsubrIndexOffset);
1154:
1155: fonts = new Font[nameOffsets.length - 1];
1156:
1157: // now get the name index
1158:
1159: /*
1160: names = new String[nfonts];
1161: privateOffset = new int[nfonts];
1162: charsetOffset = new int[nfonts];
1163: encodingOffset = new int[nfonts];
1164: charstringsOffset = new int[nfonts];
1165: fdarrayOffset = new int[nfonts];
1166: fdselectOffset = new int[nfonts];
1167: */
1168:
1169: for (int j = 0; j < nameOffsets.length - 1; j++) {
1170: fonts[j] = new Font();
1171: seek(nameOffsets[j]);
1172: fonts[j].name = "";
1173: for (int k = nameOffsets[j]; k < nameOffsets[j + 1]; k++) {
1174: fonts[j].name += (char) getCard8();
1175: }
1176: //System.err.println("name["+j+"]=<"+fonts[j].name+">");
1177: }
1178:
1179: // string index
1180:
1181: //strings = new String[stringOffsets.length-1];
1182: /*
1183: System.err.println("std strings = "+standardStrings.length);
1184: System.err.println("fnt strings = "+(stringOffsets.length-1));
1185: for (char j=0; j<standardStrings.length+(stringOffsets.length-1); j++) {
1186: //seek(stringOffsets[j]);
1187: //strings[j] = "";
1188: //for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) {
1189: // strings[j] += (char)getCard8();
1190: //}
1191: System.err.println("j="+(int)j+" <? "+(standardStrings.length+(stringOffsets.length-1)));
1192: System.err.println("strings["+(int)j+"]=<"+getString(j)+">");
1193: }
1194: */
1195:
1196: // top dict
1197: for (int j = 0; j < topdictOffsets.length - 1; j++) {
1198: seek(topdictOffsets[j]);
1199: while (getPosition() < topdictOffsets[j + 1]) {
1200: getDictItem();
1201: if (key == "FullName") {
1202: //System.err.println("getting fullname sid = "+((Integer)args[0]).intValue());
1203: fonts[j].fullName = getString((char) ((Integer) args[0])
1204: .intValue());
1205: //System.err.println("got it");
1206: } else if (key == "ROS")
1207: fonts[j].isCID = true;
1208: else if (key == "Private") {
1209: fonts[j].privateLength = ((Integer) args[0])
1210: .intValue();
1211: fonts[j].privateOffset = ((Integer) args[1])
1212: .intValue();
1213: } else if (key == "charset") {
1214: fonts[j].charsetOffset = ((Integer) args[0])
1215: .intValue();
1216:
1217: } else if (key == "Encoding") {
1218: fonts[j].encodingOffset = ((Integer) args[0])
1219: .intValue();
1220: ReadEncoding(fonts[j].encodingOffset);
1221: } else if (key == "CharStrings") {
1222: fonts[j].charstringsOffset = ((Integer) args[0])
1223: .intValue();
1224: //System.err.println("charstrings "+fonts[j].charstringsOffset);
1225: // Added by Oren & Ygal
1226: int p = getPosition();
1227: fonts[j].charstringsOffsets = getIndex(fonts[j].charstringsOffset);
1228: seek(p);
1229: } else if (key == "FDArray")
1230: fonts[j].fdarrayOffset = ((Integer) args[0])
1231: .intValue();
1232: else if (key == "FDSelect")
1233: fonts[j].fdselectOffset = ((Integer) args[0])
1234: .intValue();
1235: else if (key == "CharstringType")
1236: fonts[j].CharstringType = ((Integer) args[0])
1237: .intValue();
1238: }
1239:
1240: // private dict
1241: if (fonts[j].privateOffset >= 0) {
1242: //System.err.println("PRIVATE::");
1243: seek(fonts[j].privateOffset);
1244: while (getPosition() < fonts[j].privateOffset
1245: + fonts[j].privateLength) {
1246: getDictItem();
1247: if (key == "Subrs")
1248: //Add the private offset to the lsubrs since the offset is
1249: // relative to the begining of the PrivateDict
1250: fonts[j].privateSubrs = ((Integer) args[0])
1251: .intValue()
1252: + fonts[j].privateOffset;
1253: }
1254: }
1255:
1256: // fdarray index
1257: if (fonts[j].fdarrayOffset >= 0) {
1258: int[] fdarrayOffsets = getIndex(fonts[j].fdarrayOffset);
1259:
1260: fonts[j].fdprivateOffsets = new int[fdarrayOffsets.length - 1];
1261: fonts[j].fdprivateLengths = new int[fdarrayOffsets.length - 1];
1262:
1263: //System.err.println("FD Font::");
1264:
1265: for (int k = 0; k < fdarrayOffsets.length - 1; k++) {
1266: seek(fdarrayOffsets[k]);
1267: while (getPosition() < fdarrayOffsets[k + 1])
1268: getDictItem();
1269: if (key == "Private") {
1270: fonts[j].fdprivateLengths[k] = ((Integer) args[0])
1271: .intValue();
1272: fonts[j].fdprivateOffsets[k] = ((Integer) args[1])
1273: .intValue();
1274: }
1275:
1276: }
1277: }
1278: }
1279: //System.err.println("CFF: done");
1280: }
1281:
1282: // ADDED BY Oren & Ygal
1283:
1284: void ReadEncoding(int nextIndexOffset) {
1285: int format;
1286: seek(nextIndexOffset);
1287: format = getCard8();
1288: }
1289: }
|