Example #1
0
def handwrite2(text: str,
               template2: Mapping[str, Any],
               *,
               worker: Optional[int] = None,
               seed: Hashable = None) -> List[PIL.Image.Image]:
    """The 'periodic' version of handwrite. See also handwrite().
    The parameters of handwrite2() and handwrite() are similar. The difference
    is that some of the parameters in the template of handwrite() are replaced
    with their plural form in template2. These 'plural' parameters become a
    sequence of the corresponding original parameters. And these 'plural'
    parameters in template2 will be use periodically in the sequence of
    handwritten images.

    The original parameters and their corresponding 'plural' parameters as well
    as their default values, if any, are listed below.
    background -> backgrounds
    margin -> margins
    line_spacing -> line_spacings
    font_size -> font_sizes
    word_spacing -> word_spacings (Default: a list of 0)
    line_spacing_sigma -> line_spacing_sigmas (Default: [i / 32 for i in font_sizes])
    font_size_sigma -> font_size_sigmas (Default: [i / 64 for i in font_sizes])
    word_spacing_sigma -> word_spacing_sigmas (Default: [i / 32 for i in font_sizes])
    perturb_x_sigma -> perturb_x_sigmas (Default: [i / 32 for i in font_sizes])
    perturb_y_sigma -> perturb_y_sigmas (Default: [i / 32 for i in font_sizes])
    perturb_theta_sigma -> perturb_theta_sigmas (Default: a list of 0.07)

    Note that, all of these 'plural' parameters must have the same length.

    Example:
    >>> from PIL import Image, ImageFont
    >>> from pylf import handwrite2
    >>>
    >>>
    >>> if __name__ == '__main__':
    >>>     template2 = {
    >>>         "backgrounds": [
    >>>             Image.new(mode="1", size=(2000, 2000), color="white"),
    >>>             Image.new(mode="RGB", size=(1000, 3000), color="green")
    >>>         ],
    >>>         "margins": [
    >>>             {"left": 150, "right": 150, "top": 200, "bottom": 200},
    >>>             {"left": 100, "right": 100, "top": 300, "bottom": 300}
    >>>         ],
    >>>         "line_spacings": [150, 200],
    >>>         "font_sizes": [100, 90],
    >>>         "font": ImageFont.truetype("path/to/my/font.ttf")
    >>>     }
    >>>     for image in handwrite2("我能吞下玻璃而不伤身体。" * 30, template2):
    >>>         image.show()
    >>>
    """
    if _CHECK_PARAMETERS:
        _check_params.check_params(text, template2, worker, seed)

    font_sizes = template2["font_sizes"]

    word_spacings = template2.get(
        "word_spacings", tuple(_DEFAULT_WORD_SPACING for _ in font_sizes))

    line_spacing_sigmas = template2.get("line_spacing_sigmas",
                                        tuple(i / 32 for i in font_sizes))
    font_size_sigmas = template2.get("font_size_sigmas",
                                     tuple(i / 64 for i in font_sizes))
    word_spacing_sigmas = template2.get("word_spacing_sigmas",
                                        tuple(i / 32 for i in font_sizes))

    color = template2.get("color", _DEFAULT_COLOR)

    is_half_char_fn = template2.get(
        "is_half_char_fn",
        lambda c: c in DEFAULT_HALF_CHARS,
    )
    is_end_char_fn = template2.get(
        "is_end_char_fn",
        lambda c: c in DEFAULT_END_CHARS,
    )

    perturb_x_sigmas = template2.get("perturb_x_sigmas",
                                     tuple(i / 32 for i in font_sizes))
    perturb_y_sigmas = template2.get("perturb_y_sigmas",
                                     tuple(i / 32 for i in font_sizes))
    perturb_theta_sigmas = template2.get(
        "perturb_theta_sigmas",
        tuple(_DEFAULT_PERTURB_THETA_SIGMA for _ in font_sizes))

    if worker is None:
        worker = multiprocessing.cpu_count()

    return _core.handwrite(
        text=text,
        # If template2["backgrounds"] is already a tuple, CPython will share it
        # instead of creating a new copy of it.
        backgrounds=tuple(template2["backgrounds"]),
        top_margins=tuple(m["top"] for m in template2["margins"]),
        bottom_margins=tuple(m["bottom"] for m in template2["margins"]),
        left_margins=tuple(m["left"] for m in template2["margins"]),
        right_margins=tuple(m["right"] for m in template2["margins"]),
        line_spacings=tuple(template2["line_spacings"]),
        font_sizes=tuple(font_sizes),
        word_spacings=tuple(word_spacings),
        line_spacing_sigmas=tuple(line_spacing_sigmas),
        font_size_sigmas=tuple(font_size_sigmas),
        word_spacing_sigmas=tuple(word_spacing_sigmas),
        font=template2["font"],
        color=color,
        is_half_char_fn=is_half_char_fn,
        is_end_char_fn=is_end_char_fn,
        perturb_x_sigmas=tuple(perturb_x_sigmas),
        perturb_y_sigmas=tuple(perturb_y_sigmas),
        perturb_theta_sigmas=tuple(perturb_theta_sigmas),
        worker=worker,
        seed=seed,
    )
Example #2
0
def handwrite2(text,
               template2: dict,
               anti_aliasing: bool = True,
               worker: int = 0,
               seed: int = None) -> list:
    """The 'periodic' version of handwrite. See also handwrite.

    Args:
        text: A char iterable.
        template2: A dict containing following parameters.
            page_settings: A list of dict containing the following parameters. Each of these dict will be applied
                cyclically to each page.
                background: A Pillow's Image instance.
                box: A bounding box as a 4-tuple defining the left, upper, right and lower pixel coordinate. The module
                    uses a Cartesian pixel coordinate system, with (0,0) in the upper left corner. This function do not
                    guarantee the drawn texts will completely in the box.
                font_size: A int as the average font size in pixel. Note that (box[3] - box[1]) and (box[2] - box[0])
                    both must be greater than font_size.
                word_spacing: A int as the average gap between two adjacent chars in pixel. Default: 0.
                line_spacing: A int as the average gap between two adjacent lines in pixel. Default: font_size // 5.
                font_size_sigma: A float as the sigma of the gauss distribution of the font size. Default:
                    font_size / 256.
                word_spacing_sigma: A float as the sigma of the gauss distribution of the word spacing. Default:
                    font_size / 256.
                line_spacing_sigma: A float as the sigma of the gauss distribution of the line spacing. Default:
                    font_size / 256.
            font: A Pillow's font instance. Note that this function do not use the size attribute of the font object.
            color: A str with specific format. The format is given as 'rgb(red, green, blue)' where the color values are
                integers in the range 0 (inclusive) to 255 (inclusive). Default: 'rgb(0, 0, 0)'.
            is_half_char: A function judging whether or not a char only take up half of its original width. The function
                must take a char parameter and return a boolean value. Default: (lambda c: False).
            is_end_char: A function judging whether or not a char can NOT be in the beginning of the lines (e.g. ',',
                '。', '》', ')', ']'). The function must take a char parameter and return a boolean value. Default:
                (lambda c: c in _DEFAULT_END_CHARS).
            alpha: A tuple of two floats as the degree of the distortion in the horizontal and vertical direction in
                order. Both values must be between 0.0 (inclusive) and 1.0 (inclusive). Default: (0.1, 0.1).
        anti_aliasing: Whether or not turn on the anti-aliasing. Default: True.
        worker: A int as the number of worker. if worker is less than or equal to 0, the actual amount of worker would
            be the number of CPU in the computer adding worker. Default: 0.
        seed: A int as the seed of the internal random generators. Default: None.

    Returns:
        A list of drawn images with the same size and mode as the corresponding background images.

    Raises:
        ValueError: When the parameters are not be set properly.
    """
    page_settings = template2['page_settings']
    for page_setting in page_settings:
        font_size = page_setting['font_size']
        page_setting.setdefault('word_spacing', 0)
        page_setting.setdefault('line_spacing', font_size // 5)
        page_setting.setdefault('font_size_sigma', font_size / 256)
        page_setting.setdefault('word_spacing_sigma', font_size / 256)
        page_setting.setdefault('line_spacing_sigma', font_size / 256)

    return _core.handwrite(
        text=text,
        page_settings=page_settings,
        font=template2['font'],
        color=template2.get('color', 'rgb(0, 0, 0)'),
        is_half_char=template2.get('is_half_char', lambda c: False),
        is_end_char=template2.get('is_end_char',
                                  lambda c: c in _DEFAULT_END_CHARS),
        alpha=template2.get('alpha', (0.1, 0.1)),
        anti_aliasing=anti_aliasing,
        worker=worker if worker > 0 else multiprocessing.cpu_count() + worker,
        seed=seed)