1
0
Fork 0
mirror of https://git.lynn.is/Gwen/python-layout.git synced 2024-01-13 01:31:55 +01:00
simple layout engine for images
Go to file
2023-02-08 00:20:38 +01:00
pillow_layout Fixed imports 2023-02-07 23:56:17 +01:00
.gitignore Expanded .gitignore 2023-02-07 23:52:49 +01:00
pyproject.toml Added Lynn to the authors 2023-02-08 00:20:38 +01:00
readme.md clean up 2023-02-04 15:40:41 +01:00
requirements.txt pip dependencies 2023-02-04 21:43:09 +01:00

Example

from layout import Document, Flex, Text, TextAlign, TextVerticalAlign,

FlexAlignContent, FlexDirection, FlexAlignItems, FlexWrap

doc = Document(
    width=800,
    height=400,
    bg_color=(206, 249, 242, 255),
    content=Flex(
        direction=FlexDirection.ROW,
        wrap=FlexWrap.WRAP,
        align_items=FlexAlignItems.STRETCH,
        align_content=FlexAlignContent.STRETCH,
        gap=20,
        padding=20,
        contents=[
            Text(
                text="ITEM 1",
                bg_color=(4, 231, 98, 128),
                width=100,
                flex_grow=1,
                flex_shrink=1,
                text_align=TextAlign.CENTER,
                vertical_text_align=TextVerticalAlign.MIDDLE
            ),
            Text(
                text="ITEM 2",
                bg_color=(34, 49, 39, 128),
                width=300,
                flex_grow=1,
                flex_shrink=1,
                text_align=TextAlign.CENTER,
                vertical_text_align=TextVerticalAlign.MIDDLE
            ),
            Text(
                text="ITEM 3",
                bg_color=(220, 0, 115, 128),
                width=200,
                flex_grow=1,
                flex_shrink=1,
                text_align=TextAlign.CENTER,
                vertical_text_align=TextVerticalAlign.MIDDLE
            ),
            Text(
                text="ITEM 4",
                bg_color=(0, 139, 248, 128),
                width=400,
                flex_grow=1,
                flex_shrink=1,
                text_align=TextAlign.CENTER,
                vertical_text_align=TextVerticalAlign.MIDDLE
            ),
            Text(
                text="ITEM 5",
                bg_color=(71, 0, 99, 128),
                width=250,
                flex_grow=1,
                flex_shrink=1,
                text_align=TextAlign.CENTER,
                vertical_text_align=TextVerticalAlign.MIDDLE
            ),
        ]
    )
)

image = doc.get_image()
image.show()

Layouts

Layout

Base layout class, do not use directly. Provides the following properties:

from layout import Layout

Layout(
    width=None,  # width of the layout element
    height=None,  # height of the layout element
    min_width=None,  # minimum width of the layout element
    min_height=None,  # minimum height of the layout element
    max_width=None,  # maximum width of the layout element
    max_height=None,  # maximum height of the layout element
    fg_color=None,  # foreground color (inherited)
    bg_color=None,  # background color (inherited)
    border_color=None,  # border color (see section Borders)
    border_width=0,  # border width (see section Borders)
    border_radius=0,  # border radius (see section Borders)
    padding=0,  # padding of the layout element
    font=None,  # font for texts (inherited)
    overflow=None,  # allow overflow of layout content
    left=None,  # left absolute position (in children of Container layout)
    top=None,  # top absolute position (in children of Container layout)
    right=None,  # right absolute position (in children of Container layout)
    bottom=None,  # bottom absolute position (in children of Container layout)
    flex_grow=0,  # flex grow proportion (in children of Flex layout)
    flex_shrink=0,  # flex grow proportion (in children of Flex layout)
)

Borders

Borders are painted over the background but below potentially overflowing content. Every border property can be a single value or a tuple (except color) or list of up to four values. Multiple values for border width and color are given in the order (left, top, right, bottom). Multiple values for border radius are given in the order (top-left, top-right, bottom-right, bottom-left). The border color property can only be given as a single value or list of values, not as a tuple, since colors are defined as RGBA-tuples and a tuple value is interpreted as a single color.

Container

Simple layout container with absolute and automatic positioning. Children with any of their left/top/right/bottom properties set to something other than None are positioned absolutely. Other children are positioned automatically.

from layout import Container

Container(
    contents=[],  # child layouts
)

Flex

Flexible layout container roughly based on the CSS flex specification. Children of this layout can use the flex_grow and flex_shrink properties.

from layout import Flex, FlexDirection, FlexWrap, FlexJustify, FlexAlignItems, FlexAlignContent

Flex(
    contents=[],  # child layouts
    direction=FlexDirection.ROW,
    wrap=FlexWrap.NO_WRAP,
    justify=FlexJustify.START,
    align_items=FlexAlignItems.START,
    align_content=FlexAlignContent.START,
    gap=0,  # gap between flex items
)

The properties direction, wrap, justify, align_items, align_content and gap work roughly like their CSS counterparts.

Flex layout arranges items into one or multiple lines. A line is a row in ROW/ROW_REVERSE and a column in COLUMN/COLUMN_REVERSE direction. The "main axis" is the axis in which direction the items are arranged, i.e. the x-axis for rows and the y-axis for columns. The "cross axis" is the other axis.

FlexDirection

Specifies the direction in which child layouts (items) are arranged in the layout. Other flex properties with values like START and END depend on the direction.

FlexDirection.ROW

Items are arranged in rows.

FlexDirection.ROW_REVERSE

Items are arranged in rows, in reverse order. The item that is first in the contents list is at the end and vice versa. Items are still rendered in the same order as they appear in the contents list, so overlapping items will be rendered on top of each other in that order.

FlexDirection.COLUMN

Items are arranged in columns.

FlexDirection.COLUMN_REVERSE

Like ROW_REVERSE, but with columns.

FlexWrap

Specifies whether and how flex items can wrap into multiple lines (rows/columns).

FlexWrap.NO_WRAP

Items can not wrap, all items are displayed in one line.

FlexWrap.WRAP

Items can wrap into multiple lines if they do not fit into the available space.

FlexWrap.WRAP_REVERSE

like WRAP, but lines are arranged in reverse order.

FlexJustify

This property corresponds to justify-content in CSS flex layouts. It determines how items within a line are arranged on the main axis if there is space left over along the main axis after growing/shrinking items.

FlexJustify.START

The available space is at the end of the line, the items at the beginning.

FlexJustify.END

The available space is at the beginning of the line, the items at the end.

FlexJustify.CENTER

The available space is equally distributed at the beginning and end of the line, the items are in the center.

FlexJustify.SPACE_BETWEEN

The available space is equally distributed between the items, the first and last item are at the beginning and end of the line.

FlexJustify.SPACE_AROUND

The available space is equally distributed to the items, and for each item equally distributed before and after the item. There is twice as much space between two items as there is before the first and after the last item.

FlexJustify.SPACE_EVENLY

The available space is equally distributed before, after and between the items.

FlexAlignItems

Specifies how items within a line are arranged on the cross axis if they don't fill the entire cross size of the line.

FlexAlignItems.START

Items are arranged at the start of the line, i.e. at the top for rows and at the left for columns.

FlexAlignItems.END

Items are arranged at the end of the line, i.e. at the bottom for rows and at the right for columns.

FlexAlignItems.CENTER

Items are arranged at the center of the line.

FlexAlignItems.STRETCH

Items are stretched out to fill the line.

FlexAlignContent

Specifies how multiple lines are arranged on the cross axis within the layout when they don't fill the cross size of the layout. This is only relevant for layouts with multiple lines, a single line is always stretched to fill the layout (the items within such a line can be controlled with FlexAlignItems).

FlexAlignContent.START

The lines are at the beginning of the layout, i.e. at the top for rows and at the left for columns.

FlexAlignContent.END

The lines are at the end of the layout, i.e. at the bottom for rows and at the right for columns.

FlexAlignContent.CENTER

The lines are at the center of the layout.

FlexAlignContent.STRETCH

The lines are stretched to fill the available space. The available space is distributed equally between the lines.

FlexAlignContent.SPACE_BETWEEN

The available space is distributed equally between the lines but not around them.

FlexAlignContent.SPACE_AROUND

The available space is distributed equally to the lines, and for each line distributed equally before and after that line. The space between two lines is twice as much as the space before the first and after the last line.

FlexAlignContent.SPACE_EVENLY

The available space is distributed equally before, between and after the lines.

Box

This layout can render a title over its own top border.

from layout import Box, BoxTitleAnchor

Box(
    title=None,
    title_font=None,
    title_color=None,
    title_anchor=BoxTitleAnchor.LEFT,  # anchor for positioning
    title_position=0,  # x position of the title relative to the anchor
    title_padding=0,  # additional space to remove from the border on the left and right of the text
    content=None,
)

BoxTitleAnchor

Where to anchor the title along the top border. The top left and top right border radii are subtracted from the available space.

BoxTitleAnchor.LEFT

The title is anchored at the left edge of the border, plus the top left border radius.

BoxTitleAnchor.CENTER

The title is anchored in the middle of the border.

BoxTitleAnchor.RIGHT

The title is anchored at the right edge of the border, minus the top right border radius.

Text

This layout can render text. The layout algorithm is somewhat inefficient and arranging large amounts of texts can take a while. The line-breaking algorithm is very simplistic. Whitespace at the beginning (if left-aligned), end (if right-aligned) or begining and end (if center-aligned) is not rendered.

from layout import Text, TextAlign, TextVerticalAlign, TextWrap

Text(
    text=None,
    # can be provided as a single string or as a list of lines, if a list then lines must not contain line breaks
    text_align=TextAlign.LEFT,
    vertical_text_align=TextVerticalAlign.TOP,
    text_wrap=TextWrap.NO_WRAP,
    line_spacing=0  # spacing between the end of one line and the beginning of the next
)

TextAlign

How each line is aligned within the available horizontal space.

TextAlign.LEFT

TextAlign.CENTER

TextAlign.RIGHT

TextVerticalAlign

How all the lines together are aligned within the available vertical space.

TextVerticalAlign.TOP

TextVerticalAlign.MIDDLE

TextVerticalAlign.BOTTOM

TextWrap

TextWrap.NO_WRAP

Text is not automatically wrapped to fit into the available horizontal space, but explicit line breaks are respected.

TextWrap.ONLY_WORDS

Text is wrapped on word boundaries. Words that are too long to fit into a single line overflow.

TextWrap.PREFER_WORDS

Text is wrapped on word boundaries, and words that are too long to fit into a single line are wrapped as well.

TextWrap.EVERYWHERE

Lines are filled up as much as possible and text is wrapped wherever necessary.

Image

from layout import Image, ImageMode, ImageAnchor

Image(
    image=None,
    mode=ImageMode.ORIGINAL,
    scale=1,  # can be a number or a tuple of x- and y-scale
    position=ImageAnchor.TOP_LEFT,  # anchor for positioning
    offset_x=0,  # horizontal position of the image relative to the anchor
    offset_y=0,  # vertical position of the image relative to the anchor
)

ImageMode

How the image is displayed. This also affects how much space this layout tries to take up: With ORIGINAL mode both width and height correspond to the (scaled) width and height of the image. With STRETCH_X and REPEAT_X mode the height corresponds to the (scaled) height of the image, but the width is 0 unless forced otherwise. With STRETCH_Y and REPEAT_Y mode the width corresponds to the (scaled) width of the image, but the height is 0 unless forced otherwise. With all other modes the width and height are 0 unless forced otherwise. All modes except STRETCH, CONTAIN and COVER respect the scale property in some way.

ImageMode.ORIGINAL

The image is rendered at its original size, optionally scaled by the scale property.

ImageMode.STRETCH

The image is stretched to fill the available space.

ImageMode.STRETCH_X

The image is stretched in the x-axis to fill the available space and unmodified in the y-axis.

ImageMode.STRETCH_Y

The image is stretched in the y-axis to fill the available space and unmodified in the x-axis.

ImageMode.CONTAIN

The image is scaled proportionally to fill the available space as much as possible without being cut off. The image can still be cut off in places by positioning it or by rounded corners of the container. This can make the image smaller if the available space is smaller than the original image size.

ImageMode.COVER

The image is scaled proportionally to fill the available space completely. This can make the image smaller if the available space is smaller than the original image size.

ImageMode.REPEAT

The image is repeated on both axes to fill the available space.

ImageMode.REPEAT_X

The image is repeated on the x-axis to fill the available space.

ImageMode.REPEAT_Y

The image is repeated on the y-axis to fill the available space.

ImageMode.REPEAT_X_STRETCH

The image is repeated on the x-axis and stretched on the y-axis to fill the available space.

ImageMode.REPEAT_Y_STRETCH

The image is repeated on the y-axis and stretched on the x-axis to fill the available space.

ImageMode.REPEAT_X_FILL

The image is scaled like with CONTAIN on the y-axis and then repeated along the x-axis to fill the remaining space.

ImageMode.REPEAT_Y_FILL

The image is scaled like with CONTAIN on the x-axis and then repeated along the y-axis to fill the remaining space.

ImageAnchor

Where the image is anchored for positioning with offset_x and offset_y.

ImageAnchor.TOP_LEFT

ImageAnchor.TOP_CENTER

ImageAnchor.TOP_RIGHT

ImageAnchor.MIDDLE_LEFT

ImageAnchor.MIDDLE_CENTER

ImageAnchor.MIDDLE_RIGHT

ImageAnchor.BOTTOM_LEFT

ImageAnchor.BOTTOM_CENTER

ImageAnchor.BOTTOM_RIGHT

custom layouts

A layout should extend the Layout class and implement the following methods:

possible future features

border modes

option to render borders as outlines instead (i.e. not taking up layout space), with the following options:

  • NORMAL: border takes up layout space
  • OUTLINE_INSIDE: border is an overlay that takes up no space, inside of the layout rect
  • OUTLINE_OUTSIDE: border is an overlay that takes up no space, outside of the layout rect (only visible with overflow=true)
  • OUTLINE_CENTERED: border is an overlay that takes up no space, centered on the layout rect (only completely visible with overflow=true)

border styles

border styles like dotted, dashed, inset etc like in CSS