nbw

nbw

Hi everyone, I’d like to introduce a library I made for generating QR Codes and address some of the performance gains and some of the drawbacks.

github: GitHub - nbw/qrusty: Elixir QR Code library that leverages precompiled Rust · GitHub

Why use QRusty instead of …?

I think the only real benefit of QRusty is performance. Libraries like EQRCode or QRCode have a wider range of features (color, shapes, etc), plus they’re 100% written in Elixir. I’ve used EQRCode on many projects myself.

QRusty does support the JPG format, which EQRCode doesn’t, but that’s a perk really.

QRCode is supports SVG out of the box. Other formats (PNG, JPG, etc) require external image processing libraries.

Why make this library?

@philss published Rustler precompiled recently which in my opinion makes using Rust for libraries a real option (check out the blog post and the Thinking Elixir episode). I wanted to see what kinds of performance gains could be achieved for simply tasks like generating QR Codes (markdown parsing could be another one, etc).

I’m not a Rust developer. This was also a chance for me to learn Rust and write something for the first time that’s actually useful for me.

What were the performance gains [updated with QRCode]

Compared to EQRCode?

It varies by format and by image size but:

  • SVG: ≈ 42x faster
  • PNG: ≈ 7x - 27x faster (7x: 500 pixels wide; 27x 100 pixels wide)

I’ve summarised the gains here in the README and also added the raw benchee output here.

It’s worth saying that generating a single QR code is too fast to accurately measure, so the benchmarks are actually testing the time to generate 100 codes.

Why does the PNG performance gain get worse by image size?

You’ll notice that the performance varies between 7x - 27x depending on the image size. I suspect this is because the Rust code deals with the image pixel by pixel (writes each pixel to a buffer).

On the other hand, EQRCode stores a matrix of squares and draws those squares instead of pixel by pixel. Basically, EQRCode is more efficient in that regard and its performance doesn’t vary too much by image size. I haven’t read the code in depth, but you can see mentions of a pixel size and matrix in the png encoder.

Could this gap be fixed or improved? Maybe. I’d be happy to know if there’s a better way than writing to to a Vector buffer when creating generating the file and converting it to a binary.

Compared to QRCode?

  • SVG: ≈ 11.8x faster

Are you using it in production?

Yes, we use it on our staging Fly.io environment. Will be deploying to Gigalixir later this week.

Any tips for others using precompiled Rust in a project?

  • if you’re running benchmarks locally with a locally compiled rust binary, make sure to enable release mode
  • getting the release flow of generating and publishing the Rust binaries as part of a hex package takes a bit of getting used to. Read the documentation a few times and don’t expect to get it right the first time. As @wojtekmach pointed out in this thread you can unpublish a hex release within an hour. There are also handy hex commands to check if the right files are included before publishing

Potential drawbacks of using Rust

It’s in Rust (duh)

The biggest and most obvious one is that it’s not written in Elixir. EQRCode and QRCode are 100% written in Elixir so they’re much easier to read through and maintain. Unless you’re a Rust developer (and I’m not) then it makes it difficult to track down bugs and add features depending on your background.

For my own clarity I included a few rules in the README about using Rust:

  • The Rust layer should be as thin as possible
  • The Rust layer should not deal with errors caused by human input (ex: invalid input args). Deal with interface errors in Elixir as much as possible
  • Default values, etc. should all be handled on the Elixir side

Basically, the end user is an Elixir developer, so keep as much code as possible in Elixir for readability. Leverage Rust only for its performance benefits/access to system level libraries, etc.

Library dependencies

The other issue is that the code is very reliant on whatever existing Rust libraries are available. In the case of QRusty, I had to use a fork of qrcode that supports image v0.24. That’s not my favourite position to be in.

Known issues

  • There’s an issue with the width/height of the generated qr code. Seems like the generated qr code code isn’t exactly the specified width/height, but instead the closest size that fits all the qrcode data. will look into it later (issue)

Thank you if you made this far :folded_hands:. Let me know what you think and where things could be improved.

Showing Posts 1 to 10

princemaple

princemaple

Good little lib. Thanks :+1:

Which error correction level is it using?

nbw

nbw OP

I actually wasn’t aware of qr code “error correction” (neat), but I a did a bit of sleuthing and it’s “medium” level correction by default (rust docs).

There are four levels that the Rust library implements:

L: Low error correction. Allows up to 7% of wrong blocks.
M: Medium error correction (default). Allows up to 15% of wrong blocks.
Q: “Quartile” error correction. Allows up to 25% of wrong blocks.
H: High error correction. Allows up to 30% of wrong blocks.

https://docs.rs/qrcode/0.6.0/qrcode/types/enum.EcLevel.html#variants

Would be very trivial to add support for the variants so I’m going to look into that. Thanks!

princemaple

princemaple

Thank you. Being able to configure this will make it a lot more useful.

princemaple

princemaple

FYI this correction is how you can stick a logo in the middle of a QR code and still be able to scan it.

ondrej-tucek

ondrej-tucek

Nicely done. Can you also compare (performance, etc..) QRusty with this QRCode which is purely written in Elixir?

outlog

outlog

great work, will give it a go on a nerves/raspberry next time around..

on a tangent but see GitHub - HughChen/qr_image: A web app to generate valid QR codes with readable images. · GitHub for image/qr code awesomeness.. (suppose we should look into landing similar feature in one of the elixir libs.. - perhaps utilizing image | Hex)

nbw

nbw OP

Error correction level added along with a few other things.

nbw

nbw OP

I’ll look into it!

princemaple

princemaple

Looks great. Looking forward to using it in a project soon.

nbw

nbw OP

I added benchmarks against QRCode and updated this post. (MR)

QRCode is actually a really nice implementation. Code is clean and it has lots of supported features including error correction. Very cool. At least by my benchmarks it performs 4x faster than EQRCode too (if speed is important to your use case).

Where Next? Top

Trending in Announcing Top

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
ausimian
Castle is a package I put together to assist with building Elixir releases capable of being live-upgraded via the ‘official’ release hand...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
drozdzynski
Storex is a frontend store with state management handled on the backend. It allows you to update the store state both from the frontend a...
New
gushonorato
Hey everyone! :waving_hand: I’m excited to share a new library with you all: Magic Auth! It’s an authentication library for Phoenix proj...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews