using System; using System.Text; using System.Collections; /* * * Copyright 2003 Sivan Toledo * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. * * Alternatively, the contents of this file may be used under the terms of the * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the * provisions of LGPL are applicable instead of those above. If you wish to * allow use of your version of this file only under the terms of the LGPL * License and not to allow others to use your version of this file under * the MPL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the LGPL. * If you do not delete the provisions above, a recipient may use your version * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. * * This library is free software; you can redistribute it and/or modify it * under the terms of the MPL as stated above or under the terms of the GNU * Library General Public License as published by the Free Software Foundation; * either version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more * details. * */ namespace iTextSharp.text.pdf { public class CFFFont { internal static String[] operatorNames = { "version", "Notice", "FullName", "FamilyName", "Weight", "FontBBox", "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "UNKNOWN_12", "UniqueID", "XUID", "charset", "Encoding", "CharStrings", "Private", "Subrs", "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23", "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27", "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31", "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15", "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed", "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27", "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion", "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", "FDArray", "FDSelect", "FontName" }; internal static String[] standardStrings = { // Automatically generated from Appendix A of the CFF specification; do // not edit. Size should be 391. ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" }; //private String[] strings; public String GetString(char sid) { if (sid < standardStrings.Length) return standardStrings[sid]; if (sid >= standardStrings.Length+(stringOffsets.Length-1)) return null; int j = sid - standardStrings.Length; int p = GetPosition(); Seek(stringOffsets[j]); StringBuilder s = new StringBuilder(); for (int k=stringOffsets[j]; k count in the index header. 1->offset size in index header + 2+1 //offset array size * offset size + (count+1)*indexOffSize //???zero <-> one base - 1 // read object offset relative to object array base + GetOffset(indexOffSize); } //nextIndexOffset = offsets[count]; return offsets; } protected String key; protected Object[] args = new Object[48]; protected int arg_count = 0; protected void GetDictItem() { for (int i=0; i= 32 && b0 <= 246) { sbyte item = (sbyte) ((int)b0-139); args[arg_count] = (int)item; arg_count++; //System.err.Println(item+" "); continue; } if (b0 >= 247 && b0 <= 250) { char b1 = GetCard8(); short item = (short) (((int)b0-247)*256+(int)b1+108); args[arg_count] = (int)item; arg_count++; //System.err.Println(item+" "); continue; } if (b0 >= 251 && b0 <= 254) { char b1 = GetCard8(); short item = (short) (-((int)b0-251)*256-(int)b1-108); args[arg_count] = (int)item; arg_count++; //System.err.Println(item+" "); continue; } if (b0 == 30) { String item = ""; bool done = false; char buffer = (char)0; byte avail = 0; int nibble = 0; while (!done) { // get a nibble if (avail==0) { buffer = GetCard8(); avail=2; } if (avail==1) { nibble = (buffer / 16); avail--; } if (avail==2) { nibble = (buffer % 16); avail--; } switch (nibble) { case 0xa: item += "." ; break; case 0xb: item += "E" ; break; case 0xc: item += "E-"; break; case 0xe: item += "-" ; break; case 0xf: done=true ; break; default: if (nibble >= 0 && nibble <= 9) item += nibble.ToString(); else { item += ""; done = true; } break; } } args[arg_count] = item; arg_count++; //System.err.Println(" real=["+item+"]"); continue; } if (b0 <= 21) { gotKey=true; if (b0 != 12) key = operatorNames[b0]; else key = operatorNames[32 + GetCard8()]; //for (int i=0; i> 24) & 0xff); i++; goto case 3; case 3: buffer[myOffset+i] = (byte) ((value >> 16) & 0xff); i++; goto case 2; case 2: buffer[myOffset+i] = (byte) ((value >> 8) & 0xff); i++; goto case 1; case 1: buffer[myOffset+i] = (byte) ((value >> 0) & 0xff); i++; break; } /* int mask = 0xff; for (int i=size-1; i>=0; i--) { buffer[myOffset+i] = (byte) (value & mask); mask <<= 8; } */ } } protected internal class IndexBaseItem : Item { public IndexBaseItem() {} } protected internal class IndexMarkerItem : Item { private OffsetItem offItem; private IndexBaseItem indexBase; public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { this.offItem = offItem; this.indexBase = indexBase; } public override void Xref() { //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); offItem.Set(this.myOffset-indexBase.myOffset+1); } } /** * * @author orly manor * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Generation - Code and Comments */ protected internal class SubrMarkerItem : Item { private OffsetItem offItem; private IndexBaseItem indexBase; public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { this.offItem = offItem; this.indexBase = indexBase; } public override void Xref() { //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); offItem.Set(this.myOffset-indexBase.myOffset); } } /** an unknown offset in a dictionary for the list. * We will fix up the offset later; for now, assume it's large. */ protected internal class DictOffsetItem : OffsetItem { public int size; public DictOffsetItem() {this.size=5; } public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += size; } // this is incomplete! public override void Emit(byte[] buffer) { if (size==5) { buffer[myOffset] = 29; buffer[myOffset+1] = (byte) ((value >> 24) & 0xff); buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); } } } /** Card24 item. */ protected internal class UInt24Item : Item { public int value; public UInt24Item(int value) {this.value=value;} public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += 3; } // this is incomplete! public override void Emit(byte[] buffer) { buffer[myOffset+0] = (byte) ((value >> 16) & 0xff); buffer[myOffset+1] = (byte) ((value >> 8) & 0xff); buffer[myOffset+2] = (byte) ((value >> 0) & 0xff); } } /** Card32 item. */ protected internal class UInt32Item : Item { public int value; public UInt32Item(int value) {this.value=value;} public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += 4; } // this is incomplete! public override void Emit(byte[] buffer) { buffer[myOffset+0] = (byte) ((value >> 24) & 0xff); buffer[myOffset+1] = (byte) ((value >> 16) & 0xff); buffer[myOffset+2] = (byte) ((value >> 8) & 0xff); buffer[myOffset+3] = (byte) ((value >> 0) & 0xff); } } /** A SID or Card16 item. */ protected internal class UInt16Item : Item { public char value; public UInt16Item(char value) {this.value=value;} public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += 2; } // this is incomplete! public override void Emit(byte[] buffer) { buffer[myOffset+0] = (byte) ((value >> 8) & 0xff); buffer[myOffset+1] = (byte) ((value >> 0) & 0xff); } } /** A Card8 item. */ protected internal class UInt8Item : Item { public char value; public UInt8Item(char value) {this.value=value;} public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += 1; } // this is incomplete! public override void Emit(byte[] buffer) { buffer[myOffset+0] = (byte) ((value >> 0) & 0xff); } } protected internal class StringItem : Item { public String s; public StringItem(String s) {this.s=s;} public override void Increment(int[] currentOffset) { base.Increment(currentOffset); currentOffset[0] += s.Length; } public override void Emit(byte[] buffer) { for (int i=0; i> 24) & 0xff); buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); } } } /** An offset-marker item for the list. * It is used to mark an offset and to set the offset list item. */ protected internal class MarkerItem : Item { OffsetItem p; public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;} public override void Xref() { p.Set(this.myOffset); } } /** a utility that creates a range item for an entire index * * @param indexOffset where the index is * @return a range item representing the entire index */ protected virtual RangeItem GetEntireIndexRange(int indexOffset) { Seek(indexOffset); int count = GetCard16(); if (count==0) { return new RangeItem(buf,indexOffset,2); } else { int indexOffSize = GetCard8(); Seek(indexOffset+2+1+count*indexOffSize); int size = GetOffset(indexOffSize)-1; return new RangeItem(buf,indexOffset, 2+1+(count+1)*indexOffSize+size); } } /** get a single CID font. The PDF architecture (1.4) * supports 16-bit strings only with CID CFF fonts, not * in Type-1 CFF fonts, so we convert the font to CID if * it is in the Type-1 format. * Two other tasks that we need to do are to select * only a single font from the CFF package (this again is * a PDF restriction) and to subset the CharStrings glyph * description. */ public byte[] GetCID(String fontName) //throws java.io.FileNotFoundException { int j; for (j=0; j 127) fdFontName = fdFontName.Substring(0,127); String extraStrings = "Adobe"+"Identity"+fdFontName; int origStringsLen = stringOffsets[stringOffsets.Length-1] - stringOffsets[0]; int stringsBaseOffset = stringOffsets[0]-1; byte stringsIndexOffSize; if (origStringsLen+extraStrings.Length <= 0xff) stringsIndexOffSize = 1; else if (origStringsLen+extraStrings.Length <= 0xffff) stringsIndexOffSize = 2; else if (origStringsLen+extraStrings.Length <= 0xffffff) stringsIndexOffSize = 3; else stringsIndexOffSize = 4; l.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count l.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize for (int i=0; i= 0) { //System.err.Println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength); l.Add(GetEntireIndexRange(fonts[j].privateSubrs)); } } // copy the charstring index l.Add(new MarkerItem(charstringsRef)); l.Add(GetEntireIndexRange(fonts[j].charstringsOffset)); // now create the new CFF font int[] currentOffset = new int[1]; currentOffset[0] = 0; foreach (Item item in l) { item.Increment(currentOffset); } foreach (Item item in l) { item.Xref(); } int size = currentOffset[0]; byte[] b = new byte[size]; foreach (Item item in l) { item.Emit(b); } return b; } public bool IsCID(String fontName) { int j; for (j=0; j"); } // string index //strings = new String[stringOffsets.length-1]; /* System.err.Println("std strings = "+standardStrings.length); System.err.Println("fnt strings = "+(stringOffsets.length-1)); for (char j=0; j"); } */ // top dict for (int j=0; j= 0) { //System.err.Println("PRIVATE::"); Seek(fonts[j].privateOffset); while (GetPosition() < fonts[j].privateOffset+fonts[j].privateLength) { GetDictItem(); if (key=="Subrs") //Add the private offset to the lsubrs since the offset is // relative to the begining of the PrivateDict fonts[j].privateSubrs = (int)args[0]+fonts[j].privateOffset; } } // fdarray index if (fonts[j].fdarrayOffset >= 0) { int[] fdarrayOffsets = GetIndex(fonts[j].fdarrayOffset); fonts[j].fdprivateOffsets = new int[fdarrayOffsets.Length-1]; fonts[j].fdprivateLengths = new int[fdarrayOffsets.Length-1]; //System.err.Println("FD Font::"); for (int k=0; k