diff --git a/cbdt2sbix.py b/cbdt2sbix.py new file mode 100755 index 000000000..fee84eb83 --- /dev/null +++ b/cbdt2sbix.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# Copyright 2021 Google, Inc. All Rights Reserved. +# +# Licensed 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. +# +# Google Author(s): Rod Sheeter + +import argparse +import contextlib +from fontTools import ttLib +from fontTools.pens.ttGlyphPen import TTGlyphPen +from fontTools.ttLib.tables import sbixStrike +from fontTools.ttLib.tables import sbixGlyph +from nototools import tool_utils + +# https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt#glyph-bitmap-data-formats +_CBDT_FORMAT_SMALL_METRIC_PNG = 17 + +def _del_table(font, tag): + if tag in font: + del font[tag] + +def _make_sbix(cblc, cbdt): + # Ref https://gist.github.com/anthrotype/8c08eb372df2fb5da311887b32c2b9ac + sbix = ttLib.newTable("sbix") + + # Apple Emoji uses this + resolution = 72 + + # Noto CBLC will tell you 109 ppem but that makes the sbix assets seem too big + ppem = 128 + sbix_strike = sbixStrike.Strike(ppem=ppem, resolution=resolution) + sbix.strikes[sbix_strike.ppem] = sbix_strike + + for strike in cbdt.strikeData: + for glyph_name, cbdt_bitmap in strike.items(): + cbdt_bitmap.decompile() # populate .metrics, .imageData + + assert cbdt_bitmap.getFormat() in {_CBDT_FORMAT_SMALL_METRIC_PNG} # only format for now + + sbix_strike.glyphs[glyph_name] = sbixGlyph.Glyph( + glyphName=glyph_name, + graphicType="png", + imageData=cbdt_bitmap.imageData, + # Apple Color Emoji seem to always be 0 + # but then our glyphs are too high + originOffsetY=-20, + #originOffsetX=cbdt_bitmap.metrics.BearingX, + #originOffsetY=cbdt_bitmap.metrics.BearingY, + ) + + return sbix + + +def _add_empty_glyf_glyphs(font): + pen = TTGlyphPen(None) + empty_glyph = pen.glyph() + font['loca'] = ttLib.newTable("loca") + font['glyf'] = glyf_table = ttLib.newTable("glyf") + glyf_table.glyphOrder = font.getGlyphOrder() + glyf_table.glyphs = {g: empty_glyph for g in glyf_table.glyphOrder} + + +def main(): + parser = argparse.ArgumentParser( + description="Creates an SBIX (Apple style) bitmap font from a CBDT (Google style) bitmap font.") + parser.add_argument( + '-i', '--in_file', help='Input file', default="fonts/NotoColorEmoji.ttf") + parser.add_argument( + '-o', '--out_file', help='Output file', default="fonts/NotoColorEmoji_AppleCompatible.ttf") + args = parser.parse_args() + + with contextlib.closing(ttLib.TTFont(args.in_file)) as font: + font["sbix"] = _make_sbix(font["CBLC"], font["CBDT"]) + + _add_empty_glyf_glyphs(font) + + _del_table(font, "CBDT") + _del_table(font, "CBLC") + + print(f"Writing {args.out_file}...") + font.save(args.out_file) + +if __name__ == '__main__': + main() \ No newline at end of file