# coding: utf-8
from typing import List, Optional, Tuple, Union
import numpy as np
import numpy.typing as npt
from PIL import Image
from ..utils.image_utils import arr2pil, draw_text_in_pil, pil2arr
from .base import BaseElement, FixedElement
[docs]class TextElement(FixedElement):
def __init__(
self,
text: str,
ttfontname: str,
pos_frames: Tuple[int, Optional[int]] = (0, None),
margin: Union[int, List[int]] = 0,
width: Optional[int] = None,
height: Optional[int] = None,
top: Optional[Union[BaseElement, int]] = None,
right: Optional[Union[BaseElement, int]] = None,
left: Optional[Union[BaseElement, int]] = None,
bottom: Optional[Union[BaseElement, int]] = None,
xy: Tuple = (0, 0),
textRGB: Union[str, Tuple] = "black",
fontsize: int = 16,
**kwargs,
):
super().__init__(
pos_frames=pos_frames,
margin=margin,
width=width,
height=height,
top=top,
right=right,
left=left,
bottom=bottom,
**dict(
text=text,
ttfontname=ttfontname,
xy=xy,
textRGB=textRGB,
fontsize=fontsize,
**kwargs,
), # kwargs
**kwargs,
)
self.set_text_attributes(
text=text, ttfontname=ttfontname, fontsize=fontsize, **kwargs
)
[docs] def set_text_attributes(
self,
text: str,
ttfontname: str,
xy: Tuple = (0, 0),
textRGB: Union[str, Tuple] = "black",
fontsize: int = 16,
**kwargs,
):
"""Set attributes for a text element.
Args:
text (str) : Text to be drawn to ``img``.
ttfontname (str) : A filename or file-like object containing a TrueType font.
xy (Tuple, optional) : Where to write the ``text``. This value means the coordinates of (``x``, ``y``). Defaults to ``(0, 0)``.
textRGB (Union[str, Tuple], optional) : The color of text. Defaults to ``"black"``.
fontsize (int, optional) : The font size. Defaults to ``16``.
Examples:
>>> from veditor.utils import SampleData
>>> from veditor.elements import TextElement
>>> element = TextElement(text="PyVideoEditor", ttfontname=SampleData().FONT_POKEFONT_PATH)
>>> attribute_names = ["text", "ttfontname", "xy", "textRGB", "fontsize"]
>>> all([hasattr(element, attr) for attr in attribute_names])
True
"""
self.set_attribute(name="text", value=text)
self.set_attribute(name="ttfontname", value=ttfontname)
self.set_attribute(name="xy", value=xy)
self.set_attribute(name="textRGB", value=textRGB)
self.set_attribute(name="fontsize", value=fontsize)
self.set_attribute(
name="drawKwargs",
value=kwargs,
msg=f"{len(kwargs)} keyword arguments ({', '.join([k for k in kwargs.keys()])}) are set.",
)
[docs] def calc_element_size(
self,
text: str,
ttfontname: str,
fontsize: int = 16,
width: Optional[int] = None,
height: Optional[int] = None,
**kwargs,
) -> Tuple[int, int]:
drawKwargs = dict(text=text, ttfontname=ttfontname, fontsize=fontsize, **kwargs)
if width is None:
drawKwargs.update(dict(img=None, ret_position="word"))
_, (width, _) = draw_text_in_pil(**drawKwargs)
if height is None:
drawKwargs.update(dict(img=None, ret_position="line"))
_, (_, height) = draw_text_in_pil(**drawKwargs)
return (width, height)
[docs] def draw_text(
self, img: Image.Image, text: Optional[str] = None, **kwargs
) -> Image.Image:
"""Draw text in pillow image (``Image.Image``) using :func:`draw_text_in_pil <veditor.utils.image_utils.draw_text_in_pil>`.
Args:
img (Image.Image) : An image to which ``text`` is written.
text (Optional[str], optional) : A text string to write. Defaults to ``None``.
Returns:
Image.Image: ``img`` with ``text`` drawn.
"""
kwargs.update(self.drawKwargs)
return draw_text_in_pil(
text=text or self.text,
ttfontname=self.ttfontname,
img=img,
xy=self.xy,
textRGB=self.textRGB,
fontsize=self.fontsize,
**kwargs,
)
[docs] def edit(
self, frame: npt.NDArray[np.uint8], pos: int, **kwargs
) -> npt.NDArray[np.uint8]:
"""Return ``frame`` as it is.
Args:
frame (npt.NDArray[np.uint8]) : The current frame (BGR image) (in the video)
pos (int) : The current position (in the video)
Returns:
npt.NDArray[np.uint8]: An editied frame.
"""
if self.inCharge(pos):
img = arr2pil(frame)
img, _ = self.draw_text(img)
frame = pil2arr(img)
return frame