CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
FontFile.py135 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, _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 save(self, filename: str) -> None:
114        """Save font"""
115
116        self.compile()
117
118        # font data
119        if not self.bitmap:
120            msg = "No bitmap created"
121            raise ValueError(msg)
122        self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
123
124        # font metrics
125        with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
126            fp.write(b"PILfont\n")
127            fp.write(f";;;;;;{self.ysize};\n".encode("ascii"))  # HACK!!!
128            fp.write(b"DATA\n")
129            for id in range(256):
130                m = self.metrics[id]
131                if not m:
132                    puti16(fp, (0,) * 10)
133                else:
134                    puti16(fp, m[0] + m[1] + m[2])
135 
Aluode/PerceptionLabPortable · CoolFace