📄 cfffontsubset.java
字号:
{
int w = getCard8();
args[arg_count] = new Integer((b0-247)*256 + w + 108);
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 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 = ((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
* @return the new index subset version
* @throws IOException
*/
protected byte[] BuildNewIndex(int[] Offsets,HashMap Used) throws IOException
{
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 the same offset is kept in i+1.
}
// Offset var determines the size of the object array
byte[] NewObjects = new byte[Offset];
// Build the new Object array
for (int i=0;i<Offsets.length-1;++i)
{
int start = NewOffsets[i];
int end = NewOffsets[i+1];
// 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 begining 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, end-start);
}
}
// 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 subseted 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);
// Initialise 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 untill 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 manualy 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 entirly
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));
}
/**
* Function Build the header of an index
* @param Count the count field of the index
* @param Offsize the offsize field of the index
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -