📄 cfffontsubset.java
字号:
/*
* $Id: CFFFontSubset.java 2671 2007-04-03 16:08:04Z psoares33 $
* $Name$
*
* Copyright 2004 Oren Manor and Ygal Blum
*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*
* The Original Code is 'iText, a free JAVA-PDF library'.
*
* The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
* the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie.
* All Rights Reserved.
* Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
* are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved.
*
* Contributor(s): all the names of the contributors are added in the source code
* where applicable.
*
* Alternatively, the contents of this file may be used under the terms of the
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
* provisions of LGPL are applicable instead of those above. If you wish to
* allow use of your version of this file only under the terms of the LGPL
* License and not to allow others to use your version of this file under
* the MPL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the LGPL.
* If you do not delete the provisions above, a recipient may use your version
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MPL as stated above or under the terms of the GNU
* Library General Public License as published by the Free Software Foundation;
* either version 2 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
* details.
*
* If you didn't download this code from the following link, you should check if
* you aren't using an obsolete version:
* http://www.lowagie.com/iText/
*/
package com.lowagie.text.pdf;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
/**
* 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 (sivan@math.tau.ac.il)
* @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il)
*/
public class CFFFontSubset extends CFFFont {
/**
* The Strings in this array represent Type1/Type2 operator names
*/
static final 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
*/
static final 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
*/
HashMap GlyphsUsed;
/**
* The GlyphsUsed keys as an ArrayList
*/
ArrayList glyphsInList;
/**
* A HashMap for keeping the FDArrays being used by the font
*/
HashMap FDArrayUsed = new HashMap();
/**
* A HashMaps array for keeping the subroutines used in each FontDict
*/
HashMap[] hSubrsUsed;
/**
* The SubroutinesUsed HashMaps as ArrayLists
*/
ArrayList[] lSubrsUsed;
/**
* A HashMap for keeping the Global subroutines used in the font
*/
HashMap hGSubrsUsed = new HashMap();
/**
* The Global SubroutinesUsed HashMaps as ArrayLists
*/
ArrayList lGSubrsUsed = new ArrayList();
/**
* A HashMap for keeping the subroutines used in a non-cid font
*/
HashMap hSubrsUsedNonCID = new HashMap();
/**
* The SubroutinesUsed HashMap as ArrayList
*/
ArrayList lSubrsUsedNonCID = new ArrayList();
/**
* An array of the new Indexs for the local Subr. One index for each FontDict
*/
byte[][] NewLSubrsIndex;
/**
* The new subroutines index for a non-cid font
*/
byte[] NewSubrsIndexNonCID;
/**
* The new global subroutines index of the font
*/
byte[] NewGSubrsIndex;
/**
* The new CharString of the font
*/
byte[] NewCharStringsIndex;
/**
* The bias for the global subroutines
*/
int GBias = 0;
/**
* The linked list for generating the new font stream
*/
LinkedList OutputList;
/**
* Number of arguments to the stem operators in a subroutine calculated recursivly
*/
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,HashMap GlyphsUsed){
// Use CFFFont c'tor in order to parse the font file.
super(rf);
this.GlyphsUsed = GlyphsUsed;
//Put the glyphs into a list
glyphsInList = new ArrayList(GlyphsUsed.keySet());
for (int i=0;i<fonts.length;++i)
{
// Read the number of glyphs in the font
seek(fonts[i].charstringsOffset);
fonts[i].nglyphs = getCard16();
// Jump to the count field of the String Index
seek(stringIndexOffset);
fonts[i].nstrings = getCard16()+standardStrings.length;
// For each font save the offset array of the charstring
fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset);
// Proces the FDSelect if exist
if (fonts[i].fdselectOffset>=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
*/
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<NumofGlyphs){
num++;
Sid = getCard16();
if (Type==1)
nLeft = getCard8();
else
nLeft = getCard16();
i += nLeft+1;
}
return num;
}
/**
* Read the FDSelect of the font and compute the array and its length
* @param Font The index of the font being processed
*/
protected void readFDSelect(int Font)
{
// Restore the number of glyphs
int NumOfGlyphs = fonts[Font].nglyphs;
int[] FDSelect = new int[NumOfGlyphs];
// Go to the beginning of the FDSelect
seek(fonts[Font].fdselectOffset);
// Read the FDSelect's format
fonts[Font].FDSelectFormat = getCard8();
switch(fonts[Font].FDSelectFormat){
// Format==0 means each glyph has an entry that indicated
// its FD.
case 0:
for (int i=0;i<NumOfGlyphs;i++)
{
FDSelect[i] = getCard8();
}
// The FDSelect's Length is one for each glyph + the format
// for later use
fonts[Font].FDSelectLength = fonts[Font].nglyphs+1;
break;
case 3:
// Format==3 means the ranges version
// The number of ranges
int nRanges = getCard16();
int l=0;
// Read the first in the first range
int first = getCard16();
for (int i=0;i<nRanges;i++)
{
// Read the FD index
int fd = getCard8();
// Read the first of the next range
int last = getCard16();
// Calc the steps and write to the array
int steps = last-first;
for (int k=0;k<steps;k++)
{
FDSelect[l] = fd;
l++;
}
// The last from this iteration is the first of the next
first = last;
}
// Store the length for later use
fonts[Font].FDSelectLength = 1+2+nRanges*3+2;
break;
default:
break;
}
// Save the FDSelect of the font
fonts[Font].FDSelect = FDSelect;
}
/**
* Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used
* @param Font the Number of font being processed
*/
protected void BuildFDArrayUsed(int Font)
{
int[] FDSelect = fonts[Font].FDSelect;
// For each glyph used
for (int i=0;i<glyphsInList.size();i++)
{
// Pop the glyphs index
int glyph = ((Integer)glyphsInList.get(i)).intValue();
// Pop the glyph's FD
int FD = FDSelect[glyph];
// Put the FD index into the FDArrayUsed HashMap
FDArrayUsed.put(new Integer(FD),null);
}
}
/**
* Read the FDArray count, offsize and Offset array
* @param Font
*/
protected void ReadFDArray(int Font)
{
seek(fonts[Font].fdarrayOffset);
fonts[Font].FDArrayCount = getCard16();
fonts[Font].FDArrayOffsize = getCard8();
// Since we will change values inside the FDArray objects
// We increase its offsize to prevent errors
if (fonts[Font].FDArrayOffsize < 4)
fonts[Font].FDArrayOffsize++;
fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset);
}
/**
* The Process function extracts one font out of the CFF file and returns a
* subset version of the original.
* @param fontName - The name of the font to be taken out of the CFF
* @return The new font stream
* @throws IOException
*/
public byte[] Process(String fontName)throws IOException{
try
{
// Verify that the file is open
buf.reOpen();
// Find the Font that we will be dealing with
int j;
for (j=0; j<fonts.length; j++)
if (fontName.equals(fonts[j].name)) break;
if (j==fonts.length) return null;
// Calc the bias for the global subrs
if (gsubrIndexOffset >= 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 (Exception e) {
// 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -