So you came to the right place, here I will help you out with how with pixie basics and how to use it in your projects.
Are you looking for the API reference? https://treeform.github.io/pixie/pixie.html
nimble install pixieThen just import it:
import pixiepip install pixie-pythonThen just import it:
importpixieor
frompixieimport*You can either load paths from a standard SVG style string or build it up with methods.
var heart1 =newImage(200, 200)
heart1.fill(rgba(255, 255, 255, 255))
heart1.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""",
"#FC427B"
)
heart1.writeFile("images/heart1.png")Will produce:
But you can also build the path with path commands:
var heart2 =newImage(200, 200)
heart2.fill(rgba(255, 255, 255, 255))
var heartPath =newPath()
heartPath.moveTo(20, 60)
heartPath.ellipticalArcTo(40, 40, 90, false, true, 100, 60)
heartPath.ellipticalArcTo(40, 40, 90, false, true, 180, 60)
heartPath.quadraticCurveTo(180, 120, 100, 180)
heartPath.quadraticCurveTo(20, 120, 20, 60)
heartPath.closePath()
heart2.fillPath(heartPath, "#FC427B")
heart2.writeFile("images/heart2.png")Both methods will produce the same image:
You can use paths to draw almost anything.
var heart3 =newImage(200, 200)
heart3.fill(rgba(255, 255, 255, 255))
let gradientPaint =newPaint(RadialGradientPaint)
gradientPaint.gradientHandlePositions =@[
vec2(100, 100),
vec2(200, 100),
vec2(100, 200)
]
gradientPaint.gradientStops =@[
ColorStop(color: color(1, 0, 0, 1), position: 0),
ColorStop(color: color(1, 0, 0, 0.15), position: 1.0),
]
heart3.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""",
gradientPaint
)
heart3.writeFile("images/heart3.png")Pixie supports many different blends and masking modes. You can use masking blends modes to mask out areas of the image. Here we will draw a background "X" then cut the heart path out of it.
var background =newImage(200, 200)
background.fill("#3498db")
background.strokePath(
""" M 25, 25 L 175, 175 M 25, 175 L 175, 25""",
paint ="#ecf0f1",
strokeWidth =30
)
background.writeFile("images/masking1.png")You can see this produces crossed lines:
Mask paint is a special type of paint that has blendMod set to MaskBlend.
Instead of adding color to the image the MaskBlend will eat color a way:
var maskPaint =newPaint(SolidPaint)
maskPaint.color =color(1, 1, 1, 1)
maskPaint.blendMode =MaskBlendAnd now you can just draw the path normally but with the new mask paint:
var mask =newImage(200, 200)
background.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""",
maskPaint
)
background.writeFile("images/masking2.png")This results in a cutout "X" image.
Pixie has many powerful text features.
You can typeset text in different ways:
var textImage =newImage(240, 70)
textImage.fill("#FFFFFF")
var font =readFont("fonts/Roboto-Regular_1.ttf")
font.size =40let text ="Hello world."
textImage.fillText(font.typeset(text, vec2(240, 60)), translate(vec2(10, 10)))
textImage.writeFile("images/text1.png")Text is layed out in spans and spans are layed out into an arrangement. You can create different spans of text of different fonts and sizes.
var textImage =newImage(200, 200)
let typeface =readTypeface("fonts/Ubuntu-Regular_1.ttf")
procnewFont(typeface: Typeface, size: float32, color: Color): Font=result=newFont(typeface)
result.size = size
result.paint.color = color
let spans =@[
newSpan("verb [with object] ",
newFont(typeface, 12, color(0.6, 0.6, 0.6, 1))),
newSpan("strallow\n", newFont(typeface, 36, color(0, 0, 0, 1))),
newSpan("\nstral·low\n", newFont(typeface, 13, color(0, 0.5, 0.953125, 1))),
newSpan("\n1. free (something) from restrictive restrictions \"the regulations are intended to strallow changes in public policy\"",
newFont(typeface, 14, color(0.3125, 0.3125, 0.3125, 1)))
]
textImage.fill("#FFFFFF")
textImage.fillText(typeset(spans, vec2(180, 180)), translate(vec2(10, 10)))
textImage.writeFile("images/text2.png")Currently pixie supports many text features but not all of them:
| Description | Supported |
|---|---|
| ASCII English | ✅ |
| European Alphabets | ✅ |
| Other Alphabets | ✅ |
| CJK - Chinese/Japanese/Korean | ✅ |
| Cursive Fonts | some |
| Emoji | no |
| RTL - Arabic/Hebrew | no |
| Unicode shaping | no |
| Ligatures | no |
Do you have a server that needs to crop or scale images? You can use uploaded file size and image.readImageDimensions() to first make sure its an image you want to load:
let size =readImageDimensions("images/profile.jpeg")
echo size
if size.width >512or size.height >512:
quit("Image dimensions too big")Now that we know its not to big to cause memory issues we can read and crop it:
var profile =readImage("images/profile.jpeg")
var smallProfile = profile.resize(64, 64)
smallProfile.writeFile("images/smallProfile.png")We made a bigger image:
Turn into a 64x64 profile image:
You can also cut people out of a circle for those new "modern profiles images". Simply mask some thing with a circle like this:
var maskPath =newPath()
maskPath.circle(32, 32, 32)
smallProfile.fillPath(maskPath, maskPaint)Then just write it out:
smallProfile.writeFile("images/circleProfile.png")Some times you don't have a person's photo and want to just create a colored circle with the letter. First we will draw the background circle:
var letterProfile =newImage(64, 64)
var path =newPath()
path.circle(32, 32, 32)
var paint =newPaint(SolidPaint)
paint.color =parseHtmlColor("#2ecc71")
letterProfile.fillPath(path, paint)
letterProfile.writeFile("images/letterProfile1.png")That looks like this:
Then we will draw the foreground letter:
var profileFont =readFont("fonts/Roboto-Regular_1.ttf")
profileFont.size =36
profileFont.paint ="#ecf0f1"let profileLetters ="Ev"
letterProfile.fillText(profileFont.typeset(
profileLetters,
vec2(64, 64),
hAlign =CenterAlign,
vAlign =MiddleAlign
))And this is what you get:
letterProfile.writeFile("images/letterProfile2.png")You can load an image and convert it to a texture like this:
import opengl
procloadTexture() =let testTexture =readImage("examples/data/testTexture.png")
var textureId: uint32glGenTextures(1, textureId.addr)
glBindTexture(GL_TEXTURE_2D, textureId)
glTexImage2D(
target =GL_TEXTURE_2D,
level =0,
internalFormat =GL_RGBA8.GLint,
width = testTexture.width.GLsizei,
height = testTexture.height.GLsizei,
border =0,
format =GL_RGBA,
`type` =GL_UNSIGNED_BYTE,
pixels =cast[pointer](testTexture.data[0].addr)
)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)See the complete working example: https://github.com/treeform/windy/blob/master/examples/textured_quad.nim
Keep in mind that pixie images are in premultiplied alpha state. We recommend doing all alpha blending in premultiplied alpha for 2d and 3d graphics.












