A library for declarative rendering on the backend. Considering that there is no goal to replicate browser rendering, a simple positioning model has been implemented.
The layout is described using a yaml file, in which templates can be used to customize any field.
decorender.NewRenderer
parses this yaml file with your markup, validates the data, compiles the templates, initializes the necessary data, caches, and returns an object that is then used for frequent rendering with data.
To make layout process easier and more convenient, decorender has a dev server with auto-reloading and error display. An example of its use is shown below.
Create file layout.yaml
with minimal content:
text: Hello, world!
Make sure you have Go installed
brew install go
export PATH=$PATH:$HOME/go/bin
Install dev server for easy visualising your layouts
go install github.com/godknowsiamgood/decorender/cmd/decorender_server@latest
Start dev server. It will open page with autoreload and some useful information. If your template has templates, you can mock them with sample
field.
decorender_server layout.yaml
go get -u github.com/godknowsiamgood/decorender
// Create a renderer object that reads the yaml file
// and initializes the necessary resources
renderer, err := decorender.NewRenderer("./layout.yaml", &decorender.Options{
...
})
// Then it can be used multiple times
// with different data and concurrent-safely.
img, _ := renderer.Render(yourData, &decorender.RenderOptions{})
renderer.RenderAndWrite(yourData, decorender.EncodeFormatPNG, writer, &decorender.RenderOptions{})
renderer.RenderToFile(yourData, "result.jpg", &decorender.RenderOptions{})
size: 1000 1000 # - Optional size of result image in pixels.
scale: 2 # - Optional multiplier of result image (e.g. 0.5, 1.5, 10).
fontFaces: # - Font faces that will be used in layout.
- family: Inter
style: italic
weight: 400
file: ./Inter-italic-400.ttf
sample: # - Any arbitrary object to test layout with expr templates.
inner: # - Child nodes.
- size: 100% 100% # - Size. Use absolute values, or percents.
bkgColor: salmon # - Background color. Use predefined colors, or 0xaabbcc, 0xaabbccff.
color: black # - Color of text. This property is inherited to all children.
font: Inter 23 400 # - Current font in format <family> <size> <weight>. Every part is optional,
# except single number will be interpreted as size.
text: Hello # - Text that will be wrapped if needed.
innerDirection: row # - Values row/column instructs how children will be located.
justify: end # - Values start/center/end/space-between - how children will be positioned.
innerGap: 5 # - Minimal gap between children.
padding: 10 20 # - Padding for children.
borderRadius: 20 # - Border radii (e.g. 15 66, 10 20 30 40).
absolute: left # - Instructs how element should be anchored to parent at desired position
# with respect of parent padding, e.g.
# left - at center left, right bottom - at corner,
# left right - node will be stretched horizontally.
# Also you can specify offset for each direction, e.g. left/-10 top/55.
bkgImage: # - Image for element background. Use local or external file starting with https://...
bkgImageSize: cover # - Values cover/contain
forEach: Array # - Name of field in user data. Node will be replicated accordingly.
See test.yaml
and test.png
for more examples.
In almost any field, you can use an expression instead of a fixed one. github.com/antonmedv/expr
is used. Just write ~ Field
to access to field. In the context of loops there are variables value
, index
and parent
.
Almost everything is written with performance considerations in mind.
- No rendering libraries are used, everything is drawn with standard libraries. The only exception is github.com/disintegration/imaging for rotations.
- Work with all heavy objects (internal node tree, buffers for images, rasterizers) is done through sync.Pool.
- A small LRU cache is used for frequently used images. Also, an LRU cache is used for frequently used masks (which, for example, are used for drawing rounded rectangles).
- Downloaded external images are stored in the system's tmp directory and are not downloaded again upon reuse.
Take into consideration:
- If possible use images with exact size as will be appear in layout. Scaling is quite expensive operation.