Add FontFile.to_imagefont() (#9419)
This commit is contained in:
commit
2c87ce2d3d
@ -75,6 +75,16 @@ def test_draw(request: pytest.FixtureRequest, tmp_path: Path) -> None:
|
||||
assert_image_equal_tofile(im, "Tests/images/test_draw_pbm_target.png")
|
||||
|
||||
|
||||
def test_to_imagefont() -> None:
|
||||
with open(fontname, "rb") as test_file:
|
||||
pcffont = PcfFontFile.PcfFontFile(test_file)
|
||||
imagefont = pcffont.to_imagefont()
|
||||
im = Image.new("L", (130, 30), "white")
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), message, "black", font=imagefont)
|
||||
assert_image_equal_tofile(im, "Tests/images/test_draw_pbm_target.png")
|
||||
|
||||
|
||||
def test_textsize(request: pytest.FixtureRequest, tmp_path: Path) -> None:
|
||||
tempname = save_font(request, tmp_path)
|
||||
font = ImageFont.load(tempname)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@ -7,6 +8,15 @@ import pytest
|
||||
from PIL import FontFile, Image
|
||||
|
||||
|
||||
def test_puti16() -> None:
|
||||
fp = BytesIO()
|
||||
FontFile.puti16(fp, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
|
||||
assert fp.getvalue() == (
|
||||
b"\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04"
|
||||
b"\x00\x05\x00\x06\x00\x07\x00\x08\x00\t"
|
||||
)
|
||||
|
||||
|
||||
def test_compile() -> None:
|
||||
font = FontFile.FontFile()
|
||||
font.glyph[0] = ((0, 0), (0, 0, 0, 0), (0, 0, 0, 1), Image.new("L", (0, 0)))
|
||||
@ -24,5 +34,11 @@ def test_save(tmp_path: Path) -> None:
|
||||
tempname = str(tmp_path / "temp.pil")
|
||||
|
||||
font = FontFile.FontFile()
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="No bitmap created"):
|
||||
font.save(tempname)
|
||||
|
||||
|
||||
def test_to_imagefont() -> None:
|
||||
font = FontFile.FontFile()
|
||||
with pytest.raises(ValueError, match="No bitmap created"):
|
||||
font.to_imagefont()
|
||||
|
||||
@ -8,10 +8,14 @@ The :py:mod:`~PIL.ImageFont` module defines a class with the same name. Instance
|
||||
this class store bitmap fonts, and are used with the
|
||||
:py:meth:`PIL.ImageDraw.ImageDraw.text` method.
|
||||
|
||||
PIL uses its own font file format to store bitmap fonts, limited to 256 characters. You can use
|
||||
`pilfont.py <https://github.com/python-pillow/pillow-scripts/blob/main/Scripts/pilfont.py>`_
|
||||
from :pypi:`pillow-scripts` to convert BDF and
|
||||
PCF font descriptors (X window font formats) to this format.
|
||||
Pillow uses its own font file format to store bitmap fonts, limited to 256 characters. You
|
||||
can use :py:meth:`~PIL.FontFile.FontFile.to_imagefont` to convert BDF and PCF font
|
||||
descriptors (X Window font formats) to this format::
|
||||
|
||||
from PIL import PcfFontFile
|
||||
with open("Tests/fonts/10x20-ISO8859-1.pcf", "rb") as fp:
|
||||
font = PcfFontFile.PcfFontFile(fp)
|
||||
imagefont = font.to_imagefont()
|
||||
|
||||
Starting with version 1.1.4, PIL can be configured to support TrueType and
|
||||
OpenType fonts (as well as other font formats supported by the FreeType
|
||||
|
||||
@ -18,7 +18,7 @@ from __future__ import annotations
|
||||
import os
|
||||
from typing import BinaryIO
|
||||
|
||||
from . import Image, _binary
|
||||
from . import Image, ImageFont, _binary
|
||||
|
||||
WIDTH = 800
|
||||
|
||||
@ -110,6 +110,22 @@ class FontFile:
|
||||
self.bitmap.paste(im.crop(src), s)
|
||||
self.metrics[i] = d, dst, s
|
||||
|
||||
def _encode_metrics(self) -> bytes:
|
||||
values: list[int] = []
|
||||
for i in range(256):
|
||||
m = self.metrics[i]
|
||||
if m:
|
||||
values.extend(m[0] + m[1] + m[2])
|
||||
else:
|
||||
values.extend((0,) * 10)
|
||||
|
||||
data = bytearray()
|
||||
for v in values:
|
||||
if v < 0:
|
||||
v += 65536
|
||||
data += _binary.o16be(v)
|
||||
return bytes(data)
|
||||
|
||||
def save(self, filename: str) -> None:
|
||||
"""Save font"""
|
||||
|
||||
@ -126,9 +142,18 @@ class FontFile:
|
||||
fp.write(b"PILfont\n")
|
||||
fp.write(f";;;;;;{self.ysize};\n".encode("ascii")) # HACK!!!
|
||||
fp.write(b"DATA\n")
|
||||
for id in range(256):
|
||||
m = self.metrics[id]
|
||||
if not m:
|
||||
puti16(fp, (0,) * 10)
|
||||
else:
|
||||
puti16(fp, m[0] + m[1] + m[2])
|
||||
fp.write(self._encode_metrics())
|
||||
|
||||
def to_imagefont(self) -> ImageFont.ImageFont:
|
||||
"""Convert to ImageFont"""
|
||||
|
||||
self.compile()
|
||||
|
||||
# font data
|
||||
if not self.bitmap:
|
||||
msg = "No bitmap created"
|
||||
raise ValueError(msg)
|
||||
|
||||
imagefont = ImageFont.ImageFont()
|
||||
imagefont._load(self.bitmap, self._encode_metrics())
|
||||
return imagefont
|
||||
|
||||
@ -149,6 +149,9 @@ class ImageFont:
|
||||
# read PILfont metrics
|
||||
data = file.read(256 * 20)
|
||||
|
||||
self._load(image, data)
|
||||
|
||||
def _load(self, image: Image.Image, data: bytes) -> None:
|
||||
image.load()
|
||||
|
||||
self.font = Image.core.font(image.im, data)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user