aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/fonttools/fontTools/ttLib/tables/_s_b_i_x.py
blob: a282ea9a60d1a1e5f58747db6079d7c493504295 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from fontTools.misc import sstruct
from fontTools.misc.textTools import safeEval, num2binary, binary2num
from . import DefaultTable
from .sbixStrike import Strike


sbixHeaderFormat = """
	>
	version:       H	# Version number (set to 1)
	flags:         H	# The only two bits used in the flags field are bits 0
						# and 1. For historical reasons, bit 0 must always be 1.
						# Bit 1 is a sbixDrawOutlines flag and is interpreted as
						# follows:
						#     0: Draw only 'sbix' bitmaps
						#     1: Draw both 'sbix' bitmaps and outlines, in that
						#        order
	numStrikes:    L	# Number of bitmap strikes to follow
"""
sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat)


sbixStrikeOffsetFormat = """
	>
	strikeOffset:  L	# Offset from begining of table to data for the
						# individual strike
"""
sbixStrikeOffsetFormatSize = sstruct.calcsize(sbixStrikeOffsetFormat)


class table__s_b_i_x(DefaultTable.DefaultTable):
    """Standard Bitmap Graphics table

    The ``sbix`` table stores bitmap image data in standard graphics formats
    like JPEG, PNG, or TIFF. The glyphs for which the ``sbix`` table provides
    data are indexed by Glyph ID. For each such glyph, the ``sbix`` table can
    hold different data for different sizes, called "strikes."

    See also https://learn.microsoft.com/en-us/typography/opentype/spec/sbix
    """

    def __init__(self, tag=None):
        DefaultTable.DefaultTable.__init__(self, tag)
        self.version = 1
        self.flags = 1
        self.numStrikes = 0
        self.strikes = {}
        self.strikeOffsets = []

    def decompile(self, data, ttFont):
        # read table header
        sstruct.unpack(sbixHeaderFormat, data[:sbixHeaderFormatSize], self)
        # collect offsets to individual strikes in self.strikeOffsets
        for i in range(self.numStrikes):
            current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize
            offset_entry = sbixStrikeOffset()
            sstruct.unpack(
                sbixStrikeOffsetFormat,
                data[current_offset : current_offset + sbixStrikeOffsetFormatSize],
                offset_entry,
            )
            self.strikeOffsets.append(offset_entry.strikeOffset)

        # decompile Strikes
        for i in range(self.numStrikes - 1, -1, -1):
            current_strike = Strike(rawdata=data[self.strikeOffsets[i] :])
            data = data[: self.strikeOffsets[i]]
            current_strike.decompile(ttFont)
            # print "  Strike length: %xh" % len(bitmapSetData)
            # print "Number of Glyph entries:", len(current_strike.glyphs)
            if current_strike.ppem in self.strikes:
                from fontTools import ttLib

                raise ttLib.TTLibError("Pixel 'ppem' must be unique for each Strike")
            self.strikes[current_strike.ppem] = current_strike

        # after the glyph data records have been extracted, we don't need the offsets anymore
        del self.strikeOffsets
        del self.numStrikes

    def compile(self, ttFont):
        sbixData = b""
        self.numStrikes = len(self.strikes)
        sbixHeader = sstruct.pack(sbixHeaderFormat, self)

        # calculate offset to start of first strike
        setOffset = sbixHeaderFormatSize + sbixStrikeOffsetFormatSize * self.numStrikes

        for si in sorted(self.strikes.keys()):
            current_strike = self.strikes[si]
            current_strike.compile(ttFont)
            # append offset to this strike to table header
            current_strike.strikeOffset = setOffset
            sbixHeader += sstruct.pack(sbixStrikeOffsetFormat, current_strike)
            setOffset += len(current_strike.data)
            sbixData += current_strike.data

        return sbixHeader + sbixData

    def toXML(self, xmlWriter, ttFont):
        xmlWriter.simpletag("version", value=self.version)
        xmlWriter.newline()
        xmlWriter.simpletag("flags", value=num2binary(self.flags, 16))
        xmlWriter.newline()
        for i in sorted(self.strikes.keys()):
            self.strikes[i].toXML(xmlWriter, ttFont)

    def fromXML(self, name, attrs, content, ttFont):
        if name == "version":
            setattr(self, name, safeEval(attrs["value"]))
        elif name == "flags":
            setattr(self, name, binary2num(attrs["value"]))
        elif name == "strike":
            current_strike = Strike()
            for element in content:
                if isinstance(element, tuple):
                    name, attrs, content = element
                    current_strike.fromXML(name, attrs, content, ttFont)
            self.strikes[current_strike.ppem] = current_strike
        else:
            from fontTools import ttLib

            raise ttLib.TTLibError("can't handle '%s' element" % name)


# Helper classes


class sbixStrikeOffset(object):
    pass