Ошибка смещения таблицы в шрифте OpenType - PullRequest
0 голосов
/ 16 января 2019

У меня есть ошибка, которая вращается вокруг этих трех свойств спецификации для создания шрифта OpenType:

  • searchRange
  • rangeShift
  • entrySelector

На этой странице упоминается, что это так:

  • searchRange - это наибольшая степень, равная двум, меньше или равная количеству элементов в таблице, т. Е. Наибольшему количеству элементов, которые можно легко найти.
  • rangeShift - количество элементов минус searchRange; то есть количество элементов, которые не будут просматриваться, если вы посмотрите только на элементы searchRange.
  • entrySelector - это log2 (searchRange).

Учитывая эту информацию, мы имеем:

  • searchRange = maxPowerOf2 <= n, где n - количество элементов в таблице.
  • rangeShift = n - searchRange
  • entrySelector = log2(searchRange)

Но потом мы читаем немного дальше.

Обратите внимание, что searchRange, entrySelector и rangeShift умножаются на 16, что соответствует размеру записи каталога.

Так что теперь у нас есть:

  • searchRange = 16 * maxPowerOf2 <= n, где n - количество элементов в таблице.
  • rangeShift = 16 * n - searchRange
  • entrySelector = 16 * log2(searchRange)

Но подождите, следующая таблица показывает это:

  • searchRange : (maximum power of 2 <= numTables)*16
  • entrySelector : log2(maximum power of 2 <= numTables)
  • rangeShift : numTables*16-searchRange

Так что это означает, что наш entrySelector не имеет множителя 16, как кажется:

  • searchRange = 16 * maxPowerOf2 <= n, где n - количество элементов в таблице.
  • rangeShift = 16 * n - searchRange
  • entrySelector = log2(searchRange)

Но подождите, есть еще :

  • searchRange (Maximum power of 2 <= numTables) x 16
  • entrySelector Log2(maximum power of 2 <= numTables)
  • rangeShift NumTables x 16-searchRange

Это соответствует нашему последнему.

Проверка исходного кода произвольного шрифта , он также совпадает с последним.

То, что я не понимаю, единственное, что сработало для меня, это первое:

let maxPowerOf2 = Math.pow(2, maxExponentFor2);
var searchRange = maxPowerOf2
var entrySelector = Math.log2(searchRange)
var rangeShift = numTables - searchRange

Это единственное, что избавило меня от ошибки:

OTS parsing error: incorrect entrySelector for table directory

Но тогда я получаю эту ошибку:

OTS parsing error: CFF : misaligned table

Учитывая этот вывод:

4f54 544f 0009 0008 0003 0001 4346 4620
0000 0000 0000 00c2 9c00 0000 0563 6d61
7000 0000 0000 0000 c2a4 0000 0024 6865
6164 0000 0000 0000 00c3 8800 0000 3668
6865 6100 0000 0000 0001 0000 0000 2468
6d74 7800 0000 0000 0001 2400 0000 006d
6178 7000 0000 0000 0001 2400 0000 066e
616d 6500 0000 0000 0001 2c00 0000 064f
532f 3200 0000 0000 0001 3400 0000 6470
6f73 7400 0000 0000 0001 c298 0000 0020
0200 0400 0000 0000 0000 0001 0000 0006
0000 0010 0004 0010 0000 0002 0002 0000
0000 c3bf c3bf 0000 c3bf c3bf 0001 0000
0001 0000 0001 0000 0000 0000 5f0f 3cc3
b500 0303 c3a8 0000 0000 c398 6526 c388
0000 0000 c398 6526 c388 0000 0000 0000
0000 0000 0003 0002 0000 0000 0000 0001
0000 00c3 8800 6400 0000 0000 0000 0000
0000 0100 0000 0000 0000 0000 0000 0000
0000 0000 0050 0000 0000 0000 0000 0000
0600 0000 0500 0000 0000 0000 0002 c28a
02c2 bb00 0000 c28c 02c2 8a02 c2bb 0000
01c3 9f00 3101 0200 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0058 5858 5800 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0300
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 00

Попытка того, как это делает большинство (две ссылки на документ и исходный код), но которая дает мне первую ошибку, такова:

4f54 544f 0009 00c2 8000 0700 1043 4646
2000 0000 0000 0000 c29c 0000 0005 636d
6170 0000 0000 0000 00c2 a400 0000 2468
6561 6400 0000 0000 0000 c388 0000 0036
6868 6561 0000 0000 0000 0100 0000 0024
686d 7478 0000 0000 0000 0124 0000 0000
6d61 7870 0000 0000 0000 0124 0000 0006
6e61 6d65 0000 0000 0000 012c 0000 0006
4f53 2f32 0000 0000 0000 0134 0000 0064
706f 7374 0000 0000 0000 01c2 9800 0000
2002 0004 0000 0000 0000 0000 0100 0000
0600 0000 1000 0400 1000 0000 0200 0200
0000 00c3 bfc3 bf00 00c3 bfc3 bf00 0100
0000 0100 0000 0100 0000 0000 005f 0f3c
c3b5 0003 03c3 a800 0000 00c3 9865 271d
0000 0000 c398 6527 1d00 0000 0000 0000
0000 0000 0300 0200 0000 0000 0000 0100
0000 c388 0064 0000 0000 0000 0000 0000
0001 0000 0000 0000 0000 0000 0000 0000
0000 0000 5000 0000 0000 0000 0000 0006
0000 0005 0000 0000 0000 0000 02c2 8a02
c2bb 0000 00c2 8c02 c28a 02c2 bb00 0001
c39f 0031 0102 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 5858 5858 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0003 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 

В этом пока нет глифов, только минимум. Хотите знать, что мне не хватает, чтобы заставить это работать.

Если это вообще полезно, то это были основные данные, которые пошли на создание двоичного файла:

{
  "name": "sfnt",
  "fields": {
    "scalar": {
      "type": "TAG",
      "value": "OTTO"
    },
    "numTables": {
      "type": "USHORT",
      "value": 9
    },
    "searchRange": {
      "type": "USHORT",
      "value": 128
    },
    "entrySelector": {
      "type": "USHORT",
      "value": 7
    },
    "rangeShift": {
      "type": "USHORT",
      "value": 16
    },
    "CFF  Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "CFF "
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 156
          },
          "length": {
            "type": "ULONG",
            "value": 5
          }
        }
      }
    },
    "cmap Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "cmap"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 164
          },
          "length": {
            "type": "ULONG",
            "value": 36
          }
        }
      }
    },
    "head Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "head"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 200
          },
          "length": {
            "type": "ULONG",
            "value": 54
          }
        }
      }
    },
    "hhea Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "hhea"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 256
          },
          "length": {
            "type": "ULONG",
            "value": 36
          }
        }
      }
    },
    "hmtx Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "hmtx"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 292
          },
          "length": {
            "type": "ULONG",
            "value": 0
          }
        }
      }
    },
    "maxp Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "maxp"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 292
          },
          "length": {
            "type": "ULONG",
            "value": 6
          }
        }
      }
    },
    "name Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "name"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 300
          },
          "length": {
            "type": "ULONG",
            "value": 6
          }
        }
      }
    },
    "OS/2 Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "OS/2"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 308
          },
          "length": {
            "type": "ULONG",
            "value": 100
          }
        }
      }
    },
    "post Table Record": {
      "type": "RECORD",
      "value": {
        "name": "Table Record",
        "fields": {
          "tag": {
            "type": "TAG",
            "value": "post"
          },
          "checkSum": {
            "type": "ULONG",
            "value": 0
          },
          "offset": {
            "type": "ULONG",
            "value": 408
          },
          "length": {
            "type": "ULONG",
            "value": 32
          }
        }
      }
    },
    "CFF  table": {
      "type": "RECORD",
      "value": {
        "name": "CFF ",
        "fields": {
          "header": {
            "type": "RECORD",
            "value": {
              "name": "Header",
              "fields": {
                "major": {
                  "type": "BYTE",
                  "value": 2
                },
                "minor": {
                  "type": "BYTE",
                  "value": 0
                },
                "hdrSize": {
                  "type": "BYTE",
                  "value": 4
                },
                "topDictLength": {
                  "type": "USHORT",
                  "value": 0
                }
              }
            }
          }
        }
      }
    },
    "padding_0": {
      "type": "BYTE",
      "value": 0
    },
    "padding_1": {
      "type": "BYTE",
      "value": 0
    },
    "padding_2": {
      "type": "BYTE",
      "value": 0
    },
    "cmap table": {
      "type": "RECORD",
      "value": {
        "name": "cmap",
        "fields": {
          "version": {
            "type": "USHORT",
            "value": 0
          },
          "numTables": {
            "type": "USHORT",
            "value": 1
          },
          "platformID": {
            "type": "USHORT",
            "value": 0
          },
          "encodingID": {
            "type": "USHORT",
            "value": 6
          },
          "offset": {
            "type": "ULONG",
            "value": 16
          },
          "format": {
            "type": "USHORT",
            "value": 4
          },
          "cmap4Length": {
            "type": "USHORT",
            "value": 16
          },
          "language": {
            "type": "USHORT",
            "value": 0
          },
          "segCountX2": {
            "type": "USHORT",
            "value": 2
          },
          "searchRange": {
            "type": "USHORT",
            "value": 2
          },
          "entrySelector": {
            "type": "USHORT",
            "value": 0
          },
          "rangeShift": {
            "type": "USHORT",
            "value": 0
          },
          "end_0": {
            "type": "USHORT",
            "value": 65535
          },
          "reservedPad": {
            "type": "USHORT",
            "value": 0
          },
          "start_0": {
            "type": "USHORT",
            "value": 65535
          },
          "idDelta_0": {
            "type": "SHORT",
            "value": 1
          },
          "idRangeOffset_0": {
            "type": "USHORT",
            "value": 0
          }
        }
      }
    },
    "head table": {
      "type": "RECORD",
      "value": {
        "name": "head",
        "fields": {
          "version": {
            "type": "FIXED",
            "value": 65536
          },
          "fontRevision": {
            "type": "FIXED",
            "value": 65536
          },
          "checkSumAdjustment": {
            "type": "ULONG",
            "value": 0
          },
          "magicNumber": {
            "type": "ULONG",
            "value": 1594834165
          },
          "flags": {
            "type": "USHORT",
            "value": 3
          },
          "unitsPerEm": {
            "type": "USHORT",
            "value": 1000
          },
          "created": {
            "type": "LONGDATETIME",
            "value": 3630507805
          },
          "modified": {
            "type": "LONGDATETIME",
            "value": 3630507805
          },
          "xMin": {
            "type": "SHORT",
            "value": null
          },
          "yMin": {
            "type": "SHORT",
            "value": null
          },
          "xMax": {
            "type": "SHORT",
            "value": null
          },
          "yMax": {
            "type": "SHORT",
            "value": null
          },
          "macStyle": {
            "type": "USHORT",
            "value": 0
          },
          "lowestRecPPEM": {
            "type": "USHORT",
            "value": 3
          },
          "fontDirectionHint": {
            "type": "SHORT",
            "value": 2
          },
          "indexToLocFormat": {
            "type": "SHORT",
            "value": 0
          },
          "glyphDataFormat": {
            "type": "SHORT",
            "value": 0
          }
        }
      }
    },
    "padding_3": {
      "type": "BYTE",
      "value": 0
    },
    "padding_4": {
      "type": "BYTE",
      "value": 0
    },
    "hhea table": {
      "type": "RECORD",
      "value": {
        "name": "hhea",
        "fields": {
          "version": {
            "type": "FIXED",
            "value": 65536
          },
          "ascender": {
            "type": "FWORD",
            "value": 200
          },
          "descender": {
            "type": "FWORD",
            "value": 100
          },
          "lineGap": {
            "type": "FWORD",
            "value": 0
          },
          "advanceWidthMax": {
            "type": "UFWORD",
            "value": null
          },
          "minLeftSideBearing": {
            "type": "FWORD",
            "value": null
          },
          "minRightSideBearing": {
            "type": "FWORD",
            "value": null
          },
          "xMaxExtent": {
            "type": "FWORD",
            "value": null
          },
          "caretSlopeRise": {
            "type": "SHORT",
            "value": 1
          },
          "caretSlopeRun": {
            "type": "SHORT",
            "value": 0
          },
          "caretOffset": {
            "type": "SHORT",
            "value": 0
          },
          "reserved1": {
            "type": "SHORT",
            "value": 0
          },
          "reserved2": {
            "type": "SHORT",
            "value": 0
          },
          "reserved3": {
            "type": "SHORT",
            "value": 0
          },
          "reserved4": {
            "type": "SHORT",
            "value": 0
          },
          "metricDataFormat": {
            "type": "SHORT",
            "value": 0
          },
          "numberOfHMetrics": {
            "type": "USHORT",
            "value": 0
          }
        }
      }
    },
    "hmtx table": {
      "type": "RECORD",
      "value": {
        "name": "hmtx",
        "fields": {}
      }
    },
    "maxp table": {
      "type": "RECORD",
      "value": {
        "name": "maxp",
        "fields": {
          "version": {
            "type": "FIXED",
            "value": 20480
          },
          "numGlyphs": {
            "type": "USHORT",
            "value": 0
          }
        }
      }
    },
    "padding_5": {
      "type": "BYTE",
      "value": 0
    },
    "padding_6": {
      "type": "BYTE",
      "value": 0
    },
    "name table": {
      "type": "RECORD",
      "value": {
        "name": "name",
        "fields": {
          "format": {
            "type": "USHORT",
            "value": 0
          },
          "count": {
            "type": "USHORT",
            "value": 0
          },
          "stringOffset": {
            "type": "USHORT",
            "value": 6
          },
          "strings": {
            "type": "LITERAL",
            "value": []
          }
        }
      }
    },
    "padding_7": {
      "type": "BYTE",
      "value": 0
    },
    "padding_8": {
      "type": "BYTE",
      "value": 0
    },
    "OS/2 table": {
      "type": "RECORD",
      "value": {
        "name": "OS/2",
        "fields": {
          "version": {
            "type": "USHORT",
            "value": 5
          },
          "xAvgCharWidth": {
            "type": "SHORT",
            "value": 0
          },
          "usWeightClass": {
            "type": "USHORT",
            "value": 0
          },
          "usWidthClass": {
            "type": "USHORT",
            "value": 0
          },
          "fsType": {
            "type": "USHORT",
            "value": 0
          },
          "ySubscriptXSize": {
            "type": "SHORT",
            "value": 650
          },
          "ySubscriptYSize": {
            "type": "SHORT",
            "value": 699
          },
          "ySubscriptXOffset": {
            "type": "SHORT",
            "value": 0
          },
          "ySubscriptYOffset": {
            "type": "SHORT",
            "value": 140
          },
          "ySuperscriptXSize": {
            "type": "SHORT",
            "value": 650
          },
          "ySuperscriptYSize": {
            "type": "SHORT",
            "value": 699
          },
          "ySuperscriptXOffset": {
            "type": "SHORT",
            "value": 0
          },
          "ySuperscriptYOffset": {
            "type": "SHORT",
            "value": 479
          },
          "yStrikeoutSize": {
            "type": "SHORT",
            "value": 49
          },
          "yStrikeoutPosition": {
            "type": "SHORT",
            "value": 258
          },
          "sFamilyClass": {
            "type": "SHORT",
            "value": 0
          },
          "bFamilyType": {
            "type": "BYTE",
            "value": 0
          },
          "bSerifStyle": {
            "type": "BYTE",
            "value": 0
          },
          "bWeight": {
            "type": "BYTE",
            "value": 0
          },
          "bProportion": {
            "type": "BYTE",
            "value": 0
          },
          "bContrast": {
            "type": "BYTE",
            "value": 0
          },
          "bStrokeVariation": {
            "type": "BYTE",
            "value": 0
          },
          "bArmStyle": {
            "type": "BYTE",
            "value": 0
          },
          "bLetterform": {
            "type": "BYTE",
            "value": 0
          },
          "bMidline": {
            "type": "BYTE",
            "value": 0
          },
          "bXHeight": {
            "type": "BYTE",
            "value": 0
          },
          "ulUnicodeRange1": {
            "type": "ULONG",
            "value": 0
          },
          "ulUnicodeRange2": {
            "type": "ULONG",
            "value": 0
          },
          "ulUnicodeRange3": {
            "type": "ULONG",
            "value": 0
          },
          "ulUnicodeRange4": {
            "type": "ULONG",
            "value": 0
          },
          "achVendID": {
            "type": "CHARARRAY",
            "value": "XXXX"
          },
          "fsSelection": {
            "type": "USHORT",
            "value": 0
          },
          "usFirstCharIndex": {
            "type": "USHORT",
            "value": 0
          },
          "usLastCharIndex": {
            "type": "USHORT",
            "value": 0
          },
          "sTypoAscender": {
            "type": "SHORT",
            "value": 0
          },
          "sTypoDescender": {
            "type": "SHORT",
            "value": 0
          },
          "sTypoLineGap": {
            "type": "SHORT",
            "value": 0
          },
          "usWinAscent": {
            "type": "USHORT",
            "value": 0
          },
          "usWinDescent": {
            "type": "USHORT",
            "value": 0
          },
          "ulCodePageRange1": {
            "type": "ULONG",
            "value": 0
          },
          "ulCodePageRange2": {
            "type": "ULONG",
            "value": 0
          },
          "sxHeight": {
            "type": "SHORT",
            "value": 0
          },
          "sCapHeight": {
            "type": "SHORT",
            "value": 0
          },
          "usDefaultChar": {
            "type": "USHORT",
            "value": 0
          },
          "usBreakChar": {
            "type": "USHORT",
            "value": 0
          },
          "usMaxContext": {
            "type": "USHORT",
            "value": 0
          },
          "usLowerOpticalPointSize": {
            "type": "USHORT",
            "value": 0
          },
          "usUpperOpticalPointSize": {
            "type": "USHORT",
            "value": 0
          }
        }
      }
    },
    "post table": {
      "type": "RECORD",
      "value": {
        "name": "post",
        "fields": {
          "version": {
            "type": "FIXED",
            "value": 196608
          },
          "italicAngle": {
            "type": "FIXED",
            "value": 0
          },
          "underlinePosition": {
            "type": "FWORD",
            "value": 0
          },
          "underlineThickness": {
            "type": "FWORD",
            "value": 0
          },
          "isFixedPitch": {
            "type": "ULONG",
            "value": 0
          },
          "minMemType42": {
            "type": "ULONG",
            "value": 0
          },
          "maxMemType42": {
            "type": "ULONG",
            "value": 0
          },
          "minMemType1": {
            "type": "ULONG",
            "value": 0
          },
          "maxMemType1": {
            "type": "ULONG",
            "value": 0
          }
        }
      }
    }
  }
}

И это десятичные значения, используемые для создания выходных байтов для одного из небольших изменений:

79 84 84 79 
0 9 0 8 
0 3 0 1 
67 70 70 32 (1)
0 0 0 0 
0 0 0 156 
0 0 0 5 
99 109 97 112 (2)
0 0 0 0 
0 0 0 164 
0 0 0 36 
104 101 97 100 (3)
0 0 0 0 
0 0 0 200 
0 0 0 54 
104 104 101 97 (4)
0 0 0 0 
0 0 1 0 
0 0 0 36 
104 109 116 120 (5)
0 0 0 0 
0 0 1 36 
0 0 0 0 
109 97 120 112 (6)
0 0 0 0 
0 0 1 36 
0 0 0 6 
110 97 109 101 (7)
0 0 0 0 
0 0 1 44 
0 0 0 6 
79 83 47 50 (8)
0 0 0 0 
0 0 1 52 
0 0 0 100 
112 111 115 116 (9)
0 0 0 0 
0 0 1 152 
0 0 0 32 
2 0 4 0 (CFF start)
0 0 0 0 (4-align with three 0's)
0 0 0 1 (cmap start)
0 0 0 6 
0 0 0 16 
0 4 0 16 
0 0 0 2 0 2 0 0 0 0 255 255 0 0 255 255 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 95 15 60 245 0 3 3 232 0 0 0 0 216 101 49 90 0 0 0 0 216 101 49 90 0 0 0 0 0 0 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 1 0 0 0 200 0 100 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 0 0 0 6 0 0 0 5 0 0 0 0 0 0 0 0 2 138 2 187 0 0 0 140 2 138 2 187 0 0 1 223 0 49 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Кажется, это показывает, что оно выровнено, поэтому я не понимаю. Надеюсь на помощь.

1 Ответ

0 голосов
/ 17 января 2019

При отладке вывода может оказаться полезным использовать формат шестнадцатеричного дампа, который показывает ASCII-представление байтов в правом столбце.Я использую xxd для этого и рекомендую вам сделать то же самое.В частности, для шрифтов OpenType этот формат дампа действительно удобен для выявления проблем с выравниванием, особенно в заголовке шрифта.

Чтобы понять, что я имею в виду: вот первый раздел одного из ваших дампов:

00000000: 4f54 544f 0009 0008 0003 0001 4346 4620  OTTO........CFF 
00000010: 0000 0000 0000 00c2 9c00 0000 0563 6d61  .............cma
00000020: 7000 0000 0000 0000 c2a4 0000 0024 6865  p............$he
00000030: 6164 0000 0000 0000 00c3 8800 0000 3668  ad............6h
00000040: 6865 6100 0000 0000 0001 0000 0000 2468  hea...........$h
00000050: 6d74 7800 0000 0000 0001 2400 0000 006d  mtx.......$....m
00000060: 6178 7000 0000 0000 0001 2400 0000 066e  axp.......$....n
00000070: 616d 6500 0000 0000 0001 2c00 0000 064f  ame.......,....O
00000080: 532f 3200 0000 0000 0001 3400 0000 6470  S/2.......4...dp
00000090: 6f73 7400 0000 0000 0001 c298 0000 0020  ost............ 

Вы можете видеть, что первая запись tableDirectory для CFF таблицы, тег ('CFF') начинается как последние 4 байта первой строки (4346 4620, что в ASCII - 'CFF'),и это правильное выравнивание.Поскольку длина строки hexdump составляет ровно 16 байтов, а каждая запись в tableDirectory составляет 16 байтов, должным образом выровненный tableDirectory будет иметь теги для каждой таблицы как последние 4 байта строки.Но, как вы можете видеть, у вас есть некоторое смещение ... 'c' (0x63) для 'cmap' находится на один байт слишком далеко вправо, и последующие записи tableDirectory также сдвигаются.Он должен выглядеть примерно так:

00000000: 4f54 544f 0009 0008 0003 0001 4346 4620  OTTO........CFF 
00000010: ???? ???? ???? ???? ???? ???? 636d 6170  ............cmap
00000020: ???? ???? ???? ???? ???? ???? 6865 6164  ............head
00000030: ???? ???? ???? ???? ???? ???? 6868 6561  ............hhea
[...]

Так что похоже на некоторые ваших записей tableDirectory, в конце добавляется дополнительный байт.Поэтому вам нужно выполнить резервное копирование и проверить этот код, чтобы он сначала работал правильно, а затем позаботиться о searchRange, rangeShift и entrySelector (который, если ваш шрифт содержит 9 таблиц, как объявлено, должен быть: 0080 0003 0010 (hex)).

...