diff --git a/src/core/iTextSharp/text/pdf/CFFFontSubset.cs b/src/core/iTextSharp/text/pdf/CFFFontSubset.cs index 7b93e9d..a0db533 100644 --- a/src/core/iTextSharp/text/pdf/CFFFontSubset.cs +++ b/src/core/iTextSharp/text/pdf/CFFFontSubset.cs @@ -1,1578 +1,1595 @@ -using System; -using System.Collections; +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" + }; + + /** + * Operator codes for unused CharStrings and unused local and global Subrs + */ + internal const byte ENDCHAR_OP = 14; + internal const byte RETURN_OP = 11; -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)); - } - } + /** + * 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,ENDCHAR_OP); + } + + /** + * 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],RETURN_OP); + } + } + } + // 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,RETURN_OP); + //Builds the New Global Subrs index + NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed,RETURN_OP); + } + + /** + * 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)); + } + } } \ No newline at end of file