styled-prose

GitHub Workflow Status PyPI - Downloads GitHub

Generate images and thumbnails based on bitmap transformations of rendered prose.

Documentation: https://styledprose.thearchitector.dev.

Tested support on Python 3.8, 3.9, 3.10, 3.11, and 3.12.

$ pdm add styled-prose
# or
$ pip install --user styled-prose

Example

The following stylesheet is a super simple example that overrides the default style's font size and family.

# stylesheet.toml

[[fonts]]
font_name = "EB Garamond"
from_google_fonts = true

[[styles]]
name = "default"
font_size = 14
font_name = "EB Garamond"

Using that stylesheet, and some basic prose, you can generate an image. The requested font family EB Garamond and its license are downloaded from Google Fonts and cached automatically; subsequent generations use those cached fonts.

from PIL import Image
from styled_prose import StyledProseGenerator

text: str = """
This is normal.

<i>This is italicized.</i>

<b>This is bold.</b>

<i><b>This is bold and italicized.</b></i>

<u>This is underlined.</u>

<strike>This is struck from the record.</strike>
"""
random.seed(771999)

generator: StyledProseGenerator = StyledProseGenerator("stylesheet.toml")
img: Image.Image = generator.create_jpg(
    text,
    angle=-2.5, # optional; an angle by which to rotate the image
    thumbnail=(210, 210), # optional; the dimensions of a random thumbnail
)

img.save("prose.jpg", quality=95)

This above code produces the following image:

example rendering

class ParagraphStyle(pydantic.main.BaseModel):

Every property within this class changes the formatting and subsequent rendering of any prose using the style.

For example, the following changes the default font size to 14 and the font family to "EB Garamond". To register custom fonts, like "EB Garamond", see FontFamily.

[[styles]]
name = "default"
font_size = 14
font_name = "EB Garamond"

Multiple styles are supported through multiple [[styles]] definitions.

name: str

The name of the style. It must be unique, and can be referenced from StyledProseGenerator.create_jpg.

font_name: str

The font family this style should use to render prose. "Times" (the default), "Helvetica" / "Arial", and "Courier" are bundeled and available. You can supply your own fonts via the [[fonts]] section of your stylesheet; see FontFamily.

font_size: int

The font size. It is 12pt by default.

font_color: str

The color of your prose in hexademical format ("#RRGGBB"). By default, this is black ("#000000").

line_height: Optional[int]

The desired line height. This value should be provided in absolute font size points; by default, it will be 115% of the provided font size (single spaced).

alignment: Literal['left', 'center', 'right', 'justify']

The justification of rendered prose. By default, all text will be left-justified. It can be any one of "left", "center", "right", or "justify".

text_direction: Optional[Literal['cjk', 'ltr', 'rtl']]

Controls the text direction. By default it is "ltr" (left to right), but can also be "rtl" (right to left) and "cjk" (Chinese, Japanese, or Korean).

split_long_words: bool

Dictates if long words can be split in order to more compactly wrap text. By default, long words will begin a new line instead of being split.

allow_widows: bool

Determines if widows are allowed; a widow is a line of text carried over to a new page because it doesn't fit on the previous.

https://en.wikipedia.org/wiki/Widows_and_orphans

allow_orphans: bool

Determines if orphans are allowed; an orphan is the last word of a sentence that is too long to fit on the same line. If this docstring were to extend the entire width of this paragraph, the last word would be an
orphan.

https://en.wikipedia.org/wiki/Widows_and_orphans

class StyledProseGenerator:

A styled prose generator, configured using the provided configuration stylesheet. Font and style validation and registration happens during initialization; as such, if using this library as a part of an application, it is recommended to create a single instance of this class during startup.

def create_jpg( self, prose: str, style: str = 'default', angle: float = 0, thumbnail: Optional[Tuple[int, int]] = None, prescale_thumbnail: bool = True, comparative_font_size: float = 6.0) -> PIL.Image.Image:

Converts the provided prose into an stylized image.

If provided a style, that style is used when configuring and producing the rendered prose.

If an angle is provided, that angle is applied to the stylized prose rendering.

If thumbnail dimensions are provided, the rendering is cropped after the previous steps.

The prescale_thumbnail and comparative_font_size parameters control the thumbnail cropping behavior; if enabled, to aesthetically accommodate various font sizes, a scaled initial thumbnail area is captured as to match the density of text in the same area if the prose were rendered using the provided comparative_font_size. The defaults produce a thumbnail with a text density similar to 6pt EB Garamond text inside a 210x210 square. The intermediate thumbnail is always scaled to the requested thumbnail dimensions using the Lanczos algorithm before being returned.

class BadConfigException(builtins.ValueError):

Raised when an invalid config, likely an invalid TOML, is read.

class BadStyleException(builtins.ValueError):

Raised when an invalid paragraph style is encountered during validation.

class BadFontException(builtins.ValueError):

Raised when trying to parse an invalid font family is encountered during validation.