org.apache.fop.fonts.truetype.TTFFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fop Show documentation
Show all versions of fop Show documentation
Apache FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, AFP, TIFF, PNG, SVG, XML (area tree representation), Print, AWT and TXT. The primary output target is PDF.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: TTFFile.java 1695082 2015-08-10 14:15:48Z rmeyer $ */
package org.apache.fop.fonts.truetype;
import java.io.IOException;
/**
* Reads a TrueType file or a TrueType Collection.
* The TrueType spec can be found at the Microsoft.
* Typography site: http://www.microsoft.com/truetype/
*/
public class TTFFile extends OpenFont {
public TTFFile() {
this(true, false);
}
/**
* Constructor
* @param useKerning true if kerning data should be loaded
* @param useAdvanced true if advanced typographic tables should be loaded
*/
public TTFFile(boolean useKerning, boolean useAdvanced) {
super(useKerning, useAdvanced);
}
/**
* Read the "name" table.
* @throws IOException In case of a I/O problem
*/
protected void readName() throws IOException {
seekTab(fontFile, OFTableName.NAME, 2);
int i = fontFile.getCurrentPos();
int n = fontFile.readTTFUShort();
int j = fontFile.readTTFUShort() + i - 2;
i += 2 * 2;
while (n-- > 0) {
// getLogger().debug("Iteration: " + n);
fontFile.seekSet(i);
final int platformID = fontFile.readTTFUShort();
final int encodingID = fontFile.readTTFUShort();
final int languageID = fontFile.readTTFUShort();
int k = fontFile.readTTFUShort();
int l = fontFile.readTTFUShort();
if (((platformID == 1 || platformID == 3)
&& (encodingID == 0 || encodingID == 1))) {
fontFile.seekSet(j + fontFile.readTTFUShort());
String txt;
if (platformID == 3) {
txt = fontFile.readTTFString(l, encodingID);
} else {
txt = fontFile.readTTFString(l);
}
if (log.isDebugEnabled()) {
log.debug(platformID + " "
+ encodingID + " "
+ languageID + " "
+ k + " " + txt);
}
switch (k) {
case 0:
if (notice.length() == 0) {
notice = txt;
}
break;
case 1: //Font Family Name
case 16: //Preferred Family
familyNames.add(txt);
break;
case 2:
if (subFamilyName.length() == 0) {
subFamilyName = txt;
}
break;
case 4:
if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) {
fullName = txt;
}
break;
case 6:
if (postScriptName.length() == 0) {
postScriptName = txt;
}
break;
default:
break;
}
}
i += 6 * 2;
}
}
/**
* Read the "glyf" table to find the bounding boxes.
* @throws IOException In case of a I/O problem
*/
private void readGlyf() throws IOException {
OFDirTabEntry dirTab = dirTabs.get(OFTableName.GLYF);
if (dirTab == null) {
throw new IOException("glyf table not found, cannot continue");
}
for (int i = 0; i < (numberOfGlyphs - 1); i++) {
if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
fontFile.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
fontFile.skip(2);
final int[] bbox = {
fontFile.readTTFShort(),
fontFile.readTTFShort(),
fontFile.readTTFShort(),
fontFile.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox());
}
}
long n = (dirTabs.get(OFTableName.GLYF)).getOffset();
for (int i = 0; i < numberOfGlyphs; i++) {
if ((i + 1) >= mtxTab.length
|| mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
fontFile.seekSet(n + mtxTab[i].getOffset());
fontFile.skip(2);
final int[] bbox = {
fontFile.readTTFShort(),
fontFile.readTTFShort(),
fontFile.readTTFShort(),
fontFile.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
/**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/
final int bbox0 = mtxTab[0].getBoundingBox()[0];
final int[] bbox = {bbox0, bbox0, bbox0, bbox0};
mtxTab[i].setBoundingBox(bbox);
/* Original code
mtxTab[i].bbox[0] = mtxTab[0].bbox[0];
mtxTab[i].bbox[1] = mtxTab[0].bbox[0];
mtxTab[i].bbox[2] = mtxTab[0].bbox[0];
mtxTab[i].bbox[3] = mtxTab[0].bbox[0]; */
}
if (log.isTraceEnabled()) {
log.trace(mtxTab[i].toString(this));
}
}
}
@Override
protected void updateBBoxAndOffset() throws IOException {
readIndexToLocation();
readGlyf();
}
/**
* Read the "loca" table.
* @throws IOException In case of a I/O problem
*/
protected final void readIndexToLocation()
throws IOException {
if (!seekTab(fontFile, OFTableName.LOCA, 0)) {
throw new IOException("'loca' table not found, happens when the font file doesn't"
+ " contain TrueType outlines (trying to read an OpenType CFF font maybe?)");
}
for (int i = 0; i < numberOfGlyphs; i++) {
mtxTab[i].setOffset(locaFormat == 1 ? fontFile.readTTFULong()
: (fontFile.readTTFUShort() << 1));
}
lastLoca = (locaFormat == 1 ? fontFile.readTTFULong()
: (fontFile.readTTFUShort() << 1));
}
/**
* Gets the last location of the glyf table
* @return The last location as a long
*/
public long getLastGlyfLocation() {
return lastLoca;
}
@Override
protected void initializeFont(FontFileReader in) throws IOException {
fontFile = in;
}
}