<< Home

Yes We Scan: the backstory

It starts with a printervention

I started out wanting to make an old Canon photo printer usable by my parents and in-laws. So I made printervention.app, which I wrote about before.

While working on that app, I remembered I also had an old Canon USB scanner tucked away on a shelf. The last time I’d used that, I think I’d resorted to setting up a Windows 95 VM. But the same technology that powers printervention.app would clearly work for scanners too.

How does it work?

The core of both apps is the amazing v86, which emulates an x86 CPU — and the whole machine around it — in a browser. It compiles machine code to WebAssembly modules at runtime, which is rather clever and makes the whole thing tolerably quick.

So I set up an emulated v86 machine to run SANE (Scanner Access Now Easy) on Alpine Linux, discreetly, in your browser.

The interface between your browser and SANE is provided by a small custom C program that Claude helped write. This connects to the scanner, provides a JSON dump of its settings we can use to build a settings UI, and streams scan data over the hypervisor console (hvc0) in v86.

Back in the browser, that scan data is received and either written to a <canvas> context (when previewing), or sent to a Web Worker running wasm-mozjpeg or fflate, compressing it to JPEG or PNG on-the-fly.

Bridging v86 and WebUSB

I’d already got the USB side of things working for printervention.app:

What’s next

The app has only been tested on my CanoScan LiDE 100, but I have some hope that it will work for a range of other models. If you try it, do let me know. I must repeat my apology that I haven’t so far open-sourced any part of the code that I don’t have to.

George MacKerron
May 2026

<< Home