Hello everyone, @guzba and I have tagged our new Pixie 5.0 release today focused on shipping a ton of performance improvements and wanted to make a post sharing what is in the release.
Pixie on Github: https://github.com/treeform/pixie
Us discussing this release on YouTube: https://www.youtube.com/watch?v=Did21OYIrGI
SIMD improvements:
We have this set up so that all you ever need to do is import pixie and you'll get the best possible performance without any arcane build config.
Having NEON for arm64 is a massive upgrade. For example, while the Apple M1 can emulate x64 instructions, many of the SIMD instructions do not have direct analogues in NEON so the performance achieved by x64 SIMD on M1 can be very poor.
Furthermore, having AVX2 basically doubles the performance of many Pixie operations on amd64. The problem is AVX2 is not guaranteed to be supported on all x64 CPUs. Instead of having multiple build configs to control what instruction set is used, we opted for a runtime-check so one executable can deliver the best possible performance on every machine.
Path filling and image compositing
We've made very significant optimizations to both path filling and image compositing in Pixie. Not only do these operations now benefit from the improved SIMD, path filling in specific got a huge boost from a smart shortcut we've added. We talk much more about this in the video so check that out.
Pixie path filling and pixel-aligned image blending (eg image1.draw(image2, vec2(10, 10))) is now faster than Cairo in the set of common cases we've targetted for this release. Comparing two complex libraries is not easy but we're not cherry-picking results nor saying this lightly. Cairo is exceptional and being competitve and even outperforming it is a major accomplishment.
Faster PNG + animated GIF support
Loading PNG is now faster with Pixie (even faster than the amazing stb_image). We've also added support for loading animated GIF files. Currently you'll need to import pixie/fileformats/gif to use the new decodeGif proc. See more docs here: https://nimdocs.com/treeform/pixie/pixie/fileformats/gif.html
Better documentation and examples
Getting started with 2d graphics can be a bit overwhelming when you realize it is far more powerful than just drawing some rectangles. To help with this, we're working on https://github.com/treeform/pixiebook. This will take some time for us to really do a good job but consider checking this out of you're interested in getting started with Pixie.
Thanks to everyone that's been using Pixie. We hope these new upgrades make all of your programs even faster!
Hello, thank you for your excellent work!
I have a question about this project: I've noticed that a png file created with Pixie can be greatly reduced in size using a tool like https://tinypng.com/. For example, the result of the heart example from the documentation can be shrunk from 3,68 kB to 1,26 kB. Would you consider adding an alternative size-optimized write function to Pixie?
import pixie
let image = newImage(200, 200)
image.fill(rgba(255, 255, 255, 255))
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
)
image.writeFile("heart.png")
If you want absolutely smallest PNG files i recommend using some thing like pngcrush or tinypng that you linked.
Our aim was to write a "pretty good" PNG writer with balanced compression and speed.
If these images change rarely doing a pre-processing with pngcrush during deploy is great idea. But if you are serving dynamic images it's better to generate the image fast and send it.
Is there any document on pasting a small Image onto another big Image? For example, paste the small one on the big one at (x=10, y=20)
After reading some exampes, I have coined the following one but without success
var img = readImage("big.png")
let paint = newPaint(ImagePaint)
paint.image = readImage("small.png")
paint.imageMat = translate(vec2(10, 20))
img.fill(paint)
img.writeFile("tmp.png")
thanks.
My apologies for adding cruft that probably belongs on a separate thread.
Hey @oyster I suspect float values are used because Pixie is, at heart, a vector graphics library. That it also happens to handle pixel-based images is (somewhat tongue-in-cheek) almost incidental.
A slightly different approach?
import pixie
import pixie/contexts
var bigImage = readImage("bigImage.png")
var smallImage = readImage("smallImage.png")
var bigContext = newContext(bigImage)
bigContext.drawImage(smallImage, 10.0, 20.0)
bigImage.writeFile("modifiedBig.png")
A big thank you to @treeform and @guzba for all their excellent work on Pixie.
A slightly different approach?
from what I understand from this chapter of the new pixiebook linked above (very nice!), the context based api is for people familiar with JS Canvas or Cairo, but everything (and possibly more) should be doable with the "native" image-based api.
My apologies for adding cruft that probably belongs on a separate thread.
I think it is fine to bump and celebrate the great work @treeform and @guzba did on pixie with more examples and discussion even if not directly related to the new release. I did appreciate this, since it lead me to learn about this two apis that I was not aware of.
In the same spirit, I will share another example of pixie usage I did some time ago where I used pixie to reproduce the wordle game social image (and generated an italian version, which is currently used for an italian translation of wordle): https://pietroppeter.github.io/wordle-it/images.html
there are a couple of instances there of pasting an image into another (addSquare and drawing the flag) and oddly enough I was using once the context based api and the second time the image based api without realizing about the differences...