Making a QR code brighter than white
Building a simple tool that turns URLs and existing QR codes into brighter HDR QR code videos.
tl;dr I made hdrqr.jamesdonnelly.au, a little tool that takes any URL or existing QR code and gives you an HDR QR code in video format.
SDR image
Yes, the output is a video. Even though it doesn’t move.
A while ago I came across dtinth’s HDR QR Code demo and the accompanying superwhite project. It uses HDR video to display white at a higher brightness than the ordinary white elsewhere on the screen.
Modern HDR displays have brightness available above normal SDR “reference white”, which Apple calls display headroom. HDR content can ask to use that headroom. Video isn’t uniquely capable of being brighter. HDR images and custom rendering can do it too. But a tiny HDR video is a convenient and widely supported way of achieving it on Apple devices.
So there isn’t a special QR code trick. The video is simply encoded with a white level above SDR white, and the display renders it much brighter where it can.
Which is a neat trick, but also potentially quite useful for QR codes.
We’ve all done the little dance where someone holds up a QR code, it doesn’t scan, they turn their screen brightness up, move the phone closer, move it further away, wipe the camera, and eventually give up and send you the link instead.
Ticketing apps already know that screen brightness matters. Open a ticket in one and there’s a good chance the app will suddenly turn up the brightness of your entire screen. It works, but it’s a little jarring. Why brighten the entire phone when the QR code is the only part that needs it?
We have the technology! Make the QR code itself HDR and leave the rest of the interface alone.
The trick won’t rescue a mangled QR code or a filthy camera. On a supported phone, though, the white is plainly brighter. My hope is that this gives the scanner a better chance when you’re standing in the sun.
I wanted to use this elsewhere, but before building it into anything I thought a standalone tool would be a good way to find out how difficult it was to actually use. This is more compute-intensive than generating a standard QR code, so there were a few things to figure out.
Why is it a video?
The mildly ridiculous part is that you can’t just generate a very white PNG.
Normal web content sits within the display’s standard brightness range. Setting a pixel to #ffffff only means “as white as normal white”. There isn’t a secret #moreffffff.
To get above that range, the content needs to use the display’s HDR headroom. For this project, the simplest reliable way to do that is with HDR video.
The result from my generator is therefore a one-second MP4 containing a single frame:
- 768×768 pixels
- HEVC Main10
- 10-bit colour
- BT.2020 colour primaries
- PQ HDR
- one frame per second
- no audio
The files are surprisingly small. A normal result is around 15–25 KB for a video of a stationary QR code.
Building it
I just wanted it to be a simple tool. You enter a URL and get a file.
You can also upload an existing QR code. The service reads its payload and generates a clean HDR version rather than trying to transform the pixels in the uploaded image. That avoids carrying across compression, styling or damage that might make the final code harder to scan.
The web interface and API run on Cloudflare Workers. A render request is recorded in D1 and passed through a Cloudflare Queue to a container running FFmpeg. The generated MP4 is stored temporarily in R2 and returned through a shareable result page.
The architecture for displaying a very bright square is:
Worker → D1 → Queue → Container → FFmpeg → R2
This is perhaps more infrastructure than one would hope to need for a QR code. FFmpeg and HEVC encoding require a container and take some time to process, so they aren’t a good fit for a normal Worker request. Cloudflare Containers let the rendering step live alongside the rest of the application, while the queue handles container startup and keeps the browser request from sitting open.
In normal use, a warm render takes under two seconds.
Getting “HDR” right
Producing an HEVC file with some HDR metadata isn’t enough by itself.
The source frame needs to contain real HDR luminance values. Converting an ordinary eight-bit white PNG into a ten-bit video may give you a file that claims to be HDR while still displaying its white at ordinary SDR brightness.
The renderer generates a high-bit-depth frame and encodes it using the PQ transfer function, with the background mapped above standard reference white. The black QR modules remain black, preserving as much contrast as possible.
I validate each change in a few different ways:
ffprobeconfirms the codec, pixel format and HDR metadata.- The generated file is checked for BT.2020 and PQ signalling.
- A frame is extracted from the finished MP4.
- OpenCV scans that frame and confirms the original QR payload survived.
- Finally, it is tested on an actual HDR-capable Apple display to make sure the white really is brighter.
That last check matters. A technically impressive collection of metadata isn’t very useful if the result doesn’t visibly work.
A few small bugs along the way
The rendering pipeline worked fairly quickly. As usual, some of the less glamorous details took longer.
Cloudflare Static Assets initially swallowed the shareable /r/:jobId routes and served the frontend fallback instead of the result page. The fix was one routing configuration change, after a disproportionate amount of confusion.
The first interface also came out looking too much like an AI-generated startup landing page: enormous serif headline, excessive spacing and all. I replaced it with a more compact technical-tool design.
That said, it’s still a perfunctory little website and probably retains some of that AI lowest-common-denominator feel. That’s fine. A simple interface that accepts a URL and returns a video is all I wanted.
There was also the usual work around rate limits, expiring old R2 objects, retrying container startup failures and keeping deployment credentials out of the repository. None of that is particularly exciting, but it is the difference between a demo that worked once and a small service I can leave running.
What it’s for
It’s poor UX to make someone manually increase their screen brightness just so another phone can scan a code.
As mentioned above, I’m also surprised that massive ticketing companies still solve this by increasing the brightness of the entire screen. They already control the app and the ticket display.
They could light up the code and nothing else, although this is still a little hacky and, as mentioned above, difficult to generate synchronously.
Basically, any time one phone is showing a QR code to another, whether at ticket gates, invitations or check-ins, this could be useful. These moments rarely happen under controlled conditions. You’re outside, there’s a queue behind you and the phone is sitting at 30 percent brightness.
It won’t work everywhere. HDR playback varies between devices and browsers, and unsupported displays will not provide the same brightness boost. If you’re building it into a real product, you still need a normal QR code as a fallback.
But as a standalone generated asset, it is pleasingly simple:
- Enter a URL or upload a QR code.
- Wait a second or two.
- Download a tiny HDR MP4.
- Display it using a normal looping, muted, inline
<video>element.
You can try it at hdrqr.jamesdonnelly.au.
It is a fairly elaborate way to make a white square whiter, but it works.