using System; using System.Collections; namespace iTextSharp.text.pdf { /** * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts. * The Charstring is subseted for both types. For CID fonts only the FDArray which are used are embedded. * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2 * formatting altough only tested on Type2 Format. * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted. * A font which was not of CID type is transformed into CID as a part of the subset process. * The CID synthetic creation was written by Sivan Toledo * @author Oren Manor & Ygal Blum */ public class CFFFontSubset : CFFFont { /** * The Strings in this array represent Type1/Type2 operator names */ internal static String[] SubrsFunctions = { "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto", "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13", "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask", "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto", "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto" }; /** * The Strings in this array represent Type1/Type2 escape operator names */ internal static String[] SubrsEscapeFuncs = { "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6", "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg", "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse", "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31", "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST" }; /** * A HashMap containing the glyphs used in the text after being converted * to glyph number by the CMap */ internal Hashtable GlyphsUsed; /** * The GlyphsUsed keys as an ArrayList */ internal ArrayList glyphsInList; /** * A HashMap for keeping the FDArrays being used by the font */ internal Hashtable FDArrayUsed = new Hashtable(); /** * A HashMaps array for keeping the subroutines used in each FontDict */ internal Hashtable[] hSubrsUsed; /** * The SubroutinesUsed HashMaps as ArrayLists */ internal ArrayList[] lSubrsUsed; /** * A HashMap for keeping the Global subroutines used in the font */ internal Hashtable hGSubrsUsed = new Hashtable(); /** * The Global SubroutinesUsed HashMaps as ArrayLists */ internal ArrayList lGSubrsUsed = new ArrayList(); /** * A HashMap for keeping the subroutines used in a non-cid font */ internal Hashtable hSubrsUsedNonCID = new Hashtable(); /** * The SubroutinesUsed HashMap as ArrayList */ internal ArrayList lSubrsUsedNonCID = new ArrayList(); /** * An array of the new Indexs for the local Subr. One index for each FontDict */ internal byte[][] NewLSubrsIndex; /** * The new subroutines index for a non-cid font */ internal byte[] NewSubrsIndexNonCID; /** * The new global subroutines index of the font */ internal byte[] NewGSubrsIndex; /** * The new CharString of the font */ internal byte[] NewCharStringsIndex; /** * The bias for the global subroutines */ internal int GBias = 0; /** * The linked list for generating the new font stream */ internal ArrayList OutputList; /** * Number of arguments to the stem operators in a subroutine calculated recursivly */ internal int NumOfHints=0; /** * C'tor for CFFFontSubset * @param rf - The font file * @param GlyphsUsed - a HashMap that contains the glyph used in the subset */ public CFFFontSubset(RandomAccessFileOrArray rf,Hashtable GlyphsUsed) : base(rf) { // Use CFFFont c'tor in order to parse the font file. this.GlyphsUsed = GlyphsUsed; //Put the glyphs into a list glyphsInList = new ArrayList(GlyphsUsed.Keys); for (int i=0;i=0) { // Proces the FDSelect ReadFDSelect(i); // Build the FDArrayUsed hashmap BuildFDArrayUsed(i); } if (fonts[i].isCID) // Build the FD Array used Hash Map ReadFDArray(i); // compute the charset length fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs); } } /** * Calculates the length of the charset according to its format * @param Offset The Charset Offset * @param NumofGlyphs Number of glyphs in the font * @return the length of the Charset */ internal int CountCharset(int Offset,int NumofGlyphs){ int format; int Length=0; Seek(Offset); // Read the format format = GetCard8(); // Calc according to format switch (format){ case 0: Length = 1+2*NumofGlyphs; break; case 1: Length = 1+3*CountRange(NumofGlyphs,1); break; case 2: Length = 1+4*CountRange(NumofGlyphs,2); break; default: break; } return Length; } /** * Function calculates the number of ranges in the Charset * @param NumofGlyphs The number of glyphs in the font * @param Type The format of the Charset * @return The number of ranges in the Charset data structure */ int CountRange(int NumofGlyphs,int Type){ int num=0; char Sid; int i=1,nLeft; while (i= 0) GBias = CalcBias(gsubrIndexOffset,j); // Prepare the new CharStrings Index BuildNewCharString(j); // Prepare the new Global and Local Subrs Indices BuildNewLGSubrs(j); // Build the new file byte[] Ret = BuildNewFile(j); return Ret; } finally { try { buf.Close(); } catch { // empty on purpose } } } /** * Function calcs bias according to the CharString type and the count * of the subrs * @param Offset The offset to the relevent subrs index * @param Font the font * @return The calculated Bias */ protected int CalcBias(int Offset,int Font) { Seek(Offset); int nSubrs = GetCard16(); // If type==1 -> bias=0 if (fonts[Font].CharstringType == 1) return 0; // else calc according to the count else if (nSubrs < 1240) return 107; else if (nSubrs < 33900) return 1131; else return 32768; } /** *Function uses BuildNewIndex to create the new index of the subset charstrings * @param FontIndex the font * @throws IOException */ protected void BuildNewCharString(int FontIndex) { NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed); } /** * Function builds the new local & global subsrs indices. IF CID then All of * the FD Array lsubrs will be subsetted. * @param Font the font * @throws IOException */ protected void BuildNewLGSubrs(int Font) { // If the font is CID then the lsubrs are divided into FontDicts. // for each FD array the lsubrs will be subsetted. if (fonts[Font].isCID) { // Init the hasmap-array and the arraylist-array to hold the subrs used // in each private dict. hSubrsUsed = new Hashtable[fonts[Font].fdprivateOffsets.Length]; lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.Length]; // A [][] which will store the byte array for each new FD Array lsubs index NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.Length][]; // An array to hold the offset for each Lsubr index fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.Length]; // A [][] which will store the offset array for each lsubr index fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.Length][]; // Put the FDarrayUsed into a list ArrayList FDInList = new ArrayList(FDArrayUsed.Keys); // For each FD array which is used subset the lsubr for (int j=0;j=0) { //Scans the Charsting data storing the used Local and Global subroutines // by the glyphs. Scans the Subrs recursivley. BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]); // Builds the New Local Subrs index NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD]); } } } // If the font is not CID && the Private Subr exists then subset: else if (fonts[Font].privateSubrs>=0) { // Build the subrs offsets; fonts[Font].SubrsOffsets = GetIndex(fonts[Font].privateSubrs); //Scans the Charsting data storing the used Local and Global subroutines // by the glyphs. Scans the Subrs recursivley. BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID); } // For all fonts susbset the Global Subroutines // Scan the Global Subr Hashmap recursivly on the Gsubrs BuildGSubrsUsed(Font); if (fonts[Font].privateSubrs>=0) // Builds the New Local Subrs index NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID); //Builds the New Global Subrs index NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed); } /** * The function finds for the FD array processed the local subr offset and its * offset array. * @param Font the font * @param FD The FDARRAY processed */ protected void BuildFDSubrsOffsets(int Font,int FD) { // Initiate to -1 to indicate lsubr operator present fonts[Font].PrivateSubrsOffset[FD] = -1; // Goto begining of objects Seek(fonts[Font].fdprivateOffsets[FD]); // While in the same object: while (GetPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD]) { GetDictItem(); // If the dictItem is the "Subrs" then find and store offset, if (key=="Subrs") fonts[Font].PrivateSubrsOffset[FD] = (int)args[0]+fonts[Font].fdprivateOffsets[FD]; } //Read the lsub index if the lsubr was found if (fonts[Font].PrivateSubrsOffset[FD] >= 0) fonts[Font].PrivateSubrsOffsetsArray[FD] = GetIndex(fonts[Font].PrivateSubrsOffset[FD]); } /** * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap. * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs * calls. * @param Font the font * @param FD FD array processed. 0 indicates function was called by non CID font * @param SubrOffset the offset to the subr index to calc the bias * @param SubrsOffsets the offset array of the subr index * @param hSubr HashMap of the subrs used * @param lSubr ArrayList of the subrs used */ protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,Hashtable hSubr,ArrayList lSubr) { // Calc the Bias for the subr index int LBias = CalcBias(SubrOffset,Font); // For each glyph used find its GID, start & end pos for (int i=0;i= 0) { EmptyStack(); NumOfHints=0; // Using FDSELECT find the FD Array the glyph belongs to. int GlyphFD = fonts[Font].FDSelect[glyph]; // If the Glyph is part of the FD being processed if (GlyphFD == FD) // Find the Subrs called by the glyph and insert to hash: ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); } else // If the font is not CID //Find the Subrs called by the glyph and insert to hash: ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); } // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used for (int i=0;i=0) { // Read and process the subr int Start = SubrsOffsets[Subr]; int End = SubrsOffsets[Subr+1]; ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); } } } /** * Function scans the Glsubr used ArrayList to find recursive calls * to Gsubrs and adds to Hashmap & ArrayList * @param Font the font */ protected void BuildGSubrsUsed(int Font) { int LBias = 0; int SizeOfNonCIDSubrsUsed = 0; if (fonts[Font].privateSubrs>=0) { LBias = CalcBias(fonts[Font].privateSubrs,Font); SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; } // For each global subr used for (int i=0;i=0) { // Read the subr and process int Start = gsubrOffsets[Subr]; int End = gsubrOffsets[Subr+1]; if (fonts[Font].isCID) ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null); else { ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.Count) { for (int j=SizeOfNonCIDSubrsUsed;j=0) { // Read the subr and process int LStart = fonts[Font].SubrsOffsets[LSubr]; int LEnd = fonts[Font].SubrsOffsets[LSubr+1]; ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); } } SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; } } } } } /** * The function reads a subrs (glyph info) between begin and end. * Adds calls to a Lsubr to the hSubr and lSubrs. * Adds calls to a Gsubr to the hGSubr and lGSubrs. * @param begin the start point of the subr * @param end the end point of the subr * @param GBias the bias of the Global Subrs * @param LBias the bias of the Local Subrs * @param hSubr the HashMap for the lSubrs * @param lSubr the ArrayList for the lSubrs */ protected void ReadASubr(int begin,int end,int GBias,int LBias,Hashtable hSubr,ArrayList lSubr,int[] LSubrsOffsets) { // Clear the stack for the subrs EmptyStack(); NumOfHints = 0; // Goto begining of the subr Seek(begin); while (GetPosition() < end) { // Read the next command ReadCommand(); int pos = GetPosition(); Object TopElement=null; if (arg_count > 0) TopElement = args[arg_count-1]; int NumOfArgs = arg_count; // Check the modification needed on the Argument Stack according to key; HandelStack(); // a call to a Lsubr if (key=="callsubr") { // Verify that arguments are passed if (NumOfArgs > 0) { // Calc the index of the Subrs int Subr = (int)TopElement + LBias; // If the subr isn't in the HashMap -> Put in if (!hSubr.ContainsKey(Subr)) { hSubr[Subr] = null; lSubr.Add(Subr); } CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); Seek(pos); } } // a call to a Gsubr else if (key=="callgsubr") { // Verify that arguments are passed if (NumOfArgs > 0) { // Calc the index of the Subrs int Subr = (int)TopElement + GBias; // If the subr isn't in the HashMap -> Put in if (!hGSubrsUsed.ContainsKey(Subr)) { hGSubrsUsed[Subr] = null; lGSubrsUsed.Add(Subr); } CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); Seek(pos); } } // A call to "stem" else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") // Increment the NumOfHints by the number couples of of arguments NumOfHints += NumOfArgs/2; // A call to "mask" else if (key == "hintmask" || key == "cntrmask") { // Compute the size of the mask int SizeOfMask = NumOfHints/8; if (NumOfHints%8 != 0 || SizeOfMask == 0) SizeOfMask++; // Continue the pointer in SizeOfMask steps for (int i=0;i flush the stack */ protected int StackOpp() { if (key == "ifelse") return -3; if (key == "roll" || key == "put") return -2; if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" || key == "div" || key == "mul" || key == "drop" || key == "and" || key == "or" || key == "eq") return -1; if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" || key == "index" || key == "get" || key == "not" || key == "return") return 0; if (key == "random" || key == "dup") return 1; return 2; } /** * Empty the Type2 Stack * */ protected void EmptyStack() { // Null the arguments for (int i=0; i0) { args[arg_count-1]=null; arg_count--; } } /** * Add an item to the stack * */ protected void PushStack() { arg_count++; } /** * The function reads the next command after the file pointer is set */ protected void ReadCommand() { key = null; bool gotKey = false; // Until a key is found while (!gotKey) { // Read the first Char char b0 = GetCard8(); // decode according to the type1/type2 format if (b0 == 28) // the two next bytes represent a short int; { int first = GetCard8(); int second = GetCard8(); args[arg_count] = first<<8 | second; arg_count++; continue; } if (b0 >= 32 && b0 <= 246) // The byte read is the byte; { args[arg_count] = (int)b0 - 139; arg_count++; continue; } if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int { int w = GetCard8(); args[arg_count] = ((int)b0-247)*256 + w + 108; arg_count++; continue; } if (b0 >= 251 && b0 <= 254)// Same as above except negative { int w = GetCard8(); args[arg_count] = -((int)b0-251)*256 - w - 108; arg_count++; continue; } if (b0 == 255)// The next for bytes represent a double. { int first = GetCard8(); int second = GetCard8(); int third = GetCard8(); int fourth = GetCard8(); args[arg_count] = first<<24 | second<<16 | third<<8 | fourth; arg_count++; continue; } if (b0<=31 && b0 != 28) // An operator was found.. Set Key. { gotKey=true; // 12 is an escape command therefor the next byte is a part // of this command if (b0 == 12) { int b1 = GetCard8(); if (b1>SubrsEscapeFuncs.Length-1) b1 = SubrsEscapeFuncs.Length-1; key = SubrsEscapeFuncs[b1]; } else key = SubrsFunctions[b0]; continue; } } } /** * The function reads the subroutine and returns the number of the hint in it. * If a call to another subroutine is found the function calls recursively. * @param begin the start point of the subr * @param end the end point of the subr * @param LBias the bias of the Local Subrs * @param GBias the bias of the Global Subrs * @param LSubrsOffsets The Offsets array of the subroutines * @return The number of hints in the subroutine read. */ protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets) { // Goto begining of the subr Seek(begin); while (GetPosition() < end) { // Read the next command ReadCommand(); int pos = GetPosition(); Object TopElement = null; if (arg_count>0) TopElement = args[arg_count-1]; int NumOfArgs = arg_count; //Check the modification needed on the Argument Stack according to key; HandelStack(); // a call to a Lsubr if (key=="callsubr") { if (NumOfArgs>0) { int Subr = (int)TopElement + LBias; CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); Seek(pos); } } // a call to a Gsubr else if (key=="callgsubr") { if (NumOfArgs>0) { int Subr = (int)TopElement + GBias; CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); Seek(pos); } } // A call to "stem" else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") // Increment the NumOfHints by the number couples of of arguments NumOfHints += NumOfArgs/2; // A call to "mask" else if (key == "hintmask" || key == "cntrmask") { // Compute the size of the mask int SizeOfMask = NumOfHints/8; if (NumOfHints%8 != 0 || SizeOfMask == 0) SizeOfMask++; // Continue the pointer in SizeOfMask steps for (int i=0;i> 8) & 0xff); NewIndex[Place++] = (byte) ((Count >> 0) & 0xff); // Write the offsize field NewIndex[Place++] = Offsize; // Write the offset array according to the offsize for (int i=0;i> 24) & 0xff); goto case 3; case 3: NewIndex[Place++] = (byte) ((Num >> 16) & 0xff); goto case 2; case 2: NewIndex[Place++] = (byte) ((Num >> 8) & 0xff); goto case 1; case 1: NewIndex[Place++] = (byte) ((Num >> 0) & 0xff); break; } } // Write the new object array one by one for (int i=0;i=0) OutputList.Add(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength)); // Else create a new one else CreateFDSelect(fdselectRef,fonts[Font].nglyphs); // Copy the Charset // Mark the beginning and copy entirly OutputList.Add(new MarkerItem(charsetRef)); OutputList.Add(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength)); // Copy the FDArray // If an FDArray exists if (fonts[Font].fdarrayOffset>=0) { // Mark the beginning OutputList.Add(new MarkerItem(fdarrayRef)); // Build a new FDArray with its private dicts and their LSubrs Reconstruct(Font); } else // Else create a new one CreateFDArray(fdarrayRef,privateRef,Font); } // If the font is not CID else { // create FDSelect CreateFDSelect(fdselectRef,fonts[Font].nglyphs); // recreate a new charset CreateCharset(charsetRef,fonts[Font].nglyphs); // create a font dict index (fdarray) CreateFDArray(fdarrayRef,privateRef,Font); } // if a private dict exists insert its subsetted version if (fonts[Font].privateOffset>=0) { // Mark the beginning of the private dict IndexBaseItem PrivateBase = new IndexBaseItem(); OutputList.Add(PrivateBase); OutputList.Add(new MarkerItem(privateRef)); OffsetItem Subr = new DictOffsetItem(); // Build and copy the new private dict CreateNonCIDPrivate(Font,Subr); // Copy the new LSubrs index CreateNonCIDSubrs(Font,PrivateBase,Subr); } // copy the charstring index OutputList.Add(new MarkerItem(charstringsRef)); // Add the subsetted charstring OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.Length)); // now create the new CFF font int[] currentOffset = new int[1]; currentOffset[0] = 0; // Count and save the offset for each item foreach (Item item in OutputList) { item.Increment(currentOffset); } // Compute the Xref for each of the offset items foreach (Item item in OutputList) { item.Xref(); } int size = currentOffset[0]; byte[] b = new byte[size]; // Emit all the items into the new byte array foreach (Item item in OutputList) { item.Emit(b); } // Return the new stream return b; } /** * Function Copies the header from the original fileto the output list */ protected void CopyHeader() { Seek(0); int major = GetCard8(); int minor = GetCard8(); int hdrSize = GetCard8(); int offSize = GetCard8(); nextIndexOffset = hdrSize; OutputList.Add(new RangeItem(buf,0,hdrSize)); } /** * Function Build the header of an index * @param Count the count field of the index * @param Offsize the offsize field of the index * @param First the first offset of the index */ protected void BuildIndexHeader(int Count,int Offsize,int First) { // Add the count field OutputList.Add(new UInt16Item((char)Count)); // count // Add the offsize field OutputList.Add(new UInt8Item((char)Offsize)); // offSize // Add the first offset according to the offsize switch (Offsize){ case 1: OutputList.Add(new UInt8Item((char)First)); // first offset break; case 2: OutputList.Add(new UInt16Item((char)First)); // first offset break; case 3: OutputList.Add(new UInt24Item((char)First)); // first offset break; case 4: OutputList.Add(new UInt32Item((char)First)); // first offset break; default: break; } } /** * Function adds the keys into the TopDict * @param fdarrayRef OffsetItem for the FDArray * @param fdselectRef OffsetItem for the FDSelect * @param charsetRef OffsetItem for the CharSet * @param charstringsRef OffsetItem for the CharString */ protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef) { // create an FDArray key OutputList.Add(fdarrayRef); OutputList.Add(new UInt8Item((char)12)); OutputList.Add(new UInt8Item((char)36)); // create an FDSelect key OutputList.Add(fdselectRef); OutputList.Add(new UInt8Item((char)12)); OutputList.Add(new UInt8Item((char)37)); // create an charset key OutputList.Add(charsetRef); OutputList.Add(new UInt8Item((char)15)); // create a CharStrings key OutputList.Add(charstringsRef); OutputList.Add(new UInt8Item((char)17)); } /** * Function takes the original string item and adds the new strings * to accomodate the CID rules * @param Font the font */ protected void CreateNewStringIndex(int Font) { String fdFontName = fonts[Font].name+"-OneRange"; if (fdFontName.Length > 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; OutputList.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count OutputList.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize for (int i=0; i= 0) { OutputList.Add(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i])); OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].Length)); } } } /** * Calculates how many byte it took to write the offset for the subrs in a specific * private dict. * @param Offset The Offset for the private dict * @param Size The size of the private dict * @return The size of the offset of the subrs in the private dict */ internal int CalcSubrOffsetSize(int Offset,int Size) { // Set the size to 0 int OffsetSize = 0; // Go to the beginning of the private dict Seek(Offset); // Go until the end of the private dict while (GetPosition() < Offset+Size) { int p1 = GetPosition(); GetDictItem(); int p2 = GetPosition(); // When reached to the subrs offset if (key=="Subrs") { // The Offsize (minus the subrs key) OffsetSize = p2-p1-1; } // All other keys are ignored } // return the size return OffsetSize; } /** * Function computes the size of an index * @param indexOffset The offset for the computed index * @return The size of the index */ protected int CountEntireIndexRange(int indexOffset) { // Go to the beginning of the index Seek(indexOffset); // Read the count field int count = GetCard16(); // If count==0 -> size=2 if (count==0) return 2; else { // Read the offsize field int indexOffSize = GetCard8(); // Go to the last element of the offset array Seek(indexOffset+2+1+count*indexOffSize); // The size of the object array is the value of the last element-1 int size = GetOffset(indexOffSize)-1; // Return the size of the entire index return 2+1+(count+1)*indexOffSize+size; } } /** * The function creates a private dict for a font that was not CID * All the keys are copied as is except for the subrs key * @param Font the font * @param Subr The OffsetItem for the subrs of the private */ internal void CreateNonCIDPrivate(int Font,OffsetItem Subr) { // Go to the beginning of the private dict and read untill the end Seek(fonts[Font].privateOffset); while (GetPosition() < fonts[Font].privateOffset+fonts[Font].privateLength) { int p1 = GetPosition(); GetDictItem(); int p2 = GetPosition(); // If the dictItem is the "Subrs" then, // use marker for offset and write operator number if (key=="Subrs") { OutputList.Add(Subr); OutputList.Add(new UInt8Item((char)19)); // Subrs } // Else copy the entire range else OutputList.Add(new RangeItem(buf,p1,p2-p1)); } } /** * the function marks the beginning of the subrs index and adds the subsetted subrs * index to the output list. * @param Font the font * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs * @param Subrs OffsetItem for the subrs * @throws IOException */ internal void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs) { // Mark the beginning of the Subrs index OutputList.Add(new SubrMarkerItem(Subrs,PrivateBase)); // Put the subsetted new subrs index OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.Length)); } } }