Разбор информации из шрифта TrueType - PullRequest
2 голосов
/ 13 марта 2011

Это код PHP, который у меня есть:

https://gist.github.com/2eeba2ff31ebecb526e2

Вот результат:

https://gist.github.com/cf07fe90922ac3dfcd22

Теперь скажите, что мне нужно получить информацию, на которую есть ссылки в этой таблице:

object(ttfTableDirectoryEntry)#6 (4) {
  ["tag"]=>
  string(4) "cmap"
  ["checksum"]=>
  int(2553734765)
  ["offset"]=>
  int(1556)
  ["length"]=>
  int(1190)
}

Как мне это сделать?

В общем, мне нужно проанализировать информацию для каждой из этих таблиц.

Это то, что вы получите, если просто попытаетесьпарсит данные со смещения по длине.

object(ttfTableDirectoryEntry)#12 (4) {
  ["tag"]=>
  string(4) "name"
  ["checksum"]=>
  int(3955157420)
  ["offset"]=>
  int(400)
  ["length"]=>
  int(1153)
}
string(1153) "���>��������:����������:��������F�������"�L��������n�������
������������������5�����������������    �#��������
�:������������������    ���t#�� �����   �����   ��D���  ��$���  ��#��   ��$���  ��j=��  �����   �   �F���   �
�t#��   ��: ��  ��: Copyright (c) 2010 by YouWorkForThem. All rights reserved.YWFT HLLVTKANormalYouWorkForThem: YWFT HLLVTKA: 2010YWFT HLLVTKA NormalVersion 1.000YWFTHLLVTKA-NormalYWFT HLLVTKA Normal is a trademark of YouWorkForThem.YouWorkForThemEric Carlson & Taechit Jiropaskosolhttp://www.youworkforthem.com�C�o�p�y�r�i�g�h�t� �(�c�)� �2�0�1�0� �b�y� �Y�o�u�W�o�r�k�F�o�r�T�h�e�m�.� �A�l�l� �r�i�g�h�t�s� �r�e�s�e�r�v�e�d�.�Y�W�F�T� �H�L�L�V�T�K�A�N�o�r�m�a�l�Y�o�u�W�o�r�k�F�o�r�T�h�e�m�:� �Y�W�F�T� �H�L�L�V�T�K�A�:� �2�0�1�0�Y�W�F�T�H�L�L�V�T�K�A�-�N�o�r�m�a�l�V�e�r�s�i�o�n� �1�.�0�0�0�Y�W�F�T� �H�L�L�V�T�K�A� �N�o�r�m�a�l� �i�s� �a� �t�r�a�d�e�m�a�r�k� �o�f� �Y�o�u�W�o�r�k�F�o�r�T�h�e�m�.�Y�o�u�W�o�r�k�F�o�r�T�h�e�m�E�r�i�c� �C�a�r�l�s�o�n� �&� �T�a�e�c�h�i�t� �J�i�r�o�p�a�s�k�o�s�o�l�h�t�t�p�:�/�/�w�w�w�.�y�o�u�w�o�r�k�f�o�r�t�h�e�m�.�c�o�m"

1 Ответ

4 голосов
/ 23 марта 2011

Я пытался добиться этого и подошел к его созданию. Тем не менее, в конце я решил использовать Python вместо этого при разборе данных. Во всяком случае, если кто-то решит, что он хочет идти по пути PHP, вот что я имею до этого момента. Это один шаг близко к получению карты глифа. Для документации о том, как читать данные, обратитесь к http://developer.apple.com/fonts/ttrefman/RM06/Chap6.html.

<?php
$ttr    = new TrueTypeReader;
$ttr->open('font.otf');


class TrueTypeReader
{
    private $position   = 0;
    private $offset     = 0;

    private $file;

    public function open($file)
    {       
        $this->file         = file_get_contents($file);

        // http://developer.apple.com/fonts/ttrefman/RM06/Chap6.html
        // The offset subtable      
        $number_of_tables   = $this->getUint16(4);

        $this->tables       = array();

        for($i = 0; $i < $number_of_tables; $i++)
        {
            // http://developer.apple.com/fonts/ttrefman/RM06/Chap6.html
            // The table directory

            $table          = array();

            $tag            = $this->getTag(12 + $i * 16);

            $table          = array
            (
                'tag'       => $tag,
                'check_sum' => $this->getUint32(12 + $i * 16 + 4),
                'offset'    => $this->getUint32(12 + $i * 16 + 8),
                'length'    => $this->getUint32(12 + $i * 16 + 12),
            );

            if($tag == 'cmap')
            {
                $this->parseCmapTable($table);
            }

            $this->tables[] = $table;
        }
    }


    private function getTag($pt = FALSE)
    {
        if($pt === FALSE)
        {
            $pt = $this->position;

            $this->position += 4;
        }

        return substr($this->file, $pt, 4);
    }

    private function getUint32($pt = FALSE)
    {
        if($pt === FALSE)
        {
            $pt = $this->position;
            $this->position += 4;
        }

        $r = unpack("N", substr($this->file, $pt, 4) );

        return $r[1];
    }

    private function getUint16($pt = FALSE)
    {
        if ($pt === FALSE)
        {
            $pt = $this->position;
            $this->position += 2;
        }

        $r = unpack("n", substr($this->file, $pt, 2) );

        return $r[1];
    }

    private function parseCmapTable($table)
    {
        $this->position         = $table['offset'];

        // http://developer.apple.com/fonts/ttrefman/RM06/Chap6cmap.html
        // General table information

        $data   = array
        (
            'version'           => $this->getUint16(),
            'number_subtables'  => $this->getUint16(),
        );

        $sub_tables = array();

        for($i = 0; $i < $data['number_subtables']; $i++)
        {

            // http://developer.apple.com/fonts/ttrefman/RM06/Chap6cmap.html
            // The 'cmap' encoding subtables

            $sub_tables[]   = array
            (
                'platform_id'       => $this->getUint16(),
                'specific_id'       => $this->getUint16(),
                'offset'            => $this->getUint32(),
            );

        }

        // http://developer.apple.com/fonts/ttrefman/RM06/Chap6cmap.html
        // The 'cmap' formats

        $formats                = array();

        foreach($sub_tables as $t)
        {
            // /5049814/tablitsa-sopostavleniya-simvolov-i-simvolov#5049828

            $this->position = $table['offset'] + $t['offset'];

            $format = array
            (
                'format'                    => $this->getUint16(),
                'length'                    => $this->getUint16(),
                'language'                  => $this->getUint16(),
            );

            if($format['format'] == 4)
            {
                $format     += array
                (
                    'seg_count_X2'                  => $this->getUint16(),
                    'search_range'                  => $this->getUint16(),
                    'entry_selector'                => $this->getUint16(),
                    'range_shift'                   => $this->getUint16(),
                    'end_code[segCount]'            => $this->getUint16(),
                    'reserved_pad'                  => $this->getUint16(),
                    'start_code[segCount]'          => $this->getUint16(),
                    'id_delta[segCount]'            => $this->getUint16(),
                    'id_range_offset[segCount]'     => $this->getUint16(),
                    'glyph_index_array[variable]'   => $this->getUint16(),
                );

                $backup = $format;

                $format['seg_count_X2']     = $backup['seg_count_X2']*2;
                $format['search_range']     = 2 * (2 * floor(log($backup['seg_count_X2'], 2)));
                $format['entry_selector']   = log($backup['search_range']/2, 2);
                $format['range_shift']      = (2 * $backup['seg_count_X2']) - $backup['search_range'];
            }

            $formats[$t['offset']]  = $format;
        }       

        die(var_dump( $sub_tables, $formats ));



        die(var_dump( $this->getUint16(), $this->getUint16(), $this->getUint16(), $this->getUint16(), $this->getUint16() ));

        die(var_dump( $sub_tables[0] ));

        $cmap   = array
        (
            'format'            => $this->getUint16(),
            #'length'           => $this->getUint16(),
            #'language'         => $this->getUint16(),
        );

        die(var_dump( $cmap ));

        die(var_dump( $table, $data, $table, $cmap ));
    }

    private function parseNameTable($table)
    {
        // http://developer.apple.com/fonts/ttrefman/RM06/Chap6name.html
        // Name Table Format

        $data   = array
        (
            'format'            => $this->getUint16($table['offset']),
            'count'             => $this->getUint16($table['offset'] + 2), // $num_of_name_tables
            'string_offset'     => $this->getUint16($table['offset'] + 4),
        );

        $offset = $table['offset'] + $data['string_offset']; // $name_tables_offset

        $name_tables = array();

        for($i = 0; $i < $data['count']; $i ++)
        {       
            $this->position     = $table['offset'] + 6 + $i * 12;

            $d  = array
            (
                'platform_id'   => $this->getUint16(),
                'specific_id'   => $this->getUint16(),
                'lang_id'       => $this->getUint16(),
                'name_id'       => $this->getUint16(),
                'length'        => $this->getUint16(),
                'offset'        => $this->getUint16() + $offset,
            );

            $key                = "{$d['platform_id']}::{$d['specific_id']}::{$d['lang_id']}";

            if(isset($d['name_id']) && empty($name_tables[$key][$d['name_id']]))
            {
                $text = substr($this->file, $d['offset'], $d['length']);

                $name_tables[$key][$d['name_id']] = str_replace(chr(0), '', $text);
            }
        }

        die(var_dump( $name_tables ));
    }
}
...