/*
* $Id$
- * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/
package org.apache.fop.fonts;
-import java.io.FileInputStream;
+
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.File;
import java.io.IOException;
* provides file like functions for array access.
*/
public class FontFileReader {
+
private int fsize; // file size
private int current; // current position in file
private byte[] file;
/**
- * Initialisez class and reads stream. Init does not close stream
- * @param stream InputStream to read from
- * @param start initial size av array to read to
- * @param inc if initial size isn't enough, create
- * new array with size + inc
+ * Initializes class and reads stream. Init does not close stream.
+ *
+ * @param in InputStream to read from new array with size + inc
+ * @throws IOException In case of an I/O problem
*/
- private void init(InputStream stream, int start,
- int inc) throws java.io.IOException {
- fsize = 0;
- current = 0;
-
- file = new byte[start];
-
- int l = stream.read(file, 0, start);
- fsize += l;
-
- if (l == start) {
- // More to read - needs to extend
- byte[] tmpbuf;
-
- while (l > 0) {
- tmpbuf = new byte[file.length + inc];
- System.arraycopy(file, 0, tmpbuf, 0, file.length);
- l = stream.read(tmpbuf, file.length, inc);
- fsize += l;
- file = tmpbuf;
-
- if (l < inc) // whole file read. No need to loop again
-
+ private void init(InputStream in) throws java.io.IOException {
+ java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
+ try {
+ copyStream(in, bout);
+ this.file = bout.toByteArray();
+ this.fsize = this.file.length;
+ this.current = 0;
+ } finally {
+ bout.close();
+ }
+ }
- l = 0;
- }
+ /**@todo Use method from Avalon Excalibur IO or Jakarta Commons IO*/
+ private void copyStream(InputStream in, OutputStream out) throws IOException {
+ final int bufferSize = 2048;
+ final byte[] buf = new byte[bufferSize];
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
}
}
/**
* Constructor
+ *
* @param fileName filename to read
+ * @throws IOException In case of an I/O problem
*/
- public FontFileReader(String fileName) throws java.io.IOException {
+ public FontFileReader(String fileName) throws IOException {
+ final File f = new File(fileName);
+ InputStream in = new java.io.FileInputStream(f);
+ try {
+ init(in);
+ } finally {
+ in.close();
+ }
+ }
+
- // Get estimates for file size and increment
- File f = new File(fileName);
- FileInputStream ins = new FileInputStream(fileName);
- init(ins, (int)(f.length() + 1), (int)(f.length() / 10));
- ins.close();
+ /**
+ * Constructor
+ *
+ * @param in InputStream to read from
+ * @throws IOException In case of an I/O problem
+ */
+ public FontFileReader(InputStream in) throws IOException {
+ init(in);
}
+
/**
* Set current file position to offset
+ *
+ * @param offset The new offset to set
+ * @throws IOException In case of an I/O problem
*/
- public void seek_set(long offset) throws IOException {
- if (offset > fsize || offset < 0)
+ public void seekSet(long offset) throws IOException {
+ if (offset > fsize || offset < 0) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize
+ " offset=" + offset);
+ }
current = (int)offset;
}
/**
* Set current file position to offset
+ *
+ * @param add The number of bytes to advance
+ * @throws IOException In case of an I/O problem
*/
- public void seek_add(long add) throws IOException {
- seek_set(current + add);
+ public void seekAdd(long add) throws IOException {
+ seekSet(current + add);
}
+ /**
+ * Skip a given number of bytes.
+ *
+ * @param add The number of bytes to advance
+ * @throws IOException In case of an I/O problem
+ */
public void skip(long add) throws IOException {
- seek_add(add);
+ seekAdd(add);
}
/**
- * return current file position
+ * Returns current file position.
+ *
+ * @return int The current position.
*/
public int getCurrentPos() {
return current;
}
+ /**
+ * Returns the size of the file.
+ *
+ * @return int The filesize
+ */
public int getFileSize() {
return fsize;
}
-
/**
- * Read 1 byte, throws EOFException on end of file
+ * Read 1 byte.
+ *
+ * @return One byte
+ * @throws IOException If EOF is reached
*/
public byte read() throws IOException {
- if (current > fsize)
+ if (current > fsize) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize);
+ }
- byte ret = file[current++];
+ final byte ret = file[current++];
return ret;
}
-
-
/**
- * Read 1 signed byte from InputStream
+ * Read 1 signed byte.
+ *
+ * @return One byte
+ * @throws IOException If EOF is reached
*/
public final byte readTTFByte() throws IOException {
return read();
}
/**
- * Read 1 unsigned byte from InputStream
+ * Read 1 unsigned byte.
+ *
+ * @return One unsigned byte
+ * @throws IOException If EOF is reached
*/
public final int readTTFUByte() throws IOException {
- byte buf = read();
+ final byte buf = read();
- if (buf < 0)
+ if (buf < 0) {
return (int)(256 + buf);
- else
+ } else {
return (int)buf;
+ }
}
/**
- * Read 2 bytes signed from InputStream
+ * Read 2 bytes signed.
+ *
+ * @return One signed short
+ * @throws IOException If EOF is reached
*/
public final short readTTFShort() throws IOException {
- int ret = (readTTFUByte() << 8) + readTTFUByte();
- short sret = (short)ret;
-
+ final int ret = (readTTFUByte() << 8) + readTTFUByte();
+ final short sret = (short)ret;
return sret;
}
/**
- * Read 2 bytes unsigned from InputStream
+ * Read 2 bytes unsigned.
+ *
+ * @return One unsigned short
+ * @throws IOException If EOF is reached
*/
public final int readTTFUShort() throws IOException {
- int ret = (readTTFUByte() << 8) + readTTFUByte();
-
+ final int ret = (readTTFUByte() << 8) + readTTFUByte();
return (int)ret;
}
/**
- * Write a USHort at a given position
+ * Write a USHort at a given position.
+ *
+ * @param pos The absolute position to write to
+ * @param val The value to write
+ * @throws IOException If EOF is reached
*/
public final void writeTTFUShort(int pos, int val) throws IOException {
- if ((pos + 2) > fsize)
+ if ((pos + 2) > fsize) {
throw new java.io.EOFException("Reached EOF");
- byte b1 = (byte)((val >> 8) & 0xff);
- byte b2 = (byte)(val & 0xff);
+ }
+ final byte b1 = (byte)((val >> 8) & 0xff);
+ final byte b2 = (byte)(val & 0xff);
file[pos] = b1;
file[pos + 1] = b2;
}
/**
- * Read 2 bytes signed from InputStream at position pos
- * without changing current position
+ * Read 2 bytes signed at position pos without changing current position.
+ *
+ * @param pos The absolute position to read from
+ * @return One signed short
+ * @throws IOException If EOF is reached
*/
public final short readTTFShort(long pos) throws IOException {
- long cp = getCurrentPos();
- seek_set(pos);
- short ret = readTTFShort();
- seek_set(cp);
+ final long cp = getCurrentPos();
+ seekSet(pos);
+ final short ret = readTTFShort();
+ seekSet(cp);
return ret;
}
/**
- * Read 2 bytes unsigned from InputStream at position pos
- * without changing current position
+ * Read 2 bytes unsigned at position pos without changing current position.
+ *
+ * @param pos The absolute position to read from
+ * @return One unsigned short
+ * @throws IOException If EOF is reached
*/
public final int readTTFUShort(long pos) throws IOException {
long cp = getCurrentPos();
- seek_set(pos);
+ seekSet(pos);
int ret = readTTFUShort();
- seek_set(cp);
+ seekSet(cp);
return ret;
}
/**
- * Read 4 bytes from InputStream
+ * Read 4 bytes.
+ *
+ * @return One signed integer
+ * @throws IOException If EOF is reached
*/
public final int readTTFLong() throws IOException {
long ret = readTTFUByte(); // << 8;
}
/**
- * Read 4 bytes from InputStream
+ * Read 4 bytes.
+ *
+ * @return One unsigned integer
+ * @throws IOException If EOF is reached
*/
public final long readTTFULong() throws IOException {
long ret = readTTFUByte();
}
/**
- * Read a 0 terminatet ISO-8859-1 string
+ * Read a NUL terminated ISO-8859-1 string.
+ *
+ * @return A String
+ * @throws IOException If EOF is reached
*/
public final String readTTFString() throws IOException {
int i = current;
while (file[i++] != 0) {
- if (i > fsize)
+ if (i > fsize) {
throw new java.io.EOFException("Reached EOF, file size="
+ fsize);
+ }
}
byte[] tmp = new byte[i - current];
/**
- * Read an ISO-8859-1 string of len bytes
+ * Read an ISO-8859-1 string of len bytes.
+ *
+ * @param len The length of the string to read
+ * @return A String
+ * @throws IOException If EOF is reached
*/
public final String readTTFString(int len) throws IOException {
- if ((len + current) > fsize)
+ if ((len + current) > fsize) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize);
+ }
byte[] tmp = new byte[len];
System.arraycopy(file, current, tmp, 0, len);
/**
* Return a copy of the internal array
+ *
+ * @param offset The absolute offset to start reading from
+ * @param length The number of bytes to read
+ * @return An array of bytes
* @throws IOException if out of bounds
*/
public byte[] getBytes(int offset,
- int length) throws java.io.IOException {
- if ((offset + length) > fsize)
+ int length) throws IOException {
+ if ((offset + length) > fsize) {
throw new java.io.IOException("Reached EOF");
+ }
byte[] ret = new byte[length];
System.arraycopy(file, offset, ret, 0, length);
}
-}
+}
\ No newline at end of file
/*
* $Id$
- * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/
package org.apache.fop.fonts;
-import java.io.*;
+
+import java.io.IOException;
import java.util.Iterator;
-import java.util.HashMap;
-import java.util.ArrayList;
+import java.util.Map;
+import java.util.List;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.avalon.framework.logger.Logger;
/**
* Reads a TrueType file or a TrueType Collection.
- * The TrueType spec can be found at the Microsoft
+ * The TrueType spec can be found at the Microsoft.
* Typography site: http://www.microsoft.com/truetype/
*/
-public class TTFFile {
+public class TTFFile extends AbstractLogEnabled {
+
static final byte NTABS = 24;
static final int NMACGLYPHS = 258;
static final int MAX_CHAR_CODE = 255;
static final int ENC_BUF_SIZE = 1024;
- private Logger log;
-
- static String encoding = "WinAnsiEncoding"; // Default encoding
- short firstChar = 0;
- boolean is_embeddable = true;
- boolean hasSerifs = true;
- HashMap dirTabs; // Table directory
- HashMap kerningTab; // for CIDs
- HashMap ansiKerningTab; // For winAnsiEncoding
- ArrayList cmaps;
- ArrayList unicodeMapping; //
-
- int upem; // unitsPerEm from "head" table
- int nhmtx; // Number of horizontal metrics
- int post_format;
- int loca_format;
- long lastLoca = 0; // offset to last loca
- int nglyphs; // Number of glyphs in font (read from "maxp" table)
- int nmglyphs; // Used in fixWidths - remove?
-
- TTFMtxEntry mtx_tab[]; // Contains glyph data
- int[] mtx_encoded = null;
-
- String fontName = "";
- String fullName = "";
- String notice = "";
- String familyName = "";
- String subFamilyName = "";
-
- long italicAngle = 0;
- long isFixedPitch = 0;
- int fontBBox1 = 0;
- int fontBBox2 = 0;
- int fontBBox3 = 0;
- int fontBBox4 = 0;
- int capHeight = 0;
- int underlinePosition = 0;
- int underlineThickness = 0;
- int xHeight = 0;
- int ascender = 0;
- int descender = 0;
-
- short lastChar = 0;
-
- int ansiWidth[];
- HashMap ansiIndex;
-
- public void setLogger(Logger l) {
- log = l;
- }
+ private String encoding = "WinAnsiEncoding"; // Default encoding
+
+ private short firstChar = 0;
+ private boolean isEmbeddable = true;
+ private boolean hasSerifs = true;
+ /**
+ * Table directory
+ */
+ protected Map dirTabs;
+ private Map kerningTab; // for CIDs
+ private Map ansiKerningTab; // For winAnsiEncoding
+ private List cmaps;
+ private List unicodeMapping;
+
+ private int upem; // unitsPerEm from "head" table
+ private int nhmtx; // Number of horizontal metrics
+ private int postFormat;
+ private int locaFormat;
+ /**
+ * Offset to last loca
+ */
+ protected long lastLoca = 0;
+ private int numberOfGlyphs; // Number of glyphs in font (read from "maxp" table)
+ private int nmGlyphs; // Used in fixWidths - remove?
+
+ /**
+ * Contains glyph data
+ */
+ protected TTFMtxEntry mtxTab[]; // Contains glyph data
+ private int[] mtxEncoded = null;
+
+ private String fontName = "";
+ private String fullName = "";
+ private String notice = "";
+ private String familyName = "";
+ private String subFamilyName = "";
+
+ private long italicAngle = 0;
+ private long isFixedPitch = 0;
+ private int fontBBox1 = 0;
+ private int fontBBox2 = 0;
+ private int fontBBox3 = 0;
+ private int fontBBox4 = 0;
+ private int capHeight = 0;
+ private int underlinePosition = 0;
+ private int underlineThickness = 0;
+ private int xHeight = 0;
+ private int ascender = 0;
+ private int descender = 0;
+
+ private short lastChar = 0;
+
+ private int ansiWidth[];
+ private Map ansiIndex;
/**
* Position inputstream to position indicated
* in the dirtab offset + offset
*/
- void seek_tab(FontFileReader in, String name,
+ void seekTab(FontFileReader in, String name,
long offset) throws IOException {
TTFDirTabEntry dt = (TTFDirTabEntry)dirTabs.get(name);
if (dt == null) {
- log.error("Dirtab " + name + " not found.");
+ getLogger().error("Dirtab " + name + " not found.");
return;
}
- in.seek_set(dt.offset + offset);
+ in.seekSet(dt.getOffset() + offset);
}
/**
* @param n truetype unit
* @return pdf unit
*/
- int get_ttf_funit(int n) {
+ public int convertTTFUnit2PDFUnit(int n) {
int ret;
if (n < 0) {
long rest1 = n % upem;
*/
private boolean readCMAP(FontFileReader in) throws IOException {
- unicodeMapping = new ArrayList();
+ unicodeMapping = new java.util.ArrayList();
- /**
- * Read CMAP table and correct mtx_tab.index
- */
+ //Read CMAP table and correct mtxTab.index
int mtxPtr = 0;
- seek_tab(in, "cmap", 2);
- int num_cmap = in.readTTFUShort(); // Number of cmap subtables
- long cmap_unioffset = 0;
+ seekTab(in, "cmap", 2);
+ int numCMap = in.readTTFUShort(); // Number of cmap subtables
+ long cmapUniOffset = 0;
- log.info(num_cmap+" cmap tables");
+ getLogger().info(numCMap + " cmap tables");
- /*
- * Read offset for all tables
- * We are only interested in the unicode table
- */
- for (int i = 0; i < num_cmap; i++) {
- int cmap_pid = in.readTTFUShort();
- int cmap_eid = in.readTTFUShort();
- long cmap_offset = in.readTTFULong();
+ //Read offset for all tables. We are only interested in the unicode table
+ for (int i = 0; i < numCMap; i++) {
+ int cmapPID = in.readTTFUShort();
+ int cmapEID = in.readTTFUShort();
+ long cmapOffset = in.readTTFULong();
- log.debug("Platform ID: "+cmap_pid+
- " Encoding: "+cmap_eid);
+ getLogger().debug("Platform ID: " + cmapPID
+ + " Encoding: " + cmapEID);
- if (cmap_pid == 3 && cmap_eid == 1)
- cmap_unioffset = cmap_offset;
+ if (cmapPID == 3 && cmapEID == 1) {
+ cmapUniOffset = cmapOffset;
+ }
}
- if (cmap_unioffset <= 0) {
- log.fatalError("Unicode cmap table not present");
- log.fatalError("Unsupported format: Aborting");
+ if (cmapUniOffset <= 0) {
+ getLogger().fatalError("Unicode cmap table not present");
+ getLogger().fatalError("Unsupported format: Aborting");
return false;
}
// Read unicode cmap
- seek_tab(in, "cmap", cmap_unioffset);
- int cmap_format = in.readTTFUShort();
- int cmap_length = in.readTTFUShort();
+ seekTab(in, "cmap", cmapUniOffset);
+ int cmapFormat = in.readTTFUShort();
+ /*int cmap_length =*/ in.readTTFUShort(); //skip cmap length
- log.info("CMAP format: "+cmap_format);
- if (cmap_format == 4) {
+ getLogger().info("CMAP format: " + cmapFormat);
+ if (cmapFormat == 4) {
in.skip(2); // Skip version number
- int cmap_segCountX2 = in.readTTFUShort();
- int cmap_searchRange = in.readTTFUShort();
- int cmap_entrySelector = in.readTTFUShort();
- int cmap_rangeShift = in.readTTFUShort();
-
-
- log.debug("segCountX2 : "+cmap_segCountX2);
- log.debug("searchRange : "+cmap_searchRange);
- log.debug("entrySelector: "+cmap_entrySelector);
- log.debug("rangeShift : "+cmap_rangeShift);
-
+ int cmapSegCountX2 = in.readTTFUShort();
+ int cmapSearchRange = in.readTTFUShort();
+ int cmapEntrySelector = in.readTTFUShort();
+ int cmapRangeShift = in.readTTFUShort();
+
+ getLogger().debug("segCountX2 : " + cmapSegCountX2);
+ getLogger().debug("searchRange : " + cmapSearchRange);
+ getLogger().debug("entrySelector: " + cmapEntrySelector);
+ getLogger().debug("rangeShift : " + cmapRangeShift);
+
- int cmap_endCounts[] = new int[cmap_segCountX2 / 2];
- int cmap_startCounts[] = new int[cmap_segCountX2 / 2];
- int cmap_deltas[] = new int[cmap_segCountX2 / 2];
- int cmap_rangeOffsets[] = new int[cmap_segCountX2 / 2];
+ int cmapEndCounts[] = new int[cmapSegCountX2 / 2];
+ int cmapStartCounts[] = new int[cmapSegCountX2 / 2];
+ int cmapDeltas[] = new int[cmapSegCountX2 / 2];
+ int cmapRangeOffsets[] = new int[cmapSegCountX2 / 2];
- for (int i = 0; i < (cmap_segCountX2 / 2); i++) {
- cmap_endCounts[i] = in.readTTFUShort();
+ for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
+ cmapEndCounts[i] = in.readTTFUShort();
}
in.skip(2); // Skip reservedPad
- for (int i = 0; i < (cmap_segCountX2 / 2); i++) {
- cmap_startCounts[i] = in.readTTFUShort();
+ for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
+ cmapStartCounts[i] = in.readTTFUShort();
}
- for (int i = 0; i < (cmap_segCountX2 / 2); i++) {
- cmap_deltas[i] = in.readTTFShort();
+ for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
+ cmapDeltas[i] = in.readTTFShort();
}
- int startRangeOffset = in.getCurrentPos();
+ //int startRangeOffset = in.getCurrentPos();
- for (int i = 0; i < (cmap_segCountX2 / 2); i++) {
- cmap_rangeOffsets[i] = in.readTTFUShort();
+ for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
+ cmapRangeOffsets[i] = in.readTTFUShort();
}
int glyphIdArrayOffset = in.getCurrentPos();
- // Insert the unicode id for the glyphs in mtx_tab
+ // Insert the unicode id for the glyphs in mtxTab
// and fill in the cmaps ArrayList
- for (int i = 0; i < cmap_startCounts.length; i++) {
+ for (int i = 0; i < cmapStartCounts.length; i++) {
- log.debug(i+ ": "+cmap_startCounts[i]+
- " - "+cmap_endCounts[i]);
+ getLogger().debug(i + ": " + cmapStartCounts[i]
+ + " - " + cmapEndCounts[i]);
- for (int j = cmap_startCounts[i]; j <= cmap_endCounts[i];
- j++) {
+ for (int j = cmapStartCounts[i]; j <= cmapEndCounts[i]; j++) {
// Update lastChar
- if (j < 256 && j > lastChar)
+ if (j < 256 && j > lastChar) {
lastChar = (short)j;
+ }
- if (mtxPtr < mtx_tab.length) {
+ if (mtxPtr < mtxTab.length) {
int glyphIdx;
// the last character 65535 = .notdef
// may have a range offset
- if (cmap_rangeOffsets[i] != 0 && j != 65535) {
- int glyphOffset =
- glyphIdArrayOffset
- + ((cmap_rangeOffsets[i] / 2) + (j - cmap_startCounts[i]) + (i) - cmap_segCountX2 / 2)
- * 2;
- in.seek_set(glyphOffset);
- glyphIdx = (in.readTTFUShort() + cmap_deltas[i])
+ if (cmapRangeOffsets[i] != 0 && j != 65535) {
+ int glyphOffset = glyphIdArrayOffset
+ + ((cmapRangeOffsets[i] / 2)
+ + (j - cmapStartCounts[i])
+ + (i)
+ - cmapSegCountX2 / 2) * 2;
+ in.seekSet(glyphOffset);
+ glyphIdx = (in.readTTFUShort() + cmapDeltas[i])
& 0xffff;
- unicodeMapping.add(new UnicodeMapping(glyphIdx,
- j));
- mtx_tab[glyphIdx].unicodeIndex.add(new Integer(j));
+ unicodeMapping.add(new UnicodeMapping(glyphIdx, j));
+ mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
// Also add winAnsiWidth
- ArrayList v =
- (ArrayList)ansiIndex.get(new Integer(j));
+ List v = (List)ansiIndex.get(new Integer(j));
if (v != null) {
- for (Iterator e = v.listIterator();
- e.hasNext(); ) {
- Integer aIdx =
- (Integer)e.next();
+ Iterator e = v.listIterator();
+ while (e.hasNext()) {
+ Integer aIdx = (Integer)e.next();
ansiWidth[aIdx.intValue()] =
- mtx_tab[glyphIdx].wx;
+ mtxTab[glyphIdx].getWx();
- log.debug("Added width "+
- mtx_tab[glyphIdx].wx +
- " uni: " + j +
- " ansi: " + aIdx.intValue());
-
+ getLogger().debug("Added width "
+ + mtxTab[glyphIdx].getWx()
+ + " uni: " + j
+ + " ansi: " + aIdx.intValue());
}
}
- log.debug("Idx: "+
- glyphIdx +
- " Delta: " + cmap_deltas[i]+
- " Unicode: " + j +
- " name: " +
- mtx_tab[glyphIdx].name);
-
-
+ getLogger().debug("Idx: "
+ + glyphIdx
+ + " Delta: " + cmapDeltas[i]
+ + " Unicode: " + j
+ + " name: " + mtxTab[glyphIdx].getName());
} else {
+ glyphIdx = (j + cmapDeltas[i]) & 0xffff;
- glyphIdx = (j + cmap_deltas[i]) & 0xffff;
-
- if (glyphIdx < mtx_tab.length)
- mtx_tab[glyphIdx].unicodeIndex.add(new Integer(j));
- else
- log.debug("Glyph " + glyphIdx
- + " out of range: "
- + mtx_tab.length);
-
- unicodeMapping.add(new UnicodeMapping(glyphIdx,
- j));
- if (glyphIdx < mtx_tab.length)
- mtx_tab[glyphIdx].unicodeIndex.add(new Integer(j));
- else
- log.debug("Glyph " + glyphIdx
+ if (glyphIdx < mtxTab.length) {
+ mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
+ } else {
+ getLogger().debug("Glyph " + glyphIdx
+ " out of range: "
- + mtx_tab.length);
-
+ + mtxTab.length);
+ }
+ unicodeMapping.add(new UnicodeMapping(glyphIdx, j));
+ if (glyphIdx < mtxTab.length) {
+ mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
+ } else {
+ getLogger().debug("Glyph " + glyphIdx
+ + " out of range: "
+ + mtxTab.length);
+ }
// Also add winAnsiWidth
- ArrayList v =
- (ArrayList)ansiIndex.get(new Integer(j));
+ List v = (List)ansiIndex.get(new Integer(j));
if (v != null) {
- for (Iterator e = v.listIterator();
- e.hasNext(); ) {
- Integer aIdx =
- (Integer)e.next();
- ansiWidth[aIdx.intValue()] =
- mtx_tab[glyphIdx].wx;
+ Iterator e = v.listIterator();
+ while (e.hasNext()) {
+ Integer aIdx = (Integer)e.next();
+ ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx();
}
}
-
- //log.debug("IIdx: "+
- //mtxPtr +
- //" Delta: " + cmap_deltas[i]+
- //" Unicode: " + j +
- //" name: " +
- //mtx_tab[(j+cmap_deltas[i]) & 0xffff].name);
+ //getLogger().debug("IIdx: " +
+ // mtxPtr +
+ // " Delta: " + cmap_deltas[i] +
+ // " Unicode: " + j +
+ // " name: " +
+ // mtxTab[(j+cmap_deltas[i]) & 0xffff].name);
}
- if (glyphIdx < mtx_tab.length) {
- if (mtx_tab[glyphIdx].unicodeIndex.size() < 2) {
+ if (glyphIdx < mtxTab.length) {
+ if (mtxTab[glyphIdx].getUnicodeIndex().size() < 2) {
mtxPtr++;
}
}
return true;
}
-
-
/**
* Print first char/last char
*/
- private void print_max_min() {
+ private void printMaxMin() {
int min = 255;
int max = 0;
- for (int i = 0; i < mtx_tab.length; i++) {
- if (mtx_tab[i].index < min)
- min = mtx_tab[i].index;
- if (mtx_tab[i].index > max)
- max = mtx_tab[i].index;
+ for (int i = 0; i < mtxTab.length; i++) {
+ if (mtxTab[i].getIndex() < min) {
+ min = mtxTab[i].getIndex();
+ }
+ if (mtxTab[i].getIndex() > max) {
+ max = mtxTab[i].getIndex();
+ }
}
- log.info("Min: " + min);
- log.info("Max: " + max);
+ getLogger().info("Min: " + min);
+ getLogger().info("Max: " + max);
}
+
+ /**
+ * Reads the font using a FontFileReader.
+ *
+ * @param in The FontFileReader to use
+ * @throws IOException In case of an I/O problem
+ */
public void readFont(FontFileReader in) throws IOException {
readFont(in, (String)null);
}
*/
private void initAnsiWidths() {
ansiWidth = new int[256];
- for (int i = 0; i < 256; i++)
- ansiWidth[i] = mtx_tab[0].wx;
+ for (int i = 0; i < 256; i++) {
+ ansiWidth[i] = mtxTab[0].getWx();
+ }
// Create an index hash to the ansiWidth
// Can't just index the winAnsiEncoding when inserting widths
// same char (eg bullet) is repeated more than one place
- ansiIndex = new HashMap();
+ ansiIndex = new java.util.HashMap();
for (int i = 32; i < Glyphs.winAnsiEncoding.length; i++) {
Integer ansi = new Integer(i);
Integer uni = new Integer((int)Glyphs.winAnsiEncoding[i]);
- ArrayList v = (ArrayList)ansiIndex.get(uni);
+ List v = (List)ansiIndex.get(uni);
if (v == null) {
- v = new ArrayList();
+ v = new java.util.ArrayList();
ansiIndex.put(uni, v);
}
v.add(ansi);
}
}
-
/**
- * Read the font data
+ * Read the font data.
* If the fontfile is a TrueType Collection (.ttc file)
- * The name of the font to read data for must be supplied,
- * else the name is ignored
+ * the name of the font to read data for must be supplied,
+ * else the name is ignored.
+ *
+ * @param in The FontFileReader to use
+ * @param name The name of the font
+ * @return boolean Returns true if the font is valid
+ * @throws IOException In case of an I/O problem
*/
public boolean readFont(FontFileReader in, String name) throws IOException {
* Check if TrueType collection, and that the name
* exists in the collection
*/
- if (!checkTTC(in, name))
+ if (!checkTTC(in, name)) {
throw new IOException("Failed to read font");
+ }
readDirTabs(in);
readFontHeader(in);
getNumGlyphs(in);
- log.info("Number of glyphs in font: " + nglyphs);
+ getLogger().info("Number of glyphs in font: " + numberOfGlyphs);
readHorizontalHeader(in);
readHorizontalMetrics(in);
initAnsiWidths();
readPCLT(in);
// Read cmap table and fill in ansiwidths
boolean valid = readCMAP(in);
- if(!valid) {
+ if (!valid) {
return false;
}
// Create cmaps for bfentries
}
private void createCMaps() {
- cmaps = new ArrayList();
+ cmaps = new java.util.ArrayList();
TTFCmapEntry tce = new TTFCmapEntry();
Iterator e = unicodeMapping.listIterator();
UnicodeMapping um = (UnicodeMapping)e.next();
UnicodeMapping lastMapping = um;
- tce.unicodeStart = um.uIdx;
- tce.glyphStartIndex = um.gIdx;
+ tce.setUnicodeStart(um.getUIdx());
+ tce.setGlyphStartIndex(um.getGIdx());
while (e.hasNext()) {
um = (UnicodeMapping)e.next();
- if (((lastMapping.uIdx + 1) != um.uIdx)
- || ((lastMapping.gIdx + 1) != um.gIdx)) {
- tce.unicodeEnd = lastMapping.uIdx;
+ if (((lastMapping.getUIdx() + 1) != um.getUIdx())
+ || ((lastMapping.getGIdx() + 1) != um.getGIdx())) {
+ tce.setUnicodeEnd(lastMapping.getUIdx());
cmaps.add(tce);
tce = new TTFCmapEntry();
- tce.unicodeStart = um.uIdx;
- tce.glyphStartIndex = um.gIdx;
+ tce.setUnicodeStart(um.getUIdx());
+ tce.setGlyphStartIndex(um.getGIdx());
}
lastMapping = um;
}
- tce.unicodeEnd = um.uIdx;
+ tce.setUnicodeEnd(um.getUIdx());
cmaps.add(tce);
}
- public void printStuff() {
- System.out.println("Font name: " + fontName);
- System.out.println("Full name: " + fullName);
- System.out.println("Family name: " + familyName);
- System.out.println("Subfamily name: " + subFamilyName);
- System.out.println("Notice: " + notice);
- System.out.println("xHeight: " + (int)get_ttf_funit(xHeight));
- System.out.println("capheight: " + (int)get_ttf_funit(capHeight));
-
- int italic = (int)(italicAngle >> 16);
- System.out.println("Italic: " + italic);
- System.out.print("ItalicAngle: " + (short)(italicAngle / 0x10000));
- if ((italicAngle % 0x10000) > 0)
- System.out.print("."
- + (short)((italicAngle % 0x10000) * 1000)
- / 0x10000);
- System.out.println();
- System.out.println("Ascender: " + get_ttf_funit(ascender));
- System.out.println("Descender: " + get_ttf_funit(descender));
- System.out.println("FontBBox: [" + (int)get_ttf_funit(fontBBox1)
- + " " + (int)get_ttf_funit(fontBBox2) + " "
- + (int)get_ttf_funit(fontBBox3) + " "
- + (int)get_ttf_funit(fontBBox4) + "]");
- }
-
- public static void main(String[] args) {
- int level = ConsoleLogger.LEVEL_WARN;
- Logger log = new ConsoleLogger(level);
- try {
- TTFFile ttfFile = new TTFFile();
- ttfFile.setLogger(log);
-
- FontFileReader reader = new FontFileReader(args[0]);
-
- String name = null;
- if (args.length >= 2)
- name = args[1];
-
- ttfFile.readFont(reader, name);
- ttfFile.printStuff();
-
- } catch (IOException ioe) {
- log.error("problem reading font: " + ioe.toString(), ioe);
- }
- }
-
+ /**
+ * Returns the Windows name of the font.
+ * @return String The Windows name
+ */
public String getWindowsName() {
- return new String(familyName + "," + subFamilyName);
+ return familyName + "," + subFamilyName;
}
+ /**
+ * Returns the PostScript name of the font.
+ * @return String The PostScript name
+ */
public String getPostscriptName() {
- if ("Regular".equals(subFamilyName) || "Roman".equals(subFamilyName))
+ if ("Regular".equals(subFamilyName) || "Roman".equals(subFamilyName)) {
return familyName;
- else
+ } else {
return familyName + "," + subFamilyName;
+ }
}
+ /**
+ * Returns the font family name of the font.
+ * @return String The family name
+ */
public String getFamilyName() {
return familyName;
}
+ /**
+ * Returns the name of the character set used.
+ * @return String The caracter set
+ */
public String getCharSetName() {
return encoding;
}
+ /**
+ * Returns the CapHeight attribute of the font.
+ * @return int The CapHeight
+ */
public int getCapHeight() {
- return (int)get_ttf_funit(capHeight);
+ return (int)convertTTFUnit2PDFUnit(capHeight);
}
+ /**
+ * Returns the XHeight attribute of the font.
+ * @return int The XHeight
+ */
public int getXHeight() {
- return (int)get_ttf_funit(xHeight);
+ return (int)convertTTFUnit2PDFUnit(xHeight);
}
+ /**
+ * Returns the Flags attribute of the font.
+ * @return int The Flags
+ */
public int getFlags() {
int flags = 32; // Use Adobe Standard charset
- if (italicAngle != 0)
+ if (italicAngle != 0) {
flags = flags | 64;
- if (isFixedPitch != 0)
+ }
+ if (isFixedPitch != 0) {
flags = flags | 2;
- if (hasSerifs)
+ }
+ if (hasSerifs) {
flags = flags | 1;
+ }
return flags;
}
+ /**
+ * Returns the StemV attribute of the font.
+ * @return String The StemV
+ */
public String getStemV() {
return "0";
}
+ /**
+ * Returns the ItalicAngle attribute of the font.
+ * @return String The ItalicAngle
+ */
public String getItalicAngle() {
String ia = Short.toString((short)(italicAngle / 0x10000));
return ia;
}
+ /**
+ * Returns the font bounding box.
+ * @return int[] The font bbox
+ */
public int[] getFontBBox() {
- int[] fbb = new int[4];
- fbb[0] = (int)get_ttf_funit(fontBBox1);
- fbb[1] = (int)get_ttf_funit(fontBBox2);
- fbb[2] = (int)get_ttf_funit(fontBBox3);
- fbb[3] = (int)get_ttf_funit(fontBBox4);
+ final int[] fbb = new int[4];
+ fbb[0] = (int)convertTTFUnit2PDFUnit(fontBBox1);
+ fbb[1] = (int)convertTTFUnit2PDFUnit(fontBBox2);
+ fbb[2] = (int)convertTTFUnit2PDFUnit(fontBBox3);
+ fbb[3] = (int)convertTTFUnit2PDFUnit(fontBBox4);
return fbb;
}
+ /**
+ * Returns the LowerCaseAscent attribute of the font.
+ * @return int The LowerCaseAscent
+ */
public int getLowerCaseAscent() {
- return (int)get_ttf_funit(ascender);
+ return (int)convertTTFUnit2PDFUnit(ascender);
}
+ /**
+ * Returns the LowerCaseDescent attribute of the font.
+ * @return int The LowerCaseDescent
+ */
public int getLowerCaseDescent() {
- return (int)get_ttf_funit(descender);
+ return (int)convertTTFUnit2PDFUnit(descender);
}
- // This is only for WinAnsiEncoding, so the last char is
- // the last char < 256
+ /**
+ * Returns the index of the last character, but this is for WinAnsiEncoding
+ * only, so the last char is < 256.
+ * @return short Index of the last character (<256)
+ */
public short getLastChar() {
return lastChar;
}
+ /**
+ * Returns the index of the first character.
+ * @return short Index of the first character
+ */
public short getFirstChar() {
return firstChar;
}
+ /**
+ * Returns an array of character widths.
+ * @return int[] The character widths
+ */
public int[] getWidths() {
- int[] wx = new int[mtx_tab.length];
- for (int i = 0; i < wx.length; i++)
- wx[i] = (int)get_ttf_funit(mtx_tab[i].wx);
+ int[] wx = new int[mtxTab.length];
+ for (int i = 0; i < wx.length; i++) {
+ wx[i] = (int)convertTTFUnit2PDFUnit(mtxTab[i].getWx());
+ }
return wx;
}
+ /**
+ * Returns the width of a given character.
+ * @param idx Index of the character
+ * @return int Standard width
+ */
public int getCharWidth(int idx) {
- return (int)get_ttf_funit(ansiWidth[idx]);
+ return (int)convertTTFUnit2PDFUnit(ansiWidth[idx]);
}
- public HashMap getKerning() {
+ /**
+ * Returns the kerning table.
+ * @return Map The kerning table
+ */
+ public Map getKerning() {
return kerningTab;
}
- public HashMap getAnsiKerning() {
+ /**
+ * Returns the ANSI kerning table.
+ * @return Map The ANSI kerning table
+ */
+ public Map getAnsiKerning() {
return ansiKerningTab;
}
+ /**
+ * Indicates if the font may be embedded.
+ * @return boolean True if it may be embedded
+ */
public boolean isEmbeddable() {
- return is_embeddable;
+ return isEmbeddable;
}
* FontFileReader and fill the global HashMap dirTabs
* with the table name (String) as key and a TTFDirTabEntry
* as value.
+ * @param in FontFileReader to read the table directory from
+ * @throws IOException in case of an I/O problem
*/
protected void readDirTabs(FontFileReader in) throws IOException {
in.skip(4); // TTF_FIXED_SIZE
int ntabs = in.readTTFUShort();
in.skip(6); // 3xTTF_USHORT_SIZE
- dirTabs = new HashMap();
+ dirTabs = new java.util.HashMap();
TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs];
- log.debug("Reading " + ntabs + " dir tables");
+ getLogger().debug("Reading " + ntabs + " dir tables");
for (int i = 0; i < ntabs; i++) {
pd[i] = new TTFDirTabEntry();
dirTabs.put(pd[i].read(in), pd[i]);
/**
* Read the "head" table, this reads the bounding box and
* sets the upem (unitsPerEM) variable
+ * @param in FontFileReader to read the header from
+ * @throws IOException in case of an I/O problem
*/
protected void readFontHeader(FontFileReader in) throws IOException {
- seek_tab(in, "head", 2 * 4 + 2 * 4 + 2);
+ seekTab(in, "head", 2 * 4 + 2 * 4 + 2);
upem = in.readTTFUShort();
in.skip(16);
in.skip(2 + 2 + 2);
- loca_format = in.readTTFShort();
+ locaFormat = in.readTTFShort();
}
/**
* Read the number of glyphs from the "maxp" table
+ * @param in FontFileReader to read the number of glyphs from
+ * @throws IOException in case of an I/O problem
*/
protected void getNumGlyphs(FontFileReader in) throws IOException {
- seek_tab(in, "maxp", 4);
- nglyphs = in.readTTFUShort();
+ seekTab(in, "maxp", 4);
+ numberOfGlyphs = in.readTTFUShort();
}
* Read the "hhea" table to find the ascender and descender and
* size of "hmtx" table, i.e. a fixed size font might have only
* one width
+ * @param in FontFileReader to read the hhea table from
+ * @throws IOException in case of an I/O problem
*/
protected void readHorizontalHeader(FontFileReader in)
throws IOException {
- seek_tab(in, "hhea", 4);
+ seekTab(in, "hhea", 4);
ascender = in.readTTFShort(); // Use sTypoAscender in "OS/2" table?
descender = in.readTTFShort(); // Use sTypoDescender in "OS/2" table?
in.skip(2 + 2 + 3 * 2 + 8 * 2);
nhmtx = in.readTTFUShort();
- log.debug("Number of horizontal metrics: " + nhmtx);
+ getLogger().debug("Number of horizontal metrics: " + nhmtx);
}
/**
* Read "hmtx" table and put the horizontal metrics
- * in the mtx_tab array. If the number of metrics is less
+ * in the mtxTab array. If the number of metrics is less
* than the number of glyphs (eg fixed size fonts), extend
- * the mtx_tab array and fill in the missing widths
+ * the mtxTab array and fill in the missing widths
+ * @param in FontFileReader to read the hmtx table from
+ * @throws IOException in case of an I/O problem
*/
protected void readHorizontalMetrics(FontFileReader in)
throws IOException {
- seek_tab(in, "hmtx", 0);
+ seekTab(in, "hmtx", 0);
- int mtx_size = (nglyphs > nhmtx) ? nglyphs : nhmtx;
- mtx_tab = new TTFMtxEntry[mtx_size];
+ int mtxSize = (numberOfGlyphs > nhmtx) ? numberOfGlyphs : nhmtx;
+ mtxTab = new TTFMtxEntry[mtxSize];
- log.debug("*** Widths array: \n");
- for (int i = 0; i < mtx_size; i++)
- mtx_tab[i] = new TTFMtxEntry();
+ getLogger().debug("*** Widths array: \n");
+ for (int i = 0; i < mtxSize; i++) {
+ mtxTab[i] = new TTFMtxEntry();
+ }
for (int i = 0; i < nhmtx; i++) {
- mtx_tab[i].wx = in.readTTFUShort();
- mtx_tab[i].lsb = in.readTTFUShort();
+ mtxTab[i].setWx(in.readTTFUShort());
+ mtxTab[i].setLsb(in.readTTFUShort());
- log.debug(" width["+i+"] = "+
- get_ttf_funit(mtx_tab[i].wx)+";");
+ getLogger().debug(" width[" + i + "] = "
+ + convertTTFUnit2PDFUnit(mtxTab[i].getWx()) + ";");
}
- if (nhmtx < mtx_size) {
+ if (nhmtx < mtxSize) {
// Fill in the missing widths
- int lastWidth = mtx_tab[nhmtx - 1].wx;
- for (int i = nhmtx; i < mtx_size; i++) {
- mtx_tab[i].wx = lastWidth;
- mtx_tab[i].lsb = in.readTTFUShort();
+ int lastWidth = mtxTab[nhmtx - 1].getWx();
+ for (int i = nhmtx; i < mtxSize; i++) {
+ mtxTab[i].setWx(lastWidth);
+ mtxTab[i].setLsb(in.readTTFUShort());
}
}
}
* containing the postscript names of the glyphs.
*/
private final void readPostscript(FontFileReader in) throws IOException {
- String[] ps_glyphs_buf;
+ String[] psGlyphsBuffer;
int i, k, l;
- seek_tab(in, "post", 0);
- post_format = in.readTTFLong();
+ seekTab(in, "post", 0);
+ postFormat = in.readTTFLong();
italicAngle = in.readTTFULong();
underlinePosition = in.readTTFShort();
underlineThickness = in.readTTFShort();
in.skip(4 * 4);
- log.debug("Post format: "+post_format);
- switch (post_format) {
+ getLogger().debug("Post format: " + postFormat);
+ switch (postFormat) {
case 0x00010000:
- log.debug("Postscript format 1");
+ getLogger().debug("Postscript format 1");
for (i = 0; i < Glyphs.mac_glyph_names.length; i++) {
- mtx_tab[i].name = Glyphs.mac_glyph_names[i];
+ mtxTab[i].setName(Glyphs.mac_glyph_names[i]);
}
break;
case 0x00020000:
- log.debug("Postscript format 2");
+ getLogger().debug("Postscript format 2");
int numGlyphStrings = 0;
l = in.readTTFUShort(); // Num Glyphs
// short minIndex=256;
for (i = 0; i < l; i++) { // Read indexes
- mtx_tab[i].index = in.readTTFUShort();
- // if (minIndex > mtx_tab[i].index)
- // minIndex=(short)mtx_tab[i].index;
+ mtxTab[i].setIndex(in.readTTFUShort());
+ // if (minIndex > mtxTab[i].index)
+ // minIndex=(short)mtxTab[i].index;
- if (mtx_tab[i].index > 257)
+ if (mtxTab[i].getIndex() > 257) {
numGlyphStrings++;
+ }
- log.debug("Post index: "+mtx_tab[i].index);
+ getLogger().debug("Post index: " + mtxTab[i].getIndex());
}
// firstChar=minIndex;
- ps_glyphs_buf = new String[numGlyphStrings];
- log.debug("Reading " + numGlyphStrings +
- " glyphnames" + ", was n num glyphs="+l);
- for (i = 0; i < ps_glyphs_buf.length; i++) {
- ps_glyphs_buf[i] = in.readTTFString(in.readTTFUByte());
+ psGlyphsBuffer = new String[numGlyphStrings];
+ getLogger().debug("Reading " + numGlyphStrings
+ + " glyphnames" + ", was n num glyphs=" + l);
+ for (i = 0; i < psGlyphsBuffer.length; i++) {
+ psGlyphsBuffer[i] = in.readTTFString(in.readTTFUByte());
}
for (i = 0; i < l; i++) {
- if (mtx_tab[i].index < NMACGLYPHS) {
- mtx_tab[i].name =
- Glyphs.mac_glyph_names[mtx_tab[i].index];
+ if (mtxTab[i].getIndex() < NMACGLYPHS) {
+ mtxTab[i].setName(Glyphs.mac_glyph_names[mtxTab[i].getIndex()]);
} else {
- k = mtx_tab[i].index - NMACGLYPHS;
+ k = mtxTab[i].getIndex() - NMACGLYPHS;
- log.debug(k+" i="+i+" mtx="+mtx_tab.length+
- " ps="+ps_glyphs_buf.length);
+ getLogger().debug(k + " i=" + i + " mtx=" + mtxTab.length
+ + " ps=" + psGlyphsBuffer.length);
- mtx_tab[i].name = ps_glyphs_buf[k];
+ mtxTab[i].setName(psGlyphsBuffer[k]);
}
}
break;
case 0x00030000:
// Postscript format 3 contains no glyph names
- log.debug("Postscript format 3");
+ getLogger().debug("Postscript format 3");
break;
default:
- log.error("Unknown Postscript format : " + post_format);
+ getLogger().error("Unknown Postscript format: " + postFormat);
}
}
private final void readOS2(FontFileReader in) throws IOException {
// Check if font is embeddable
if (dirTabs.get("OS/2") != null) {
- seek_tab(in, "OS/2", 2 * 4);
+ seekTab(in, "OS/2", 2 * 4);
int fsType = in.readTTFUShort();
- if (fsType == 2)
- is_embeddable = false;
- else
- is_embeddable = true;
- } else
- is_embeddable = true;
+ if (fsType == 2) {
+ isEmbeddable = false;
+ } else {
+ isEmbeddable = true;
+ }
+ } else {
+ isEmbeddable = true;
+ }
}
/**
- * Read the "loca" table
+ * Read the "loca" table.
+ * @param in FontFileReader to read from
+ * @throws IOException In case of a I/O problem
*/
protected final void readIndexToLocation(FontFileReader in)
throws IOException {
- seek_tab(in, "loca", 0);
- for (int i = 0; i < nglyphs; i++) {
- mtx_tab[i].offset = (loca_format == 1 ? in.readTTFULong()
+ seekTab(in, "loca", 0);
+ for (int i = 0; i < numberOfGlyphs; i++) {
+ mtxTab[i].setOffset(locaFormat == 1 ? in.readTTFULong()
: (in.readTTFUShort() << 1));
}
- lastLoca = (loca_format == 1 ? in.readTTFULong()
+ lastLoca = (locaFormat == 1 ? in.readTTFULong()
: (in.readTTFUShort() << 1));
}
/**
- * Read the "glyf" table to find the bounding boxes
+ * Read the "glyf" table to find the bounding boxes.
+ * @param in FontFileReader to read from
+ * @throws IOException In case of a I/O problem
*/
private final void readGlyf(FontFileReader in) throws IOException {
TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("glyf");
- for (int i = 0; i < (nglyphs - 1); i++) {
- if (mtx_tab[i].offset != mtx_tab[i + 1].offset) {
- in.seek_set(dirTab.offset + mtx_tab[i].offset);
+ for (int i = 0; i < (numberOfGlyphs - 1); i++) {
+ if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
+ in.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
in.skip(2);
- mtx_tab[i].bbox[0] = in.readTTFShort();
- mtx_tab[i].bbox[1] = in.readTTFShort();
- mtx_tab[i].bbox[2] = in.readTTFShort();
- mtx_tab[i].bbox[3] = in.readTTFShort();
+ final int[] bbox = {
+ in.readTTFShort(),
+ in.readTTFShort(),
+ in.readTTFShort(),
+ in.readTTFShort()};
+ mtxTab[i].setBoundingBox(bbox);
} else {
- mtx_tab[i].bbox[0] = mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[1] = mtx_tab[0].bbox[1];
- mtx_tab[i].bbox[2] = mtx_tab[0].bbox[2];
- mtx_tab[i].bbox[3] = mtx_tab[0].bbox[3];
+ mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox());
}
}
- long n = ((TTFDirTabEntry)dirTabs.get("glyf")).offset;
- for (int i = 0; i < nglyphs; i++) {
- if ((i + 1) >= mtx_tab.length
- || mtx_tab[i].offset != mtx_tab[i + 1].offset) {
- in.seek_set(n + mtx_tab[i].offset);
+ long n = ((TTFDirTabEntry)dirTabs.get("glyf")).getOffset();
+ for (int i = 0; i < numberOfGlyphs; i++) {
+ if ((i + 1) >= mtxTab.length
+ || mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
+ in.seekSet(n + mtxTab[i].getOffset());
in.skip(2);
- mtx_tab[i].bbox[0] = in.readTTFShort();
- mtx_tab[i].bbox[1] = in.readTTFShort();
- mtx_tab[i].bbox[2] = in.readTTFShort();
- mtx_tab[i].bbox[3] = in.readTTFShort();
+ final int[] bbox = {
+ in.readTTFShort(),
+ in.readTTFShort(),
+ in.readTTFShort(),
+ in.readTTFShort()};
+ mtxTab[i].setBoundingBox(bbox);
} else {
- mtx_tab[i].bbox[0] = mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[1] = mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[2] = mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[3] = mtx_tab[0].bbox[0];
+ /**@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]; */
}
- log.debug(mtx_tab[i].toString(this));
+ getLogger().debug(mtxTab[i].toString(this));
}
}
/**
- * Read the "name" table
+ * Read the "name" table.
+ * @param in FontFileReader to read from
+ * @throws IOException In case of a I/O problem
*/
private final void readName(FontFileReader in) throws IOException {
- int platform_id, encoding_id, language_id;
-
- seek_tab(in, "name", 2);
+ seekTab(in, "name", 2);
int i = in.getCurrentPos();
int n = in.readTTFUShort();
int j = in.readTTFUShort() + i - 2;
i += 2 * 2;
while (n-- > 0) {
- // log.debug("Iteration: "+n);
- in.seek_set(i);
- platform_id = in.readTTFUShort();
- encoding_id = in.readTTFUShort();
- language_id = in.readTTFUShort();
+ // getLogger().debug("Iteration: " + n);
+ in.seekSet(i);
+ final int platformID = in.readTTFUShort();
+ final int encodingID = in.readTTFUShort();
+ /*final int language_id =*/ in.readTTFUShort(); //Skip language id
int k = in.readTTFUShort();
int l = in.readTTFUShort();
- if (((platform_id == 1 || platform_id == 3) && (encoding_id == 0 || encoding_id == 1))
+ if (((platformID == 1 || platformID == 3) && (encodingID == 0 || encodingID == 1))
&& (k == 1 || k == 2 || k == 0 || k == 4 || k == 6)) {
// if (k==1 || k==2 || k==0 || k==4 || k==6) {
- in.seek_set(j + in.readTTFUShort());
+ in.seekSet(j + in.readTTFUShort());
String txt = in.readTTFString(l);
- // log.debug(platform_id+" "+encoding_id+
- // " "+k+" "+txt);
+ // getLogger().debug(platform_id + " " + encoding_id
+ // + " " + k + " " + txt);
switch (k) {
case 0:
notice = txt;
fontName = txt;
break;
}
- if (!notice.equals("") &&!fullName.equals("")
- &&!fontName.equals("") &&!familyName.equals("")
- &&!subFamilyName.equals("")) {
+ if (!notice.equals("")
+ && !fullName.equals("")
+ && !fontName.equals("")
+ && !familyName.equals("")
+ && !subFamilyName.equals("")) {
break;
}
}
}
/**
- * Read the "PCLT" table to find xHeight and capHeight
+ * Read the "PCLT" table to find xHeight and capHeight.
+ * @param in FontFileReader to read from
+ * @throws IOException In case of a I/O problem
*/
private final void readPCLT(FontFileReader in) throws IOException {
TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("PCLT");
if (dirTab != null) {
- in.seek_set(dirTab.offset + 4 + 4 + 2);
+ in.seekSet(dirTab.getOffset() + 4 + 4 + 2);
xHeight = in.readTTFUShort();
in.skip(2 * 2);
capHeight = in.readTTFUShort();
int serifStyle = in.readTTFUByte();
serifStyle = serifStyle >> 6;
serifStyle = serifStyle & 3;
- if (serifStyle == 1)
+ if (serifStyle == 1) {
hasSerifs = false;
- else
+ } else {
hasSerifs = true;
-
+ }
} else {
// Approximate capHeight from height of "H"
// It's most unlikly that a font misses the PCLT table
// This also assumes that psocriptnames exists ("H")
// Should look it up int the cmap (that wouldn't help
// for charsets without H anyway...)
- for (int i = 0; i < mtx_tab.length; i++) {
- if ("H".equals(mtx_tab[i].name))
- capHeight = mtx_tab[i].bbox[3] - mtx_tab[i].bbox[1];
+ for (int i = 0; i < mtxTab.length; i++) {
+ if ("H".equals(mtxTab[i].getName())) {
+ capHeight = mtxTab[i].getBoundingBox()[3] - mtxTab[i].getBoundingBox()[1];
+ }
}
}
}
/**
* Read the kerning table, create a table for both CIDs and
- * winAnsiEncoding
+ * winAnsiEncoding.
+ * @param in FontFileReader to read from
+ * @throws IOException In case of a I/O problem
*/
private final void readKerning(FontFileReader in) throws IOException {
// Read kerning
- kerningTab = new HashMap();
- ansiKerningTab = new HashMap();
+ kerningTab = new java.util.HashMap();
+ ansiKerningTab = new java.util.HashMap();
TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("kern");
if (dirTab != null) {
- seek_tab(in, "kern", 2);
+ seekTab(in, "kern", 2);
for (int n = in.readTTFUShort(); n > 0; n--) {
in.skip(2 * 2);
int k = in.readTTFUShort();
- if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0)
+ if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) {
return;
- if ((k >> 8) != 0)
+ }
+ if ((k >> 8) != 0) {
continue;
+ }
k = in.readTTFUShort();
in.skip(3 * 2);
if (kpx != 0) {
// CID table
Integer iObj = new Integer(i);
- HashMap adjTab = (HashMap)kerningTab.get(iObj);
- if (adjTab == null)
- adjTab = new HashMap();
+ Map adjTab = (Map)kerningTab.get(iObj);
+ if (adjTab == null) {
+ adjTab = new java.util.HashMap();
+ }
adjTab.put(new Integer(j),
- new Integer((int)get_ttf_funit(kpx)));
+ new Integer((int)convertTTFUnit2PDFUnit(kpx)));
kerningTab.put(iObj, adjTab);
}
}
}
- // log.debug(kerningTab.toString());
+ // getLogger().debug(kerningTab.toString());
// Create winAnsiEncoded kerning table
-
- for (Iterator ae = kerningTab.keySet().iterator(); ae.hasNext(); ) {
+ Iterator ae = kerningTab.keySet().iterator();
+ while (ae.hasNext()) {
Integer cidKey = (Integer)ae.next();
- HashMap akpx = new HashMap();
- HashMap ckpx = (HashMap)kerningTab.get(cidKey);
+ Map akpx = new java.util.HashMap();
+ Map ckpx = (Map)kerningTab.get(cidKey);
- for (Iterator aee = ckpx.keySet().iterator(); aee.hasNext(); ) {
+ Iterator aee = ckpx.keySet().iterator();
+ while (aee.hasNext()) {
Integer cidKey2 = (Integer)aee.next();
Integer kern = (Integer)ckpx.get(cidKey2);
- for (Iterator uniMap = mtx_tab[cidKey2.intValue()].unicodeIndex.listIterator();
- uniMap.hasNext(); ) {
+ Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator();
+ while (uniMap.hasNext()) {
Integer unicodeKey = (Integer)uniMap.next();
- Integer[] ansiKeys =
- unicodeToWinAnsi(unicodeKey.intValue());
+ Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
for (int u = 0; u < ansiKeys.length; u++) {
akpx.put(ansiKeys[u], kern);
}
}
}
- if (akpx.size() > 0)
- for (Iterator uniMap = mtx_tab[cidKey.intValue()].unicodeIndex.listIterator();
- uniMap.hasNext(); ) {
+ if (akpx.size() > 0) {
+ Iterator uniMap = mtxTab[cidKey.intValue()].getUnicodeIndex().listIterator();
+ while (uniMap.hasNext()) {
Integer unicodeKey = (Integer)uniMap.next();
- Integer[] ansiKeys =
- unicodeToWinAnsi(unicodeKey.intValue());
+ Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
for (int u = 0; u < ansiKeys.length; u++) {
ansiKerningTab.put(ansiKeys[u], akpx);
}
}
+ }
}
}
}
/**
- * Return a vector with TTFCmapEntry
+ * Return a List with TTFCmapEntry.
+ * @return A list of TTFCmapEntry objects
*/
- public ArrayList getCMaps() {
+ public List getCMaps() {
return cmaps;
}
* Check if this is a TrueType collection and that the given
* name exists in the collection.
* If it does, set offset in fontfile to the beginning of
- * the Table Directory for that font
- * @ return true if not collection or font name present, false
- * otherwise
+ * the Table Directory for that font.
+ * @param in FontFileReader to read from
+ * @param name The name to check
+ * @return True if not collection or font name present, false otherwise
+ * @throws IOException In case of an I/O problem
*/
protected final boolean checkTTC(FontFileReader in, String name) throws IOException {
String tag = in.readTTFString(4);
dirOffsets[i] = in.readTTFULong();
}
- log.debug("This is a TrueType collection file with"
+ getLogger().debug("This is a TrueType collection file with"
+ numDirectories + " fonts");
- log.debug("Containing the following fonts: ");
+ getLogger().debug("Containing the following fonts: ");
// Read all the directories and name tables to check
// If the font exists - this is a bit ugly, but...
boolean found = false;
// Is found, just to show all the names
long dirTabOffset = 0;
for (int i = 0; (i < numDirectories); i++) {
- in.seek_set(dirOffsets[i]);
+ in.seekSet(dirOffsets[i]);
readDirTabs(in);
readName(in);
if (fullName.equals(name)) {
found = true;
dirTabOffset = dirOffsets[i];
- log.debug("* " + fullName);
+ getLogger().debug("* " + fullName);
} else {
- log.debug(fullName);
+ getLogger().debug(fullName);
}
// Reset names
subFamilyName = "";
}
- in.seek_set(dirTabOffset);
+ in.seekSet(dirTabOffset);
return found;
} else {
- in.seek_set(0);
+ in.seekSet(0);
return true;
}
}
* doesn't matter...
*/
private Integer[] unicodeToWinAnsi(int unicode) {
- ArrayList ret = new ArrayList();
- for (int i = 32; i < Glyphs.winAnsiEncoding.length; i++)
- if (unicode == Glyphs.winAnsiEncoding[i])
+ List ret = new java.util.ArrayList();
+ for (int i = 32; i < Glyphs.winAnsiEncoding.length; i++) {
+ if (unicode == Glyphs.winAnsiEncoding[i]) {
ret.add(new Integer(i));
+ }
+ }
return (Integer[])ret.toArray(new Integer[0]);
}
+ /**
+ * Dumps a few informational values to System.out.
+ */
+ public void printStuff() {
+ System.out.println("Font name: " + fontName);
+ System.out.println("Full name: " + fullName);
+ System.out.println("Family name: " + familyName);
+ System.out.println("Subfamily name: " + subFamilyName);
+ System.out.println("Notice: " + notice);
+ System.out.println("xHeight: " + (int)convertTTFUnit2PDFUnit(xHeight));
+ System.out.println("capheight: " + (int)convertTTFUnit2PDFUnit(capHeight));
+
+ int italic = (int)(italicAngle >> 16);
+ System.out.println("Italic: " + italic);
+ System.out.print("ItalicAngle: " + (short)(italicAngle / 0x10000));
+ if ((italicAngle % 0x10000) > 0) {
+ System.out.print("."
+ + (short)((italicAngle % 0x10000) * 1000)
+ / 0x10000);
+ }
+ System.out.println();
+ System.out.println("Ascender: " + convertTTFUnit2PDFUnit(ascender));
+ System.out.println("Descender: " + convertTTFUnit2PDFUnit(descender));
+ System.out.println("FontBBox: [" + (int)convertTTFUnit2PDFUnit(fontBBox1)
+ + " " + (int)convertTTFUnit2PDFUnit(fontBBox2) + " "
+ + (int)convertTTFUnit2PDFUnit(fontBBox3) + " "
+ + (int)convertTTFUnit2PDFUnit(fontBBox4) + "]");
+ }
+
+ /**
+ * Static main method to get info about a TrueType font.
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+ int level = ConsoleLogger.LEVEL_WARN;
+ Logger log = new ConsoleLogger(level);
+ try {
+ TTFFile ttfFile = new TTFFile();
+ ttfFile.enableLogging(log);
+
+ FontFileReader reader = new FontFileReader(args[0]);
+
+ String name = null;
+ if (args.length >= 2) {
+ name = args[1];
+ }
+
+ ttfFile.readFont(reader, name);
+ ttfFile.printStuff();
+
+ } catch (IOException ioe) {
+ log.error("Problem reading font: " + ioe.toString(), ioe);
+ }
+ }
+
}
* Key-value helper class
*/
class UnicodeMapping {
- int uIdx;
- int gIdx;
+
+ private int uIdx;
+ private int gIdx;
+
UnicodeMapping(int gIdx, int uIdx) {
this.uIdx = uIdx;
this.gIdx = gIdx;
}
+ /**
+ * Returns the gIdx.
+ * @return int
+ */
+ public int getGIdx() {
+ return gIdx;
+ }
+
+ /**
+ * Returns the uIdx.
+ * @return int
+ */
+ public int getUIdx() {
+ return uIdx;
+ }
+
}
/*
* $Id$
- * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/
package org.apache.fop.fonts;
-import java.io.*;
+
+import java.io.IOException;
import java.util.Iterator;
-import java.util.HashMap;
-import java.util.ArrayList;
+import java.util.Map;
+import java.util.List;
/**
* Reads a TrueType file and generates a subset
- * That can be used to embed a TrueType CID font
+ * that can be used to embed a TrueType CID font
* TrueType tables needed for embedded CID fonts are:
- * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm"
+ * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm".
* The TrueType spec can be found at the Microsoft
* Typography site: http://www.microsoft.com/truetype/
*/
public class TTFSubSetFile extends TTFFile {
- byte[] output = null;
- int realSize = 0;
- int currentPos = 0;
+
+ private byte[] output = null;
+ private int realSize = 0;
+ private int currentPos = 0;
/*
* Offsets in name table to be filled out by table.
* The offsets are to the checkSum field
*/
- int cvtDirOffset = 0;
- int fpgmDirOffset = 0;
- int glyfDirOffset = 0;
- int headDirOffset = 0;
- int hheaDirOffset = 0;
- int hmtxDirOffset = 0;
- int locaDirOffset = 0;
- int maxpDirOffset = 0;
- int prepDirOffset = 0;
-
- int checkSumAdjustmentOffset = 0;
- int locaOffset = 0;
+ private int cvtDirOffset = 0;
+ private int fpgmDirOffset = 0;
+ private int glyfDirOffset = 0;
+ private int headDirOffset = 0;
+ private int hheaDirOffset = 0;
+ private int hmtxDirOffset = 0;
+ private int locaDirOffset = 0;
+ private int maxpDirOffset = 0;
+ private int prepDirOffset = 0;
+
+ private int checkSumAdjustmentOffset = 0;
+ private int locaOffset = 0;
/**
* Initalize the output array
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
if (entry != null) {
pad4();
- seek_tab(in, "cvt ", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
+ seekTab(in, "cvt ", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(cvtDirOffset, checksum);
writeULong(cvtDirOffset + 4, currentPos);
- writeULong(cvtDirOffset + 8, (int)entry.length);
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ writeULong(cvtDirOffset + 8, (int)entry.getLength());
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find cvt table");
}
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
if (entry != null) {
pad4();
- seek_tab(in, "fpgm", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ seekTab(in, "fpgm", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(fpgmDirOffset, checksum);
writeULong(fpgmDirOffset + 4, currentPos);
- writeULong(fpgmDirOffset + 8, (int)entry.length);
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ writeULong(fpgmDirOffset + 8, (int)entry.getLength());
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find fpgm table");
}
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
if (entry != null) {
pad4();
- seek_tab(in, "maxp", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
+ seekTab(in, "maxp", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
writeUShort(currentPos + 4, size);
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(maxpDirOffset, checksum);
writeULong(maxpDirOffset + 4, currentPos);
- writeULong(maxpDirOffset + 8, (int)entry.length);
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ writeULong(maxpDirOffset + 8, (int)entry.getLength());
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find maxp table");
}
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
if (entry != null) {
pad4();
- seek_tab(in, "prep", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
+ seekTab(in, "prep", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(prepDirOffset, checksum);
writeULong(prepDirOffset + 4, currentPos);
- writeULong(prepDirOffset + 8, (int)entry.length);
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ writeULong(prepDirOffset + 8, (int)entry.getLength());
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find prep table");
}
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
if (entry != null) {
pad4();
- seek_tab(in, "hhea", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
- writeUShort((int)entry.length + currentPos - 2, size);
+ seekTab(in, "hhea", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
+ writeUShort((int)entry.getLength() + currentPos - 2, size);
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(hheaDirOffset, checksum);
writeULong(hheaDirOffset + 4, currentPos);
- writeULong(hheaDirOffset + 8, (int)entry.length);
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ writeULong(hheaDirOffset + 8, (int)entry.getLength());
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find hhea table");
}
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
if (entry != null) {
pad4();
- seek_tab(in, "head", 0);
- System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
- 0, output, currentPos, (int)entry.length);
+ seekTab(in, "head", 0);
+ System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
+ 0, output, currentPos, (int)entry.getLength());
checkSumAdjustmentOffset = currentPos + 8;
output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
output[currentPos + 50] = 0; // long locaformat
output[currentPos + 51] = 1; // long locaformat
- int checksum = getCheckSum(currentPos, (int)entry.length);
+ int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(headDirOffset, checksum);
writeULong(headDirOffset + 4, currentPos);
- writeULong(headDirOffset + 8, (int)entry.length);
+ writeULong(headDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.length;
- realSize += (int)entry.length;
+ currentPos += (int)entry.getLength();
+ realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find head table");
}
* Create the glyf table and fill in loca table
*/
private void createGlyf(FontFileReader in,
- HashMap glyphs) throws IOException {
+ Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
int size = 0;
int start = 0;
pad4();
start = currentPos;
- for (Iterator e = glyphs.keySet().iterator(); e.hasNext(); ) {
- int glyphLength = 0;
+ /* Loca table must be in order by glyph index, so build
+ * an array first and then write the glyph info and
+ * location offset.
+ */
+ int[] origIndexes = new int[glyphs.size()];
+
+ Iterator e = glyphs.keySet().iterator();
+ while (e.hasNext()) {
Integer origIndex = (Integer)e.next();
Integer subsetIndex = (Integer)glyphs.get(origIndex);
+ origIndexes[subsetIndex.intValue()] = origIndex.intValue();
+ }
+ for (int i = 0; i < origIndexes.length; i++) {
+ int glyphLength = 0;
int nextOffset = 0;
- if (origIndex.intValue() >= (mtx_tab.length - 1))
+ int origGlyphIndex = origIndexes[i];
+ if (origGlyphIndex >= (mtxTab.length - 1)) {
nextOffset = (int)lastLoca;
- else
- nextOffset =
- (int)mtx_tab[origIndex.intValue() + 1].offset;
-
- glyphLength = nextOffset
- - (int)mtx_tab[origIndex.intValue()].offset;
+ } else {
+ nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
+ }
+ glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
// Copy glyph
- System.arraycopy(in.getBytes((int)entry.offset + (int)mtx_tab[origIndex.intValue()].offset, glyphLength),
- 0, output, currentPos, glyphLength);
+ System.arraycopy(
+ in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
+ glyphLength), 0,
+ output, currentPos,
+ glyphLength);
// Update loca table
- writeULong(locaOffset + subsetIndex.intValue() * 4,
- currentPos - start);
- if ((currentPos - start + glyphLength) > endOffset)
+ writeULong(locaOffset + i * 4, currentPos - start);
+ if ((currentPos - start + glyphLength) > endOffset) {
endOffset = (currentPos - start + glyphLength);
+ }
currentPos += glyphLength;
realSize += glyphLength;
/**
* Create the hmtx table by copying metrics from original
- * font to subset font. The glyphs hashtable contains an
+ * font to subset font. The glyphs Map contains an
* Integer key and Integer value that maps the original
* metric (key) to the subset metric (value)
*/
private void createHmtx(FontFileReader in,
- HashMap glyphs) throws IOException {
+ Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
int longHorMetricSize = glyphs.size() * 2;
if (entry != null) {
pad4();
- int offset = (int)entry.offset;
- for (Iterator e = glyphs.keySet().iterator(); e.hasNext(); ) {
+ //int offset = (int)entry.offset;
+ Iterator e = glyphs.keySet().iterator();
+ while (e.hasNext()) {
Integer origIndex = (Integer)e.next();
Integer subsetIndex = (Integer)glyphs.get(origIndex);
writeUShort(currentPos + subsetIndex.intValue() * 4,
- mtx_tab[origIndex.intValue()].wx);
+ mtxTab[origIndex.intValue()].getWx());
writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
- mtx_tab[origIndex.intValue()].lsb);
+ mtxTab[origIndex.intValue()].getLsb());
}
int checksum = getCheckSum(currentPos, hmtxSize);
* Returns a List containing the glyph itself plus all glyphs
* that this composite glyph uses
*/
- private ArrayList getIncludedGlyphs(FontFileReader in, int glyphOffset,
+ private List getIncludedGlyphs(FontFileReader in, int glyphOffset,
Integer glyphIdx) throws IOException {
- ArrayList ret = new ArrayList();
+ List ret = new java.util.ArrayList();
ret.add(glyphIdx);
- int offset = glyphOffset + (int)mtx_tab[glyphIdx.intValue()].offset
- + 10;
+ int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10;
Integer compositeIdx = null;
int flags = 0;
boolean moreComposites = true;
offset += 2;
}
- if ((flags & 8) > 0)
+ if ((flags & 8) > 0) {
offset += 2; // WE_HAVE_A_SCALE
- else if ((flags & 64) > 0)
+ } else if ((flags & 64) > 0) {
offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
- else if ((flags & 128) > 0)
+ } else if ((flags & 128) > 0) {
offset += 8; // WE_HAVE_A_TWO_BY_TWO
+ }
- if ((flags & 32) > 0)
+ if ((flags & 32) > 0) {
moreComposites = true;
- else
+ } else {
moreComposites = false;
+ }
}
return ret;
* Rewrite all compositepointers in glyphindex glyphIdx
*
*/
- private void remapComposite(FontFileReader in, HashMap glyphs,
+ private void remapComposite(FontFileReader in, Map glyphs,
int glyphOffset,
Integer glyphIdx) throws IOException {
- int offset = glyphOffset + (int)mtx_tab[glyphIdx.intValue()].offset
+ int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset()
+ 10;
Integer compositeIdx = null;
offset += 8; // WE_HAVE_A_TWO_BY_TWO
}
- if ((flags & 32) > 0)
+ if ((flags & 32) > 0) {
moreComposites = true;
- else
+ } else {
moreComposites = false;
+ }
}
}
* mapping
*/
private void scanGlyphs(FontFileReader in,
- HashMap glyphs) throws IOException {
+ Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
- HashMap newComposites = null;
- HashMap allComposites = new HashMap();
+ Map newComposites = null;
+ Map allComposites = new java.util.HashMap();
int newIndex = glyphs.size();
if (entry != null) {
while (newComposites == null || newComposites.size() > 0) {
// Inefficient to iterate through all glyphs
- newComposites = new HashMap();
+ newComposites = new java.util.HashMap();
- for (Iterator e = glyphs.keySet().iterator(); e.hasNext(); ) {
+ Iterator e = glyphs.keySet().iterator();
+ while (e.hasNext()) {
Integer origIndex = (Integer)e.next();
- if (in.readTTFShort(entry.offset
- + mtx_tab[origIndex.intValue()].offset) < 0) {
+ if (in.readTTFShort(entry.getOffset()
+ + mtxTab[origIndex.intValue()].getOffset()) < 0) {
// origIndex is a composite glyph
allComposites.put(origIndex, glyphs.get(origIndex));
- ArrayList composites =
- getIncludedGlyphs(in, (int)entry.offset,
+ List composites =
+ getIncludedGlyphs(in, (int)entry.getOffset(),
origIndex);
// Iterate through all composites pointed to
// by this composite and check if they exists
// in the glyphs map, add them if not.
- for (Iterator cps = composites.iterator();
- cps.hasNext(); ) {
-
+ Iterator cps = composites.iterator();
+ while (cps.hasNext()) {
Integer cIdx = (Integer)cps.next();
if (glyphs.get(cIdx) == null
&& newComposites.get(cIdx) == null) {
}
// Add composites to glyphs
- for (Iterator m = newComposites.keySet().iterator();
- m.hasNext(); ) {
+ Iterator m = newComposites.keySet().iterator();
+ while (m.hasNext()) {
Integer im = (Integer)m.next();
glyphs.put(im, newComposites.get(im));
}
}
// Iterate through all composites to remap their composite index
-
- for (Iterator ce = allComposites.keySet().iterator();
- ce.hasNext(); ) {
- remapComposite(in, glyphs, (int)entry.offset,
+ Iterator ce = allComposites.keySet().iterator();
+ while (ce.hasNext()) {
+ remapComposite(in, glyphs, (int)entry.getOffset(),
(Integer)ce.next());
}
/**
- * glyphs has old index as (Integer) key and new index
- * as (Integer) value
+ * Returns a subset of the original font.
+ *
+ * @param in FontFileReader to read from
+ * @param name Name to be checked for in the font file
+ * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
+ * new index as (Integer) value)
+ * @return A subset of the original font
+ * @throws IOException in case of an I/O problem
*/
-
public byte[] readFont(FontFileReader in, String name,
- HashMap glyphs) throws IOException {
+ Map glyphs) throws IOException {
- /*
- * Check if TrueType collection, and that the name
- * exists in the collection
- */
- if (!checkTTC(in, name))
+ //Check if TrueType collection, and that the name exists in the collection
+ if (!checkTTC(in, name)) {
throw new IOException("Failed to read font");
+ }
output = new byte[in.getFileSize()];
System.arraycopy(buf, 0, output, currentPos, buf.length);
length = buf.length;
currentPos += length;
- } catch (Exception e) {
+ } catch (java.io.UnsupportedEncodingException e) {
// This should never happen!
}
*/
private int readUShort(int pos) {
int ret = (int)output[pos];
- if (ret < 0)
+ if (ret < 0) {
ret += 256;
+ }
ret = ret << 8;
if ((int)output[pos + 1] < 0) {
ret |= (int)output[pos + 1] + 256;
- } else
+ } else {
ret |= (int)output[pos + 1];
+ }
return ret;
}
*/
private int maxPow2(int max) {
int i = 0;
- while (Math.pow(2, (double)i) < max)
+ while (Math.pow(2, (double)i) < max) {
i++;
+ }
return (i - 1);
}
// All the tables here are aligned on four byte boundaries
// Add remainder to size if it's not a multiple of 4
int remainder = size % 4;
- if (remainder != 0)
+ if (remainder != 0) {
size += remainder;
+ }
long sum = 0;
l += (int)(output[start + i + 2] << 16);
l += (int)(output[start + i + 3] << 16);
sum += l;
- if (sum > 0xffffffff)
+ if (sum > 0xffffffff) {
sum = sum - 0xffffffff;
+ }
}
return sum;