qart.uk

Free photo QR code generator

Turn a photo into a QR code that still scans — free, instant, and entirely inside your browser. The picture is dithered into the gaps between the code's modules, so the photo and the data occupy the same pixels. No account, no watermark, no limit, and the image is never uploaded anywhere: this page does the work, not a server. The tool is right below.


How it works

A scanner reads a QR code as a grid of light and dark modules, not as pixels, which leaves room to say the same thing with a picture. Each module is expanded into a block of subpixels and only the centre one has to carry the module's true value. That frees every other subpixel in the block to carry the photograph instead.

  1. The code is encoded first. Your payload, error-correction level, version and mask are settled before any image processing happens, so the pixels that matter are known up front rather than negotiated afterwards.
  2. A first error-diffusion pass fixes the data. Floyd–Steinberg dithering walks the image; where a pixel is a data point it is forced to the value the code needs, and the resulting error is pushed out into the surrounding free subpixels.
  3. A second pass dithers everything left over. The free points take whatever the photograph wants, having already absorbed the error from step 2 — which is why the result reads as a continuous-tone picture rather than a code with a photo pasted behind it.

The finder squares, timing lines and alignment patterns stay locked by default. They are what a scanner uses to find and square up the code at all, and dithering them is the fastest way to make something that looks better and scans worse. The output is a 1-bit PNG, which is what you want for print.

Getting one that actually scans

Two knobs decide this, and the defaults are already the safe ones. Error correction defaults to H, the highest of the four levels — it spends more of the code on redundancy, which is exactly the budget the dithering spends. Subpixel ratio is how many subpixels wide each module gets, and it is capped at 3 to 6 because both ends of that range have been shown to decode with real photographs. Below 3 there is no room for a picture; above 6 the file grows without scanning any better.

Shorter payloads scan better, always. A long URL needs a denser code, which means smaller modules and less room per module for the photo. If a code is fighting you, shortening the link does more than any other change.

This tool is the one thing on qart.uk that nobody checks for you. Everywhere else on this site an image is decoded by a real QR detector before it is offered to you, and that check runs on our GPU host. This page never talks to that host — it never talks to any server — so its output is unverified by construction. Scan the result with more than one phone before you commit it to print, especially at small sizes or on anything glossy.

Where the technique comes from

The error-diffusion approach here is a port of Andrew Tunnicliffe's dithered QR codes, which is the clearest treatment of the two-pass idea we know of. The older ancestor is Russ Cox's QArt codes, which established the point this all rests on: a QR code has enough slack that you can choose what the redundant bits look like. Neither of them is responsible for our bugs.

If a dithered photo is not what you wanted

You want generated artwork, not your own photo
The Studio runs a diffusion model against your payload and checks every image with a real detector before you keep it. Paid, in prepaid credits, and it will tell you which images failed rather than quietly hiding them.
You want to change the destination after printing
A dithered code encodes your URL directly, so it can never be re-pointed — the trade being that it does not depend on us still existing. If you need to retarget later, claim a free code from the pool instead: those encode a short qart.uk link, so every copy already printed follows when you change where it goes.
You want one from a script or an agent
This tool has no API — there is no server side to call. The paid endpoints do; llms.txt is the map.