Получить имя шрифта из файла из папки активов

У меня есть эта функция, которую пользователь выбирает из списка разных шрифтов. Теперь я хочу получить точное имя файла шрифта, который я пытаюсь использовать.

Я показываю имя файла шрифта, но не имя шрифта. Бывший. «Arial.tff» или «BROADW.tff».

Это тот, который я хочу получить из файла.

введите здесь описание изображения

Я хочу получить поле заголовка здесь. Это возможно?

Вот мой код при попытке получить все файлы шрифтов из моей папки активов.

String[] fileList;
AssetManager aMan = getAssets();
    try {
        fileList = aMan.list("");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Затем я просто отображаю это в адаптере, и когда пользователь выбирает этот шрифт, я конвертирую его. Любые идеи? Спасибо.


person Luke Villanueva    schedule 19.08.2015    source источник
comment
Вы помещаете шрифты в assest, поэтому у вас наверняка есть имена шрифтов... и затем вы можете поместить их в ArrayList или массив... статическим способом, и вы можете легко их использовать.   -  person shreyash mashru    schedule 19.08.2015
comment
Можете ли вы показать пример того, как я могу извлечь имя шрифта из файла?   -  person Luke Villanueva    schedule 19.08.2015
comment
что вы получаете в списке файлов? Или вы получаете сообщение об ошибке, тогда, пожалуйста, покажите журнал здесь   -  person shreyash mashru    schedule 19.08.2015
comment
Я получаю файл так же, как я сказал в своем сообщении. Arial.tff или BROADW.tff. Но я также хочу получить точное название шрифта, как на моем скриншоте. Не только имя файла шрифта.   -  person Luke Villanueva    schedule 19.08.2015
comment
Хорошо, какое точное название шрифта в Arial.tff? Пожалуйста, приведите пример. Мы не можем видеть, из каких окон файлов отображалась информация. И нигде не вижу Имя.   -  person greenapps    schedule 19.08.2015
comment
Не совсем Arial.tff. Посмотрите на мой скриншот. Имя файла AGENCYB.TFF, но имя шрифта — Agency FB Bold. Я хочу получить это имя/титул. Плохо, я должен был сказать титул, а не имя. Отредактировал мой пост.   -  person Luke Villanueva    schedule 21.08.2015


Ответы (1)


Вам нужно будет разобрать файл шрифта. Сначала я вставлю код примера при получении имени шрифта. Затем я вставлю код, извлеченный и измененный из 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 (используется в 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 &gt; 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() {

    }

}
person Jared Rummler    schedule 21.08.2015
comment
Привет, спасибо за этот замечательный ответ, я просто хотел бы спросить, каким должно быть значение DEFAULT_BUFFER в методе copyLarge в IOUtils.java, а также переменная EOF? - person Luke Villanueva; 22.08.2015
comment
Это сделало трюк! Немного изменил его в зависимости от потребностей моего приложения. Большое спасибо. - person Luke Villanueva; 23.08.2015
comment
@KamenDobrev Так и должно быть. Попробуйте. Также посетите github.com/jaredrummler/sfntly. - person Jared Rummler; 11.03.2019
comment
Большой! Эти файлы также можно без проблем использовать в Android. - person alijandro; 05.07.2019