I have this function that the user selects from a list of different fonts. Now I want to get the exact name of the font file I'm trying to use.
I'm displaying the font file name, but not the name of the font. Ex. "Arial.tff" or "BROADW.tff".
This is the one that I want to get from the file.
I want to get the title field here. Is that possible?
Here's my code when trying to get all the font files from my asset folder.
String[] fileList;
AssetManager aMan = getAssets();
try {
fileList = aMan.list("");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Then I just display this into a adapter and when the user choose that font, I convert it. Any Ideas? Thanks.
You will need to parse the font file. I will first paste example code on getting the font name. Then I will paste the code I extracted and modified from Apache FOP.
try {
String pathToFontInAssets = "fonts/Arrial.ttf";
InputStream inputStream = getAssets().open(pathToFontInAssets);
TTFFile ttfFile = FontFileReader.readTTF(inputStream);
String fontName = ttfFile.getFullName();
} catch (IOException e) {
e.printStackTrace();
}
FontFileReader.java
/*
* 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: FontFileReader.java 1357883 2012-07-05 20:29:53Z gadams $ */
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Reads a TrueType font file into a byte array and provides file like functions for array access.
*/
public class FontFileReader {
/**
* Read a font file
*
* @param path absolute path to the font file.
* @return
* @throws IOException if an error occurred while reading the font.
*/
public static TTFFile readTTF(String path) throws IOException {
TTFFile ttfFile = new TTFFile();
ttfFile.readFont(new FontFileReader(path));
return ttfFile;
}
/**
* Read a font file
*
* @param inputStream InputStream to read from
* @return
* @throws IOException if an error occurred while reading the font.
*/
public static TTFFile readTTF(InputStream inputStream) throws IOException {
TTFFile ttfFile = new TTFFile();
ttfFile.readFont(new FontFileReader(inputStream));
return ttfFile;
}
private int fsize; // file size
private int current; // current position in file
private byte[] file;
/**
* Constructor
*
* @param in
* InputStream to read from
* @throws IOException
* In case of an I/O problem
*/
public FontFileReader(InputStream in) throws IOException {
init(in);
}
/**
* Constructor
*
* @param fileName
* filename to read
* @throws IOException
* In case of an I/O problem
*/
public FontFileReader(String fileName) throws IOException {
File f = new File(fileName);
InputStream in = new FileInputStream(f);
try {
init(in);
} finally {
in.close();
}
}
/**
* Returns the full byte array representation of the file.
*
* @return byte array.
*/
public byte[] getAllBytes() {
return file;
}
/**
* 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;
}
/**
* 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 in) throws java.io.IOException {
file = IOUtils.toByteArray(in);
fsize = file.length;
current = 0;
}
/**
* Read 1 byte.
*
* @return One byte
* @throws IOException
* If EOF is reached
*/
private byte read() throws IOException {
if (current >= fsize) {
throw new EOFException("Reached EOF, file size=" + fsize);
}
byte ret = file[current++];
return ret;
}
/**
* Read 1 signed byte.
*
* @return One byte
* @throws IOException
* If EOF is reached
*/
public byte readTTFByte() throws IOException {
return read();
}
/**
* Read 4 bytes.
*
* @return One signed integer
* @throws IOException
* If EOF is reached
*/
public int readTTFLong() throws IOException {
long ret = readTTFUByte(); // << 8;
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
return (int) ret;
}
/**
* Read an ISO-8859-1 string of len bytes.
*
* @param len
* The bytesToUpload of the string to read
* @return A String
* @throws IOException
* If EOF is reached
*/
public String readTTFString(int len) throws IOException {
if ((len + current) > fsize) {
throw new EOFException("Reached EOF, file size=" + fsize);
}
byte[] tmp = new byte[len];
System.arraycopy(file, current, tmp, 0, len);
current += len;
String encoding;
if ((tmp.length > 0) && (tmp[0] == 0)) {
encoding = "UTF-16BE";
} else {
encoding = "ISO-8859-1";
}
return new String(tmp, encoding);
}
/**
* Read an ISO-8859-1 string of len bytes.
*
* @param len
* The bytesToUpload of the string to read
* @param encodingID
* the string encoding id (presently ignored; always uses UTF-16BE)
* @return A String
* @throws IOException
* If EOF is reached
*/
public String readTTFString(int len, int encodingID) throws IOException {
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);
current += len;
String encoding;
encoding = "UTF-16BE"; // Use this for all known encoding IDs for now
return new String(tmp, encoding);
}
/**
* Read 1 unsigned byte.
*
* @return One unsigned byte
* @throws IOException
* If EOF is reached
*/
public int readTTFUByte() throws IOException {
byte buf = read();
if (buf < 0) {
return 256 + buf;
} else {
return buf;
}
}
/**
* Read 4 bytes.
*
* @return One unsigned integer
* @throws IOException
* If EOF is reached
*/
public long readTTFULong() throws IOException {
long ret = readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
return ret;
}
/**
* Read 2 bytes unsigned.
*
* @return One unsigned short
* @throws IOException
* If EOF is reached
*/
public int readTTFUShort() throws IOException {
int ret = (readTTFUByte() << 8) + readTTFUByte();
return ret;
}
/**
* Set current file position to offset
*
* @param offset
* The new offset to set
* @throws IOException
* In case of an I/O problem
*/
public void seekSet(long offset) throws IOException {
if (offset > fsize || offset < 0) {
throw new EOFException("Reached EOF, file size=" + fsize + " offset=" + offset);
}
current = (int) offset;
}
/**
* 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 {
seekSet(current + add);
}
}
TTFDirTabEntry.java
/*
* 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: TTFDirTabEntry.java 1357883 2012-07-05 20:29:53Z gadams $ */
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* This class represents an entry to a TrueType font's Dir Tab.
*/
public class TTFDirTabEntry {
private final byte[] tag = new byte[4];
private long offset;
private long length;
TTFDirTabEntry() {
}
public TTFDirTabEntry(long offset, long length) {
this.offset = offset;
this.length = length;
}
/**
* Returns the bytesToUpload.
*
* @return long
*/
public long getLength() {
return length;
}
/**
* Returns the offset.
*
* @return long
*/
public long getOffset() {
return offset;
}
/**
* Returns the tag bytes.
*
* @return byte[]
*/
public byte[] getTag() {
return tag;
}
/**
* Returns the tag bytes.
*
* @return byte[]
*/
public String getTagString() {
try {
return new String(tag, "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
return toString(); // Should never happen.
}
}
/**
* Read Dir Tab.
*
* @param in
* font file reader
* @return tag name
* @throws IOException
* upon I/O exception
*/
public String read(FontFileReader in) throws IOException {
tag[0] = in.readTTFByte();
tag[1] = in.readTTFByte();
tag[2] = in.readTTFByte();
tag[3] = in.readTTFByte();
in.skip(4); // Skip checksum
offset = in.readTTFULong();
length = in.readTTFULong();
String tagStr = new String(tag, "ISO-8859-1");
return tagStr;
}
@Override
public String toString() {
return "Read dir tab [" + tag[0] + " " + tag[1] + " " + tag[2] + " " + tag[3] + "]"
+ " offset: " + offset + " bytesToUpload: " + length + " name: " + tag;
}
}
TTFFile.java
/*
* 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 1395925 2012-10-09 09:13:18Z jeremias $ */
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 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 {
/** The FontFileReader used to read this TrueType font. */
private FontFileReader fontFile;
/**
* Table directory
*/
private Map<TTFTableName, TTFDirTabEntry> dirTabs;
private String postScriptName = "";
private String fullName = "";
private String notice = "";
private final Set<String> familyNames = new HashSet<String>();
private String subFamilyName = "";
TTFFile() {
}
/**
* Returns the font family names of the font.
*
* @return Set The family names (a Set of Strings)
*/
public Set<String> getFamilyNames() {
return familyNames;
}
/**
* Returns the full name of the font.
*
* @return String The full name
*/
public String getFullName() {
return fullName;
}
public String getNotice() {
return notice;
}
/**
* Returns the PostScript name of the font.
*
* @return String The PostScript name
*/
public String getPostScriptName() {
return postScriptName;
}
/**
* Returns the font sub family name of the font.
*
* @return String The sub family name
*/
public String getSubFamilyName() {
return subFamilyName;
}
/**
* Read Table Directory from the current position in the FontFileReader and fill the global
* HashMap dirTabs with the table name (String) as key and a TTFDirTabEntry as value.
*
* @throws IOException
* in case of an I/O problem
*/
private void readDirTabs() throws IOException {
fontFile.readTTFLong(); // TTF_FIXED_SIZE (4 bytes)
int ntabs = fontFile.readTTFUShort();
fontFile.skip(6); // 3xTTF_USHORT_SIZE
dirTabs = new HashMap<>();
TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs];
for (int i = 0; i < ntabs; i++) {
pd[i] = new TTFDirTabEntry();
String tableName = pd[i].read(fontFile);
dirTabs.put(TTFTableName.getValue(tableName), pd[i]);
}
dirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0L, fontFile.getCurrentPos()));
}
/**
* Reads the font using a FontFileReader.
*
* @param in
* The FontFileReader to use
* @throws IOException
* In case of an I/O problem
*/
void readFont(FontFileReader in) throws IOException {
fontFile = in;
readDirTabs();
readName();
}
/**
* Read the "name" table.
*
* @throws IOException
* In case of a I/O problem
*/
private void readName() throws IOException {
seekTab(fontFile, TTFTableName.NAME, 2);
int i = fontFile.getCurrentPos();
int n = fontFile.readTTFUShort();
int j = fontFile.readTTFUShort() + i - 2;
i += 2 * 2;
while (n-- > 0) {
fontFile.seekSet(i);
int platformID = fontFile.readTTFUShort();
int encodingID = fontFile.readTTFUShort();
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);
}
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;
}
}
/**
* Position inputstream to position indicated in the dirtab offset + offset
*
* @param in
* font file reader
* @param tableName
* (tag) of table
* @param offset
* from start of table
* @return true if seek succeeded
* @throws IOException
* if I/O exception occurs during seek
*/
private boolean seekTab(FontFileReader in, TTFTableName tableName, long offset)
throws IOException
{
TTFDirTabEntry dt = dirTabs.get(tableName);
if (dt == null) {
return false;
} else {
in.seekSet(dt.getOffset() + offset);
}
return true;
}
}
TTFTableName.java
/*
* 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: TTFTableName.java 1357883 2012-07-05 20:29:53Z gadams $ */
/**
* Represents table names as found in a TrueType font's Table Directory. TrueType fonts may have
* custom tables so we cannot use an enum.
*/
public final class TTFTableName {
/** The first table in a TrueType font file containing metadata about other tables. */
public static final TTFTableName TABLE_DIRECTORY = new TTFTableName("tableDirectory");
/** Naming table. */
public static final TTFTableName NAME = new TTFTableName("name");
/**
* Returns an instance of this class corresponding to the given string representation.
*
* @param tableName
* table name as in the Table Directory
* @return TTFTableName
*/
public static TTFTableName getValue(String tableName) {
if (tableName != null) {
return new TTFTableName(tableName);
}
throw new IllegalArgumentException("A TrueType font table name must not be null");
}
private final String name;
private TTFTableName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof TTFTableName)) {
return false;
}
TTFTableName to = (TTFTableName) o;
return name.equals(to.getName());
}
/**
* Returns the name of the table as it should be in the Directory Table.
*/
public String getName() {
return name;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return name;
}
}
IOUtils.java (used in FontFileReader)
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class IOUtils {
private static int DEFAULT_BUFFER = 4096; // 4kb
private static int EOF = -1; // end of file
/**
* Get the contents of an {@code InputStream} as a {@code byte[]}.
* <p/>
* This method buffers the input internally, so there is no need to use a {@code
* BufferedInputStream}.
*
* @param input
* the {@code InputStream} to read from
* @return the requested byte array
* @throws NullPointerException
* if the input is null
* @throws IOException
* if an I/O error occurs
*/
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(input, output);
return output.toByteArray();
}
/**
* Copy bytes from an {@code InputStream} to an {@code OutputStream}.</p>
* <p/>
* This method buffers the input internally, so there is no need to use a {@code
* BufferedInputStream}.</p>
* <p/>
* Large streams (over 2GB) will return a bytes copied value of {@code -1} after the copy has
* completed since the correct number of bytes cannot be returned as an int. For large streams
* use the {@code copyLarge(InputStream, OutputStream)} method.</p>
*
* @param input
* the {@code InputStream} to read from
* @param output
* the {@code OutputStream} to write to
* @return the number of bytes copied, or -1 if > Integer.MAX_VALUE
* @throws NullPointerException
* if the input or output is null
* @throws IOException
* if an I/O error occurs
*/
public static int copy(InputStream input, OutputStream output) throws IOException {
long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
/**
* Copy bytes from a large (over 2GB) {@code InputStream} to an {@code OutputStream}.</p>
* <p/>
* This method buffers the input internally, so there is no need to use a {@code
* BufferedInputStream}.</p>
* <p/>
* The buffer size is given by {@link #DEFAULT_BUFFER}.</p>
*
* @param input
* the {@code InputStream} to read from
* @param output
* the {@code OutputStream} to write to
* @return the number of bytes copied
* @throws NullPointerException
* if the input or output is null
* @throws IOException
* if an I/O error occurs
*/
public static long copyLarge(InputStream input, OutputStream output) throws
IOException
{
return copyLarge(input, output, new byte[DEFAULT_BUFFER]);
}
/**
* Copy bytes from a large (over 2GB) {@code InputStream} to an {@code OutputStream}.</p>
* <p/>
* This method uses the provided buffer, so there is no need to use a {@code
* BufferedInputStream}.</p>
*
* @param input
* the {@code InputStream} to read from
* @param output
* the {@code OutputStream} to write to
* @param buffer
* the buffer to use for the copy
* @return the number of bytes copied
* @throws NullPointerException
* if the input or output is null
* @throws IOException
* if an I/O error occurs
*/
public static long copyLarge(InputStream input, OutputStream output, byte[] buffer)
throws IOException
{
long count = 0;
int n = 0;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
private IOUtils() {
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With