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, )
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)