Почему операции CharString усекаются при просмотре шрифта OpenType / CFF2 через FontTools - PullRequest
0 голосов
/ 22 января 2019

Я начинаю с этой структуры данных, содержащей мои операции CharStrings (поэтому в основном эти 3 элемента в массиве JSON образуют 3 символа шрифта):

[
  {
    "name": "a",
    "type": "CHARSTRING",
    "value": [
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 10
          },
          "dy": {
            "type": "NUMBER",
            "value": 160
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": -20
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 80
          },
          "dy": {
            "type": "NUMBER",
            "value": 20
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": -80
          },
          "dy": {
            "type": "NUMBER",
            "value": 0
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 80
          },
          "dy": {
            "type": "NUMBER",
            "value": 0
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": -80
          },
          "dy": {
            "type": "NUMBER",
            "value": -20
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": 60
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 80
          },
          "dy": {
            "type": "NUMBER",
            "value": -60
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": 60
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      }
    ]
  },
  {
    "name": "b",
    "type": "CHARSTRING",
    "value": [
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 10
          },
          "dy": {
            "type": "NUMBER",
            "value": 20
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": 180
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": -100
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 30
          },
          "dy": {
            "type": "NUMBER",
            "value": 0
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": -30
          },
          "dy": {
            "type": "NUMBER",
            "value": 100
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      }
    ]
  },
  {
    "name": "d",
    "type": "CHARSTRING",
    "value": [
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 90
          },
          "dy": {
            "type": "NUMBER",
            "value": 20
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": 180
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 0
          },
          "dy": {
            "type": "NUMBER",
            "value": -100
          },
          "name": {
            "type": "OP",
            "value": 5
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": -30
          },
          "dy": {
            "type": "NUMBER",
            "value": 0
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      },
      {
        "name": "CharString Op",
        "fields": {
          "dx": {
            "type": "NUMBER",
            "value": 30
          },
          "dy": {
            "type": "NUMBER",
            "value": 100
          },
          "name": {
            "type": "OP",
            "value": 21
          }
        }
      }
    ]
  }
]

и в конечном итоге это из ttx Regular.otf:

<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="OTTO" ttLibVersion="3.36">

  <GlyphOrder>
    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
    <GlyphID id="0" name=".notdef"/>
    <GlyphID id="1" name="b"/>
    <GlyphID id="2" name="d"/>
  </GlyphOrder>

  <head>
    <!-- Most of this table will be recalculated by the compiler -->
    <tableVersion value="1.0"/>
    <fontRevision value="0.0"/>
    <checkSumAdjustment value="0x0"/>
    <magicNumber value="0x5f0f3cf5"/>
    <flags value="00000000 00000011"/>
    <unitsPerEm value="1000"/>
    <created value="Tue Jan 22 09:38:57 2019"/>
    <modified value="Tue Jan 22 09:38:57 2019"/>
    <xMin value="0"/>
    <yMin value="0"/>
    <xMax value="90"/>
    <yMax value="0"/>
    <macStyle value="00000000 00000000"/>
    <lowestRecPPEM value="3"/>
    <fontDirectionHint value="2"/>
    <indexToLocFormat value="0"/>
    <glyphDataFormat value="0"/>
  </head>

  <hhea>
    <tableVersion value="0x00010000"/>
    <ascent value="200"/>
    <descent value="100"/>
    <lineGap value="0"/>
    <advanceWidthMax value="90"/>
    <minLeftSideBearing value="0"/>
    <minRightSideBearing value="0"/>
    <xMaxExtent value="0"/>
    <caretSlopeRise value="1"/>
    <caretSlopeRun value="0"/>
    <caretOffset value="0"/>
    <reserved0 value="0"/>
    <reserved1 value="0"/>
    <reserved2 value="0"/>
    <reserved3 value="0"/>
    <metricDataFormat value="0"/>
    <numberOfHMetrics value="3"/>
  </hhea>

  <maxp>
    <!-- Most of this table will be recalculated by the compiler -->
    <tableVersion value="0x10000"/>
    <numGlyphs value="3"/>
    <maxPoints value="5"/>
    <maxContours value="1"/>
    <maxCompositePoints value="0"/>
    <maxCompositeContours value="0"/>
    <maxZones value="1"/>
    <maxTwilightPoints value="0"/>
    <maxStorage value="0"/>
    <maxFunctionDefs value="0"/>
    <maxInstructionDefs value="0"/>
    <maxStackElements value="0"/>
    <maxSizeOfInstructions value="0"/>
    <maxComponentElements value="0"/>
    <maxComponentDepth value="0"/>
  </maxp>

  <OS_2>
    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
         will be recalculated by the compiler -->
    <version value="5"/>
    <xAvgCharWidth value="90"/>
    <usWeightClass value="500"/>
    <usWidthClass value="5"/>
    <fsType value="00000000 00000000"/>
    <ySubscriptXSize value="650"/>
    <ySubscriptYSize value="699"/>
    <ySubscriptXOffset value="0"/>
    <ySubscriptYOffset value="140"/>
    <ySuperscriptXSize value="650"/>
    <ySuperscriptYSize value="699"/>
    <ySuperscriptXOffset value="0"/>
    <ySuperscriptYOffset value="479"/>
    <yStrikeoutSize value="49"/>
    <yStrikeoutPosition value="258"/>
    <sFamilyClass value="0"/>
    <panose>
      <bFamilyType value="0"/>
      <bSerifStyle value="0"/>
      <bWeight value="0"/>
      <bProportion value="0"/>
      <bContrast value="0"/>
      <bStrokeVariation value="0"/>
      <bArmStyle value="0"/>
      <bLetterForm value="0"/>
      <bMidline value="0"/>
      <bXHeight value="0"/>
    </panose>
    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
    <achVendID value="XXXX"/>
    <fsSelection value="00000000 01000000"/>
    <usFirstCharIndex value="97"/>
    <usLastCharIndex value="100"/>
    <sTypoAscender value="200"/>
    <sTypoDescender value="100"/>
    <sTypoLineGap value="0"/>
    <usWinAscent value="0"/>
    <usWinDescent value="0"/>
    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
    <sxHeight value="100"/>
    <sCapHeight value="40"/>
    <usDefaultChar value="0"/>
    <usBreakChar value="0"/>
    <usMaxContext value="0"/>
    <usLowerOpticalPointSize value="0.0"/>
    <usUpperOpticalPointSize value="0.15"/>
  </OS_2>

  <hmtx>
    <mtx name=".notdef" width="90" lsb="0"/>
    <mtx name="b" width="90" lsb="0"/>
    <mtx name="d" width="90" lsb="0"/>
  </hmtx>

  <cmap>
    <tableVersion version="0"/>
    <cmap_format_4 platformID="3" platEncID="1" language="0">
      <map code="0x62" name="b"/><!-- LATIN SMALL LETTER B -->
      <map code="0x64" name="d"/><!-- LATIN SMALL LETTER D -->
    </cmap_format_4>
  </cmap>

  <name>
    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Foo
    </namerecord>
    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Foo
    </namerecord>
    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Regular
    </namerecord>
    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
      foo
    </namerecord>
    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Foo Regular
    </namerecord>
    <namerecord nameID="13" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Licensed under the Apache License, Version 2.0
    </namerecord>
    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
      Version 1.000
    </namerecord>
  </name>

  <post>
    <formatType value="3.0"/>
    <italicAngle value="0.0"/>
    <underlinePosition value="0"/>
    <underlineThickness value="0"/>
    <isFixedPitch value="0"/>
    <minMemType42 value="0"/>
    <maxMemType42 value="0"/>
    <minMemType1 value="0"/>
    <maxMemType1 value="0"/>
  </post>

  <CFF2>
    <major value="2"/>
    <minor value="0"/>
    <CFFFont name="CFF2Font">
      <FontMatrix value="0.001 0.0 0.0 0.001 0.0 0.0"/>
      <FDArray>
        <FontDict index="0">
          <Private>
            <BlueScale value="0.039625"/>
            <BlueShift value="7"/>
            <BlueFuzz value="1"/>
          </Private>
        </FontDict>
      </FDArray>
      <CharStrings>
        <CharString name=".notdef">
          10</CharString>
        <CharString name="b">
          10 20 rlineto
          0</CharString>
        <CharString name="d">
          90 20 rlineto
          0</CharString>
      </CharStrings>
    </CFFFont>

    <GlobalSubrs>
      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
    </GlobalSubrs>
  </CFF2>

</ttFont>

Если я изменю все в CharStrings на 0 (все значения dx и dy и т. Д., А не операторы), это приведет к:

...

  <CFF2>
    <major value="2"/>
    <minor value="0"/>
    <CFFFont name="CFF2Font">
      <FontMatrix value="0.001 0.0 0.0 0.001 0.0 0.0"/>
      <FDArray>
        <FontDict index="0">
          <Private>
            <BlueScale value="0.039625"/>
            <BlueShift value="7"/>
            <BlueFuzz value="1"/>
          </Private>
        </FontDict>
      </FDArray>
      <CharStrings>
        <CharString name=".notdef">
          0 0 rlineto
          0 0 rmoveto
          0 0 rlineto
          0 0 rlineto
          0 0 rmoveto
          0 0 rlineto
          0 0 rmoveto
          0 0 rlineto
          0 0 rmoveto
        </CharString>
        <CharString name="b">
          0 0 rlineto
          0 0 rmoveto
          0 0 rlineto
          0 0 rmoveto
          0 0 rmoveto
        </CharString>
        <CharString name="d">
          0 0 rlineto
          0 0 rmoveto
          0 0 rlineto
          0 0 rmoveto
          0 0 rmoveto
        </CharString>
      </CharStrings>
    </CFFFont>

    <GlobalSubrs>
      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
    </GlobalSubrs>
  </CFF2>

</ttFont>

Это коды операций для JSON в начале:

var charStringCodes = {
  rlineto: 5,
  rmoveto : 21
}

В основном мой вопрос, почему вывод такой странный. Я еще не заставил шрифт работать, только ttx / fonttools настолько близко подошли к отладке. Но я пока не понимаю, почему при использовании регулярных входных данных для точек кривой это практически не дает выходных данных, а замена их на 0 приводит к почти полному выходному сигналу.

...