QR codes have invaded our world.
Their prolific penetration is no surprise. They store information efficiently, scan fast and reliably, and now that QR code scanning is built-in on most phone cameras, there is nothing that even comes close to their convenience.
They are simply irreplaceable to anyone looking to share a URL (read: everyone).


With how widespread they are in consumer facing spaces like advertising, it's also no suprise that companies would want to brand their QR codes. The most common practice is placing a logo in the center, which works because QR codes have error correction built-in.



Beyond simply placing a logo on top, there have also been many attempts to create "artistic" QR codes. Making a picture is the obvious thing to do, and there are various ways of combining the QR code pixels with an image for a unique look.
While these might require some upfront technical work, it's trivial to change the image to create any number of new QR codes. This is in stark contrast to the labor intensive process of having artists design fully bespoke QR codes from scratch.
There are more amazing examples than I could possibly fit on one page. These artists' have many other works, and Pinterest is full of examples that are otherwise impossible to find.Obviously, human-made QR code's aren't practical for anyone without lots of time or money since each new URL would require a redesign.
The natural progression is beating the dead elephant in the room called generative AI. These AI QR codes promise beautiful and customizable designs at scale. I recommend reading the creators' showcase blog post and Stable Diffusion QR Code 101 for a detailed explaination. I'll omit showing examples here—visit the links if you're interested—and I'll leave a poem in their place.
I shall not beleaguer thy weary eyes,
nor further burden the web, world wide,
with pages from this Babelian picture tome.
This is not a place of honor,
there are thirteen fingers on her,
anime girl big boobs ancient rome.
I'm more interested in programmatically generated QR codes.
Before they invented AI QR codes, the guys behind QRBTF also created these beautiful style options for their generator.
To this day, I still haven't seen anyone else make QR codes like this. I wanted more, so I made my own generator.


It's available at qrframe.kylezhe.ng, but it's more of a tool for crafting QR codes. It comes with presets that are simple to modify or create from scratch, because it's just Javascript that generates an SVG or renders to an HTML canvas.
Here's the source code for the perverts.
Anyways, if you have the time, I'd like to share what I learned about QR codes along the way.
The Anatomy of a QR Code
Finder patterns are the big squares shapes in three corners. These are used to determine the code's orientation, dimensions, perspective and more. The ratio of black and white pixels through the center is key (roughly 1:1:3:1:1), so the corners aren't essential.
To aid detection, finder patterns need a separator or "quiet zone" around them, but this doesn't have to be a specific size.
Alignment patterns are smaller squares used to account for distortion. There's usually one in the last corner, but the smallest QR code doesn't have any, while very large codes have multiple.
Timing patterns are the horizontal and vertical belts of alternating black and white pixels. These supposedly help with aligning rows and columns while decoding.
Unlike the finder patterns, the timing patterns and alignment patterns are not strictly necessary in practice. A QR code will mostly* scan fine without them.
*The bottom right alignment pattern does help, especially for larger sizes, while the timing pattern seems to be completely useless.
Format information stores the error correction level and the mask pattern applied to the data (explained below). One copy is in the top left, and the other copy is split between the top right and bottom left.
Very large QR codes will have a section for version information. Version means size, and it ranges from 1–40. One copy is in the top right, and the other copy is in the bottom left.
For smaller codes, size can be accurately calculated just using the distance between the finder patterns.
The remaining space is for the data.
Perhaps surprisingly, it starts at the bottom right and zigzags up and down, from the right to the left.
The bits are organized in blocks of 8 (aka bytes), so the last few pixels will be unused if the number of data pixels isn't divisible by 8.
There are 4 levels of error correction which allow roughly 7%, 15%, 25%, or 30% of all the bytes to be recovered. See how increasing the error correction also reduces the data capacity.
If you further break down the data, you'll see it starts with a header and is padded to fill the unused capacity. You can play around with the error correction level, version (size), and input text to see how the space is used.
THIS MAY LOOK VERY WEIRD. After the certain size, the data bytes are interleaved so they are spread throughout the space rather than placed continguously. Also, the header isn't a multiple of 8 bits, so the data isn't byte aligned.The data header describes the encoding mode and the character count. There are efficient encoding modes for numbers and alphanumeric text, but the only relevant mode for URLs is Byte mode*, which just means UTF-8.
*Alphanumeric mode can encode URLs, but it only supports uppercase characters, so no one uses it.Finally, the mask is one of 8 patterns XOR-ed with the data to break up undesirable pixel arrangements (like the finder pattern shape).
QR codes can be rotated, mirrored, and the "dark" and "light" pixels can be inverted.
Here's all you need to remember to make an artistic QR code: the finder patterns must be the right shape, and the rest of the QR code just needs to be dark or light enough in the right place.
That's 80% of it, but unfortunately there's one major gotcha we've gotta cover.
Convenience at a Cost
Can you tell what I did wrong with these QR codes I drew using chalk?


The first one is janky, but I was legitimately confused why my second attempt failed.
Computer vision is commonly used in code scanners nowadays, but the tradeoff of non-dedicated scanners (like the default smartphone camera app) is that they need to first detect a QR code before any scanning occurs. This ends up being much pickier than dumb scanners which constantly try to decode what they see.
I'm no expert in this domain, and computer vision is somewhat of a black box anyway, so the only way I know to tell if a QR code will scan is to try scanning it, and moving closer or farther can sometimes help.
In my experience, solid colors and high contrast are good indicators (and what my chalk drawing lacked), but once a QR code strays from black and white pixels, its fate is partially in the hands of God.
With that in mind, let's cover existing ways people have successfully created artistic codes programmatically.
Image Techniques
There is a wide breadth and depth of research into recreating images with QR codes, but they can be broadly categorized into the following categories.
Overlaying data
Reverse-engineering data
These techniques start with the desired output and modify the input data to match. These are basically incompatible with a normal QR code generator and require deep custom logic.
I ended up making my own reverse-engineered Bad Apple with the goal of making it somewhat scannable in realtime. Adding a noisy pattern makes it much more likely to be detected. The source code is an example in fuqr
.
Non-Image Techniques
Since there aren't too many examples of these, I'll be showing my own work and giving my thoughts.
While each unique design will have unique challenges, hopefully these examples can give you some some idea of steps you can take.
Forgery
Good artists copy. Often times human-made designs are possible to implement using code. Here, Douglas Coupland has replaced 2x2 squares of black and white with a corresponding dark or light colored square. Not only is this easy to code, it demonstrates a common tactic of replacing groups of pixels with a larger design element. See Vancouver Codes (2012) for more examples of his work.
Great artists steal. The original design is slick, but not all that glitters is a scannable QR code. When things don't scan, experience tells us that we need solid colors and higher contrast. I opted to increase the dot size and density, especially for the finder patterns, and I filled the gap between dots with a dark shadow. This is less pretty, but a necessary compromise.
Great programmers steal by copying code. This QR code style option, along with many others, is found in the react-qrbtf
repository under the MIT license. Building on top of existing code is a great way to make a new design, so feel free to use my code in the qrframe
repository as well. The psychological damage you'll suffer is cost enough.
Touching grass
Of course I had to digitally create what I failed to do in real life. With the help of roughjs
, making hand-drawn SVGs is quite simple. Playing with the fill and roughness parameters really helped me understand where the line between undetectable and reliably scannable is. My manual drawing was not even close. I cannot overemphasize solid colors and high contrast.
Exposure to all types of art is probably the best source of creative energy. The design is quite simple, but the effect is mighty like the elephant. If there's a lesson to be learned here, it's that rules are made to be respectfully broken. You CAN mess with the finder patterns, but notice how the cross shape is completely preserved in two of them.
Animation is generally a bad idea since you want every frame to be scannable. But the call of the sea is unrelenting. In this example, each pixel only changes in scale, and the center 1/3 of each pixel is always the correct color like in the dot overlay technique. And that's the final lesson, that none of these techniques are mutually exclusive.
Congratulations, you now know too much about QR codes!
Thanks for reading!
I hope you learned something interesting, even if it's not useful.
If you'd like to design a QR code, and you're not afraid of writing a little code, give qrframe.kylezhe.ng a try.
The editor and rendering source code is available at qrframe
while the QR code generator written in Rust that powers it is available at fuqr
.
You can do it if you try, but also your time is precious.
See ya! 🫡
Random Tangents
Here are some QR code thoughts I had to get off my mind.
-
There are
many, there are4, there is 1 encoding mode.- The QR code standard doesn't reflect reality. I'm sure there are standards compliant generators and scanners, probably in some legacy systems of some Japanese enterprise that still uses fax machines and pagers.
- Alphanumeric and Numeric mode are supported b/c they are dead simple to implement, but nobody uses this.
- Nobody supports extensions like Structured append, ECI, and FNC1 encoding modes.
- Nobody supports Kanji mode
- Nobody assumes byte mode is ISO 8859-1
- Everybody just assumes UTF-8. It's identical for ASCII (all URLs) and the default encoding for most systems.
-
The mask selection step is deeply unserious.
- The best mask is chosen by scoring the masked data, but the scoring conditions are arbitrary, and all 8 masks will work just fine anyway.
- This interative step by step walkthrough showcases this in Steps 7 and 8. Choose the worst mask and see that it doesn't matter.
- www.nayuki.io/page/creating-a-qr-code-step-by-step
-
Proprietary scannable codes are kinda funny. Tiktok, Snapchat, and Instagram have already replaced their custom codes (TikCode, Snapcode, Nametag, respectively) with stylized QR codes.
-
Here are links I don't want to lose.
- www.thonky.com/qr-code-tutorial is a great resource and helped me understand the error correction math.
- segno is probably the only QR code generator that supports Kanji mode.
- I've found two 3d galleries of QR code art. If I had a nickel...
- QRazyBox is a super cool QR code recovery tool that I used to decode this book cover and find the original stock image from 2011.