Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
FontFile.py160 linesDownload Raw Back to PIL
1#
2# The Python Imaging Library
3# $Id$
4#
5# base class for raster font file parsers
6#
7# history:
8# 1997-06-05 fl   created
9# 1997-08-19 fl   restrict image width
10#
11# Copyright (c) 1997-1998 by Secret Labs AB
12# Copyright (c) 1997-1998 by Fredrik Lundh
13#
14# See the README file for information on usage and redistribution.
15#
16from __future__ import annotations
17
18import os
19from typing import BinaryIO
20
21from . import Image, ImageFont, _binary
22
23WIDTH = 800
24
25
26def puti16(
27    fp: BinaryIO, values: tuple[int, int, int, int, int, int, int, int, int, int]
28) -> None:
29    """Write network order (big-endian) 16-bit sequence"""
30    for v in values:
31        if v < 0:
32            v += 65536
33        fp.write(_binary.o16be(v))
34
35
36class FontFile:
37    """Base class for raster font file handlers."""
38
39    bitmap: Image.Image | None = None
40
41    def __init__(self) -> None:
42        self.info: dict[bytes, bytes | int] = {}
43        self.glyph: list[
44            tuple[
45                tuple[int, int],
46                tuple[int, int, int, int],
47                tuple[int, int, int, int],
48                Image.Image,
49            ]
50            | None
51        ] = [None] * 256
52
53    def __getitem__(self, ix: int) -> (
54        tuple[
55            tuple[int, int],
56            tuple[int, int, int, int],
57            tuple[int, int, int, int],
58            Image.Image,
59        ]
60        | None
61    ):
62        return self.glyph[ix]
63
64    def compile(self) -> None:
65        """Create metrics and bitmap"""
66
67        if self.bitmap:
68            return
69
70        # create bitmap large enough to hold all data
71        h = w = maxwidth = 0
72        lines = 1
73        for glyph in self.glyph:
74            if glyph:
75                d, dst, src, im = glyph
76                h = max(h, src[3] - src[1])
77                w = w + (src[2] - src[0])
78                if w > WIDTH:
79                    lines += 1
80                    w = src[2] - src[0]
81                maxwidth = max(maxwidth, w)
82
83        xsize = maxwidth
84        ysize = lines * h
85
86        if xsize == 0 and ysize == 0:
87            return
88
89        self.ysize = h
90
91        # paste glyphs into bitmap
92        self.bitmap = Image.new("1", (xsize, ysize))
93        self.metrics: list[
94            tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]]
95            | None
96        ] = [None] * 256
97        x = y = 0
98        for i in range(256):
99            glyph = self[i]
100            if glyph:
101                d, dst, src, im = glyph
102                xx = src[2] - src[0]
103                x0, y0 = x, y
104                x = x + xx
105                if x > WIDTH:
106                    x, y = 0, y + h
107                    x0, y0 = x, y
108                    x = xx
109                s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
110                self.bitmap.paste(im.crop(src), s)
111                self.metrics[i] = d, dst, s
112
113    def _encode_metrics(self) -> bytes:
114        values: list[int] = []
115        for i in range(256):
116            m = self.metrics[i]
117            if m:
118                values.extend(m[0] + m[1] + m[2])
119            else:
120                values.extend((0,) * 10)
121
122        data = bytearray()
123        for v in values:
124            if v < 0:
125                v += 65536
126            data += _binary.o16be(v)
127        return bytes(data)
128
129    def save(self, filename: str) -> None:
130        """Save font"""
131
132        self.compile()
133
134        # font data
135        if not self.bitmap:
136            msg = "No bitmap created"
137            raise ValueError(msg)
138        self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
139
140        # font metrics
141        with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
142            fp.write(b"PILfont\n")
143            fp.write(f";;;;;;{self.ysize};\n".encode("ascii"))  # HACK!!!
144            fp.write(b"DATA\n")
145            fp.write(self._encode_metrics())
146
147    def to_imagefont(self) -> ImageFont.ImageFont:
148        """Convert to ImageFont"""
149
150        self.compile()
151
152        # font data
153        if not self.bitmap:
154            msg = "No bitmap created"
155            raise ValueError(msg)
156
157        imagefont = ImageFont.ImageFont()
158        imagefont._load(self.bitmap, self._encode_metrics())
159        return imagefont
160 
codekingpro/portable-devtools · Team Ai