Switch font render backend

This commit is contained in:
夜坂雅 2022-09-08 10:33:13 +08:00
parent 71b069c7f7
commit 187e150c85
3 changed files with 62 additions and 25 deletions

Binary file not shown.

View file

@ -212,7 +212,7 @@ async def send_quote_image(
image = Image(file=bytesio)
else:
image = Image(width=64, height=64, background="#FFFF00")
quote_image = make_quote_image(sender_name, body, image)
quote_image = await make_quote_image(sender_name, body, image)
await send_sticker_image(client, room.room_id, quote_image, reply_to)
else:
@ -270,7 +270,7 @@ async def send_sticker_image(
image.save(file=bytesio)
length = bytesio.getbuffer().nbytes
bytesio.seek(0)
logger.debug(f'Sending Image with length {length}, width={width}, height={height}')
logger.debug(f"Sending Image with length {length}, width={width}, height={height}")
resp, maybe_keys = await client.upload(
bytesio,

View file

@ -1,28 +1,37 @@
import logging
import os.path
from asyncio import create_subprocess_exec
from asyncio.subprocess import PIPE
from html import escape
from tempfile import mkstemp
from wand.drawing import Drawing
from wand.image import Image
from wand.color import Color
import os.path
import nyx_bot
logger = logging.getLogger(__name__)
TEXTBOX_PADDING_PIX = 8
TEXTBOX_INNER_MARGIN = 4
TEXTBOX_INNER_MARGIN = 2
AVATAR_SIZE = 48
AVATAR_RIGHT_PADDING = 6
BORDER_MARGIN = 8
MIN_TEXTBOX_WIDTH = 256
FONT_FILE = os.path.join(nyx_bot.__path__[0], "DroidSansFallback.ttf")
MASK_FILE = os.path.join(nyx_bot.__path__[0], "mask.png")
def make_quote_image(sender: str, text: str, avatar: Image):
PANGO_MARKUP_TEMPLATE = """\
<span size="larger" foreground="orange" weight="bold">{}</span>
{}
"""
async def make_quote_image(sender: str, text: str, avatar: Image):
draw = Drawing()
draw.font = FONT_FILE
draw.font_size = 15
with Image(width=2000, height=2000) as i:
bbox = draw.get_font_metrics(i, text, True)
sender_bbox = draw.get_font_metrics(i, sender, False)
text_width = max(bbox.text_width, sender_bbox.text_width)
textbox_height = (TEXTBOX_PADDING_PIX * 2) + bbox.text_height + sender_bbox.text_height + TEXTBOX_INNER_MARGIN
imagefile = await render_text(PANGO_MARKUP_TEMPLATE.format(sender, escape(text)))
image = Image(filename=imagefile)
text_width = image.width
text_height = image.height
textbox_height = (TEXTBOX_PADDING_PIX * 2) + text_height + TEXTBOX_INNER_MARGIN - 8
# Original textbox width
textbox_width_orig = (TEXTBOX_PADDING_PIX * 2) + text_width
# Final textbox width
@ -41,21 +50,49 @@ def make_quote_image(sender: str, text: str, avatar: Image):
img.resize(AVATAR_SIZE, AVATAR_SIZE)
img.alpha_channel = True
img.composite_channel("default", mask, "copy_alpha", 0, 0)
draw.composite("overlay", BORDER_MARGIN, BORDER_MARGIN, AVATAR_SIZE, AVATAR_SIZE, img)
draw.composite(
"overlay", BORDER_MARGIN, BORDER_MARGIN, AVATAR_SIZE, AVATAR_SIZE, img
)
# Make image
draw.fill_color = "#111111"
draw.fill_color = "#000000"
draw.stroke_width = 0
draw.rectangle(textbox_x, textbox_y, width=textbox_width, height=textbox_height, radius=8)
draw.rectangle(
textbox_x, textbox_y, width=textbox_width, height=textbox_height, radius=8
)
# Draw text
draw.fill_color = "#FFFFFF"
name_x = textbox_x + TEXTBOX_PADDING_PIX
name_y = textbox_y + TEXTBOX_PADDING_PIX + 14
draw.text(int(name_x), int(name_y), sender)
text_x = name_x
text_y = name_y + TEXTBOX_INNER_MARGIN + sender_bbox.text_height
draw.text(int(text_x), int(text_y), text)
text_x = textbox_x + TEXTBOX_PADDING_PIX
text_y = textbox_y + TEXTBOX_PADDING_PIX - 4
with image:
draw.composite("src_over", text_x, text_y, text_width, text_height, image)
ret = Image(width=int(width), height=int(height))
draw(ret)
return ret
async def render_text(text: str) -> str:
_, path = mkstemp(".png")
logger.debug(f"File path: {path}")
proc = await create_subprocess_exec(
"pango-view",
"--background=black",
"--foreground=white",
"--font=Noto Sans CJK SC 16",
"--antialias=gray",
"--margin=0",
"--hinting=full",
"--subpixel-order=bgr",
"--markup",
"-q",
"-o",
path,
f"--text={text}",
stdin=PIPE,
)
stdout, stderr = await proc.communicate(input=text.encode("utf-8"))
if stdout:
print(f"[stdout]\n{stdout}")
if stderr:
print(f"[stderr]\n{stderr}")
return path