📄 cfffontsubset.java
字号:
arg_count++; continue; } if (b0 >= 251 && b0 <= 254)// Same as above except negative { int w = getCard8(); args[arg_count] = new Integer(-(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] = new Integer(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 therefore 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 beginning 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 = ((Integer)TopElement).intValue() + 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 = ((Integer)TopElement).intValue() + 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<SizeOfMask;i++) getCard8(); } } return NumOfHints; } /** * Function builds the new offset array, object array and assembles the index. * used for creating the glyph and subrs subsetted index * @param Offsets the offset array of the original index * @param Used the hashmap of the used objects * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries * @return the new index subset version * @throws IOException */ protected byte[] BuildNewIndex(int[] Offsets,HashMap Used,byte OperatorForUnusedEntries) throws IOException { int unusedCount = 0; int Offset=0; int[] NewOffsets = new int[Offsets.length]; // Build the Offsets Array for the Subset for (int i=0;i<Offsets.length;++i) { NewOffsets[i] = Offset; // If the object in the offset is also present in the used // HashMap then increment the offset var by its size if (Used.containsKey(new Integer(i))) { Offset += Offsets[i+1] - Offsets[i]; } else { // Else the same offset is kept in i+1. unusedCount++; } } // Offset var determines the size of the object array byte[] NewObjects = new byte[Offset+unusedCount]; // Build the new Object array int unusedOffset = 0; for (int i=0;i<Offsets.length-1;++i) { int start = NewOffsets[i]; int end = NewOffsets[i+1]; NewOffsets[i] = start+unusedOffset; // If start != End then the Object is used // So, we will copy the object data from the font file if (start != end) { // All offsets are Global Offsets relative to the beginning of the font file. // Jump the file pointer to the start address to read from. buf.seek(Offsets[i]); // Read from the buffer and write into the array at start. buf.readFully(NewObjects, start+unusedOffset, end-start); } else { NewObjects[start+unusedOffset] = OperatorForUnusedEntries; unusedOffset++; } } NewOffsets[Offsets.length-1] += unusedOffset; // Use AssembleIndex to build the index from the offset & object arrays return AssembleIndex(NewOffsets,NewObjects); } /** * Function creates the new index, inserting the count,offsetsize,offset array * and object array. * @param NewOffsets the subsetted offset array * @param NewObjects the subsetted object array * @return the new index created */ protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects) { // Calc the index' count field char Count = (char)(NewOffsets.length-1); // Calc the size of the object array int Size = NewOffsets[NewOffsets.length-1]; // Calc the Offsize byte Offsize; if (Size <= 0xff) Offsize = 1; else if (Size <= 0xffff) Offsize = 2; else if (Size <= 0xffffff) Offsize = 3; else Offsize = 4; // The byte array for the new index. The size is calc by // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array byte[] NewIndex = new byte[2+1+Offsize*(Count+1)+NewObjects.length]; // The counter for writing int Place = 0; // Write the count field NewIndex[Place++] = (byte) ((Count >>> 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<NewOffsets.length;i++) { // The value to be written int Num = NewOffsets[i]-NewOffsets[0]+1; // Write in bytes according to the offsize switch (Offsize) { case 4: NewIndex[Place++] = (byte) ((Num >>> 24) & 0xff); case 3: NewIndex[Place++] = (byte) ((Num >>> 16) & 0xff); case 2: NewIndex[Place++] = (byte) ((Num >>> 8) & 0xff); case 1: NewIndex[Place++] = (byte) ((Num >>> 0) & 0xff); } } // Write the new object array one by one for (int i=0;i<NewObjects.length;i++) { NewIndex[Place++] = NewObjects[i]; } // Return the new index return NewIndex; } /** * The function builds the new output stream according to the subset process * @param Font the font * @return the subsetted font stream */ protected byte[] BuildNewFile(int Font) { // Prepare linked list for new font components OutputList = new LinkedList(); // copy the header of the font CopyHeader(); // create a name index BuildIndexHeader(1,1,1); OutputList.addLast(new UInt8Item((char)( 1+fonts[Font].name.length() ))); OutputList.addLast(new StringItem(fonts[Font].name)); // create the topdict Index BuildIndexHeader(1,2,1); OffsetItem topdictIndex1Ref = new IndexOffsetItem(2); OutputList.addLast(topdictIndex1Ref); IndexBaseItem topdictBase = new IndexBaseItem(); OutputList.addLast(topdictBase); // Initialize the Dict Items for later use OffsetItem charsetRef = new DictOffsetItem(); OffsetItem charstringsRef = new DictOffsetItem(); OffsetItem fdarrayRef = new DictOffsetItem(); OffsetItem fdselectRef = new DictOffsetItem(); OffsetItem privateRef = new DictOffsetItem(); // If the font is not CID create the following keys if ( !fonts[Font].isCID ) { // create a ROS key OutputList.addLast(new DictNumberItem(fonts[Font].nstrings)); OutputList.addLast(new DictNumberItem(fonts[Font].nstrings+1)); OutputList.addLast(new DictNumberItem(0)); OutputList.addLast(new UInt8Item((char)12)); OutputList.addLast(new UInt8Item((char)30)); // create a CIDCount key OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs)); OutputList.addLast(new UInt8Item((char)12)); OutputList.addLast(new UInt8Item((char)34)); // Sivan's comments // What about UIDBase (12,35)? Don't know what is it. // I don't think we need FontName; the font I looked at didn't have it. } // Go to the TopDict of the font being processed seek(topdictOffsets[Font]); // Run until the end of the TopDict while (getPosition() < topdictOffsets[Font+1]) { int p1 = getPosition(); getDictItem(); int p2 = getPosition(); // The encoding key is disregarded since CID has no encoding if (key=="Encoding" // These keys will be added manually by the process. || key=="Private" || key=="FDSelect" || key=="FDArray" || key=="charset" || key=="CharStrings" ) { }else { //OtherWise copy key "as is" to the output list OutputList.add(new RangeItem(buf,p1,p2-p1)); } } // Create the FDArray, FDSelect, Charset and CharStrings Keys CreateKeys(fdarrayRef,fdselectRef,charsetRef,charstringsRef); // Mark the end of the top dict area OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase)); // Copy the string index if (fonts[Font].isCID) OutputList.addLast(getEntireIndexRange(stringIndexOffset)); // If the font is not CID we need to append new strings. // We need 3 more strings: Registry, Ordering, and a FontName for one FD. // The total length is at most "Adobe"+"Identity"+63 = 76 else CreateNewStringIndex(Font); // copy the new subsetted global subroutine index OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewGSubrsIndex),0,NewGSubrsIndex.length)); // deal with fdarray, fdselect, and the font descriptors // If the font is CID: if (fonts[Font].isCID) { // copy the FDArray, FDSelect, charset // Copy FDSelect // Mark the beginning OutputList.addLast(new MarkerItem(fdselectRef)); // If an FDSelect exists copy it if (fonts[Font].fdselectOffset>=0) OutputList.addLast(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 entirely OutputList.addLast(new MarkerItem(charsetRef)); OutputList.addLast(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.addLast(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.addLast(PrivateBase); OutputList.addLast(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.addLast(new MarkerItem(charstringsRef)); // Add the subsetted charstring OutputList.addLast(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 Iterator listIter = OutputList.iterator(); while ( listIter.hasNext() ) { Item item = (Item) listIter.next(); item.increment(currentOffset); } // Compute the Xref for each of the offset items listIter = OutputList.iterator(); while ( listIter.hasNext() ) { Item item = (Item) listIter.next(); item.xref(); } int size = currentOffset[0]; byte[] b = new byte[size]; // Emit all the items into the new byte array listIter = OutputList.iterator(); while ( listIter.hasNext() ) { Item item = (Item) listIter.next(); 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.addLast(new RangeItem(buf,0,hdrSize)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -