📄 truetypefont.java
字号:
private void readBbox() throws DocumentException, IOException {
int tableLocation[];
tableLocation = (int[])tables.get("head");
if (tableLocation == null)
throw new DocumentException("Table 'head' does not exist in " + fileName + style);
rf.seek(tableLocation[0] + TrueTypeFontSubSet.HEAD_LOCA_FORMAT_OFFSET);
boolean locaShortTable = (rf.readUnsignedShort() == 0);
tableLocation = (int[])tables.get("loca");
if (tableLocation == null)
return;
rf.seek(tableLocation[0]);
int locaTable[];
if (locaShortTable) {
int entries = tableLocation[1] / 2;
locaTable = new int[entries];
for (int k = 0; k < entries; ++k)
locaTable[k] = rf.readUnsignedShort() * 2;
}
else {
int entries = tableLocation[1] / 4;
locaTable = new int[entries];
for (int k = 0; k < entries; ++k)
locaTable[k] = rf.readInt();
}
tableLocation = (int[])tables.get("glyf");
if (tableLocation == null)
throw new DocumentException("Table 'glyf' does not exist in " + fileName + style);
int tableGlyphOffset = tableLocation[0];
bboxes = new int[locaTable.length - 1][];
for (int glyph = 0; glyph < locaTable.length - 1; ++glyph) {
int start = locaTable[glyph];
if (start != locaTable[glyph + 1]) {
rf.seek(tableGlyphOffset + start + 2);
bboxes[glyph] = new int[]{
(rf.readShort() * 1000) / head.unitsPerEm,
(rf.readShort() * 1000) / head.unitsPerEm,
(rf.readShort() * 1000) / head.unitsPerEm,
(rf.readShort() * 1000) / head.unitsPerEm};
}
}
}
/** Reads the several maps from the table 'cmap'. The maps of interest are 1.0 for symbolic
* fonts and 3.1 for all others. A symbolic font is defined as having the map 3.0.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
void readCMaps() throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("cmap");
if (table_location == null)
throw new DocumentException("Table 'cmap' does not exist in " + fileName + style);
rf.seek(table_location[0]);
rf.skipBytes(2);
int num_tables = rf.readUnsignedShort();
fontSpecific = false;
int map10 = 0;
int map31 = 0;
int map30 = 0;
for (int k = 0; k < num_tables; ++k) {
int platId = rf.readUnsignedShort();
int platSpecId = rf.readUnsignedShort();
int offset = rf.readInt();
if (platId == 3 && platSpecId == 0) {
fontSpecific = true;
map30 = offset;
}
else if (platId == 3 && platSpecId == 1) {
map31 = offset;
}
if (platId == 1 && platSpecId == 0) {
map10 = offset;
}
}
if (map10 > 0) {
rf.seek(table_location[0] + map10);
int format = rf.readUnsignedShort();
switch (format) {
case 0:
cmap10 = readFormat0();
break;
case 4:
cmap10 = readFormat4();
break;
case 6:
cmap10 = readFormat6();
break;
}
}
if (map31 > 0) {
rf.seek(table_location[0] + map31);
int format = rf.readUnsignedShort();
if (format == 4) {
cmap31 = readFormat4();
}
}
if (map30 > 0) {
rf.seek(table_location[0] + map30);
int format = rf.readUnsignedShort();
if (format == 4) {
cmap10 = readFormat4();
}
}
}
/** The information in the maps of the table 'cmap' is coded in several formats.
* Format 0 is the Apple standard character to glyph index mapping table.
* @return a <CODE>HashMap</CODE> representing this map
* @throws IOException the font file could not be read
*/
HashMap readFormat0() throws IOException {
HashMap h = new HashMap();
rf.skipBytes(4);
for (int k = 0; k < 256; ++k) {
int r[] = new int[2];
r[0] = rf.readUnsignedByte();
r[1] = getGlyphWidth(r[0]);
h.put(new Integer(k), r);
}
return h;
}
/** The information in the maps of the table 'cmap' is coded in several formats.
* Format 4 is the Microsoft standard character to glyph index mapping table.
* @return a <CODE>HashMap</CODE> representing this map
* @throws IOException the font file could not be read
*/
HashMap readFormat4() throws IOException {
HashMap h = new HashMap();
int table_lenght = rf.readUnsignedShort();
rf.skipBytes(2);
int segCount = rf.readUnsignedShort() / 2;
rf.skipBytes(6);
int endCount[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
endCount[k] = rf.readUnsignedShort();
}
rf.skipBytes(2);
int startCount[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
startCount[k] = rf.readUnsignedShort();
}
int idDelta[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
idDelta[k] = rf.readUnsignedShort();
}
int idRO[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
idRO[k] = rf.readUnsignedShort();
}
int glyphId[] = new int[table_lenght / 2 - 8 - segCount * 4];
for (int k = 0; k < glyphId.length; ++k) {
glyphId[k] = rf.readUnsignedShort();
}
for (int k = 0; k < segCount; ++k) {
int glyph;
for (int j = startCount[k]; j <= endCount[k] && j != 0xFFFF; ++j) {
if (idRO[k] == 0) {
glyph = (j + idDelta[k]) & 0xFFFF;
}
else {
int idx = k + idRO[k] / 2 - segCount + j - startCount[k];
if (idx >= glyphId.length)
continue;
glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF;
}
int r[] = new int[2];
r[0] = glyph;
r[1] = getGlyphWidth(r[0]);
h.put(new Integer(fontSpecific ? ((j & 0xff00) == 0xf000 ? j & 0xff : j) : j), r);
}
}
return h;
}
/** The information in the maps of the table 'cmap' is coded in several formats.
* Format 6 is a trimmed table mapping. It is similar to format 0 but can have
* less than 256 entries.
* @return a <CODE>HashMap</CODE> representing this map
* @throws IOException the font file could not be read
*/
HashMap readFormat6() throws IOException {
HashMap h = new HashMap();
rf.skipBytes(4);
int start_code = rf.readUnsignedShort();
int code_count = rf.readUnsignedShort();
for (int k = 0; k < code_count; ++k) {
int r[] = new int[2];
r[0] = rf.readUnsignedShort();
r[1] = getGlyphWidth(r[0]);
h.put(new Integer(k + start_code), r);
}
return h;
}
/** Reads the kerning information from the 'kern' table.
* @throws IOException the font file could not be read
*/
void readKerning() throws IOException {
int table_location[];
table_location = (int[])tables.get("kern");
if (table_location == null)
return;
rf.seek(table_location[0] + 2);
int nTables = rf.readUnsignedShort();
int checkpoint = table_location[0] + 4;
int length = 0;
for (int k = 0; k < nTables; ++k) {
checkpoint += length;
rf.seek(checkpoint);
rf.skipBytes(2);
length = rf.readUnsignedShort();
int coverage = rf.readUnsignedShort();
if ((coverage & 0xfff7) == 0x0001) {
int nPairs = rf.readUnsignedShort();
rf.skipBytes(6);
for (int j = 0; j < nPairs; ++j) {
int pair = rf.readInt();
int value = ((int)rf.readShort() * 1000) / head.unitsPerEm;
kerning.put(pair, value);
}
}
}
}
/** Gets the kerning between two Unicode chars.
* @param char1 the first char
* @param char2 the second char
* @return the kerning to be applied
*/
public int getKerning(char char1, char char2) {
int metrics[] = getMetricsTT(char1);
if (metrics == null)
return 0;
int c1 = metrics[0];
metrics = getMetricsTT(char2);
if (metrics == null)
return 0;
int c2 = metrics[0];
return kerning.get((c1 << 16) + c2);
}
/** Gets the width from the font according to the unicode char <CODE>c</CODE>.
* If the <CODE>name</CODE> is null it's a symbolic font.
* @param c the unicode char
* @param name the glyph name
* @return the width of the char
*/
int getRawWidth(int c, String name) {
HashMap map = null;
if (name == null || cmap31 == null)
map = cmap10;
else
map = cmap31;
if (map == null)
return 0;
int metric[] = (int[])map.get(new Integer(c));
if (metric == null)
return 0;
return metric[1];
}
/** Generates the font descriptor for this font.
* @return the PdfDictionary containing the font descriptor or <CODE>null</CODE>
* @param subsetPrefix the subset prefix
* @param fontStream the indirect reference to a PdfStream containing the font or <CODE>null</CODE>
* @throws DocumentException if there is an error
*/
protected PdfDictionary getFontDescriptor(PdfIndirectReference fontStream, String subsetPrefix) {
PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR);
dic.put(PdfName.ASCENT, new PdfNumber((int)os_2.sTypoAscender * 1000 / head.unitsPerEm));
dic.put(PdfName.CAPHEIGHT, new PdfNumber((int)os_2.sCapHeight * 1000 / head.unitsPerEm));
dic.put(PdfName.DESCENT, new PdfNumber((int)os_2.sTypoDescender * 1000 / head.unitsPerEm));
dic.put(PdfName.FONTBBOX, new PdfRectangle(
(int)head.xMin * 1000 / head.unitsPerEm,
(int)head.yMin * 1000 / head.unitsPerEm,
(int)head.xMax * 1000 / head.unitsPerEm,
(int)head.yMax * 1000 / head.unitsPerEm));
if (cff) {
if (encoding.startsWith("Identity-"))
dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName+"-"+encoding));
else
dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style));
}
else
dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style));
dic.put(PdfName.ITALICANGLE, new PdfNumber(italicAngle));
dic.put(PdfName.STEMV, new PdfNumber(80));
if (fontStream != null) {
if (cff)
dic.put(PdfName.FONTFILE3, fontStream);
else
dic.put(PdfName.FONTFILE2, fontStream);
}
int flags = 0;
if (isFixedPitch)
flags |= 1;
flags |= fontSpecific ? 4 : 32;
if ((head.macStyle & 2) != 0)
flags |= 64;
if ((head.macStyle & 1) != 0)
flags |= 262144;
dic.put(PdfName.FLAGS, new PdfNumber(flags));
return dic;
}
/** Generates the font dictionary for this font.
* @return the PdfDictionary containing the font dictionary
* @param subsetPrefix the subset prefx
* @param firstChar the first valid character
* @param lastChar the last valid character
* @param shortTag a 256 bytes long <CODE>byte</CODE> array where each unused byte is represented by 0
* @param fontDescriptor the indirect reference to a PdfDictionary containing the font descriptor or <CODE>null</CODE>
* @throws DocumentException if there is an error
*/
protected PdfDictionary getFontBaseType(PdfIndirectReference fontDescriptor, String subsetPrefix, int firstChar, int lastChar, byte shortTag[]) {
PdfDictionary dic = new PdfDictionary(PdfName.FONT);
if (cff) {
dic.put(PdfName.SUBTYPE, PdfName.TYPE1);
dic.put(PdfName.BASEFONT, new PdfName(fontName + style));
}
else {
dic.put(PdfName.SUBTYPE, PdfName.TRUETYPE);
dic.put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style));
}
dic.put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style));
if (!fontSpecific) {
for (int k = firstChar; k <= lastChar; ++k) {
if (!differences[k].equals(notdef)) {
firstChar = k;
break;
}
}
if (encoding.equals("Cp1252") || encoding.equals("MacRoman"))
dic.put(PdfName.ENCODING, encoding.equals("Cp1252") ? PdfName.WIN_ANSI_ENCODING : PdfName.MAC_ROMAN_ENCODING);
else {
PdfDictionary enc = new PdfDictionary(PdfName.ENCODING);
PdfArray dif = new PdfArray();
boolean gap = true;
for (int k = firstChar; k <= lastChar; ++k) {
if (shortTag[k] != 0) {
if (gap) {
dif.add(new PdfNumber(k));
gap = false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -