36b10a62d6
simpler + out of bounds color for image blur |
||
---|---|---|
.github/workflows | ||
docs | ||
examples | ||
experiments | ||
src | ||
tests | ||
tools | ||
.gitignore | ||
LICENSE | ||
pixie.nimble | ||
README.md |
Pixie - A full-featured 2D graphics library for Nim
Pixie is a 2D graphics library similar to Cairo and Skia written (almost) entirely in Nim.
This library is being actively developed and we'd be happy for you to use it.
nimble install pixie
Features:
- Drawing paths, shapes and curves with even-odd and non-zero windings.
- Pixel-perfect AA quality.
- Supported file formats are PNG, BMP, JPG, SVG + more in development.
- Strokes with joins and caps.
- Shadows, glows and blurs.
- Complex masking: Subtract, Intersect, Exclude.
- Complex blends: Darken, Multiply, Color Dodge, Hue, Luminosity... etc.
Documentation
API reference: https://treeform.github.io/pixie/pixie.html
File formats
Format | Read | Write |
---|---|---|
PNG | ✅ | ✅ |
JPEG | ✅ | |
BMP | ✅ | ✅ |
SVG | ✅ |
Joins and caps
Supported Caps:
- Butt
- Round
- Square
Supported Joins:
- Miter (with miter angle limit)
- Bevel
- Round
Blending & masking
Supported Blend Modes:
- Normal
- Darken
- Multiply
- ColorBurn
- Lighten
- Screen
- Color Dodge
- Overlay
- Soft Light
- Hard Light
- Difference
- Exclusion
- Hue
- Saturation
- Color
- Luminosity
Supported Mask Modes:
- Mask
- Overwrite
- Subtract Mask
- Intersect Mask
- Exclude Mask
SVG style paths:
Format | Supported | Description |
---|---|---|
M,m | ✅ | move to |
L,l | ✅ | line to |
h,h | ✅ | horizontal line to |
V,v | ✅ | vertical line to |
C,c,S,s | ✅ | cublic to |
Q,q,T,t | ✅ | quadratic to |
A,a | ✅ | arc to |
z | ✅ | close path |
Testing
nimble test
Examples
Square
let
pos = vec2(50, 50)
wh = vec2(100, 100)
image.fillRect(rect(pos, wh), rgba(255, 0, 0, 255))
Line
let
start = vec2(25, 25)
stop = vec2(175, 175)
color = parseHtmlColor("#FF5C00").rgba
image.strokeSegment(segment(start, stop), color, strokeWidth = 10)
Rounded rectangle
examples/rounded_rectangle.nim
let
pos = vec2(50, 50)
wh = vec2(100, 100)
r = 25.0
image.fillRoundedRect(rect(pos, wh), r, rgba(0, 255, 0, 255))
Heart
image.fillPath(
"""
M 20 60
A 40 40 90 0 1 100 60
A 40 40 90 0 1 180 60
Q 180 120 100 180
Q 20 120 20 60
z
""",
parseHtmlColor("#FC427B").rgba
)
Masking
lines.strokeSegment(
segment(vec2(25, 25), vec2(175, 175)), color, strokeWidth = 30)
lines.strokeSegment(
segment(vec2(25, 175), vec2(175, 25)), color, strokeWidth = 30)
mask.fillPath(
"""
M 20 60
A 40 40 90 0 1 100 60
A 40 40 90 0 1 180 60
Q 180 120 100 180
Q 20 120 20 60
z
"""
)
lines.draw(mask)
image.draw(lines)
Gradient
let paint = Paint(
kind: pkGradientRadial,
gradientHandlePositions: @[
vec2(100, 100),
vec2(200, 100),
vec2(100, 200)
],
gradientStops: @[
ColorStop(color: rgba(255, 0, 0, 255), position: 0),
ColorStop(color: rgba(255, 0, 0, 40), position: 1.0),
]
)
image.fillPath(
"""
M 20 60
A 40 40 90 0 1 100 60
A 40 40 90 0 1 180 60
Q 180 120 100 180
Q 20 120 20 60
z
""",
paint
)
Image tiled
var path: Path
path.polygon(
vec2(100, 100),
70,
sides = 8
)
image.fillPath(
path,
Paint(
kind: pkImageTiled,
image: readImage("tests/images/png/baboon.png"),
imageMat: scale(vec2(0.08, 0.08))
)
)
Shadow
let polygonImage = newImage(200, 200)
polygonImage.fillPolygon(
vec2(100, 100),
70,
sides = 8,
rgba(255, 255, 255, 255)
)
let shadow = polygonImage.shadow(
offset = vec2(2, 2),
spread = 2,
blur = 10,
color = rgba(0, 0, 0, 200)
)
image.draw(shadow)
image.draw(polygonImage)
Blur
let mask = newMask(200, 200)
mask.fillPolygon(vec2(100, 100), 70, sides = 6)
blur.blur(20)
blur.draw(mask, blendMode = bmMask)
image.draw(trees)
image.draw(blur)
Tiger
let tiger = readImage("examples/data/tiger.svg")
image.draw(
tiger,
translate(vec2(100, 100)) *
scale(vec2(0.2, 0.2)) *
translate(vec2(-450, -450))
)