How to scan QR codes without camera or phone

Posted in Development, Open Source, Command line, Linux, 2 months ago Reading time: 3 minutes
image

QR codes are everywhere. Easy to scan with a phone. But what if you want to decode a QR on your laptop instead of your phone, without a camera?

I was working on an app with generated QR codes containing login links. But my local development environment is not reachable from my phone, so the links from the QR code didn't work. Not very practical. So I needed a way to scan the QR directly on my laptop. I succeeded but it was slightly less easy than I hoped.

Using the command line tool zbarimg you can decode a QR-code in an image file.

If you're using Debian or derivitive like Ubuntu you can install the tool using:

sudo apt install zbar-tools

Now you can easily decode files with QR codes:

zbarimg screenshot.png 

Works fine, but I had to test a lot of QR codes during development and testing. Making a screenshot, run the tool, and copy the result got old soon. So I set out to automate things further, of course.

For screenshots I've been using the great tool flameshot for a while. Check it out, if you haven't already. It has a GUI but like a good Linux application also a command line interface so you can use it in scripts.

Installing flameshot:

sudo apt install flameshot

Then create a new file named qr-scan with the following contents:

#!/bin/bash

flameshot gui -r \
    | zbarimg - \
    | sed "s/^QR-Code://g" \
    | xclip -selection clipboard

Make it executable using chmod +x qr-scan and execute it with ./qr-scan. Put it in a directory that's in your PATH and you can run it from everywhere.

The script works like this:

  • Execute flameshot with the gui parameter to show the gui to make the screen selection. The -r parameter (for raw) will send the selection as raw png data to stdout
  • The output is piped through zbarimg which decodes the QR code
  • The output of zbarimg is cleaned up by sed
  • The final result is copied to the clipboard using xclip

Well, I hoped so, but I bumped into issues. Quite a few QR codes turned out to be unreadable by zbarimg. It seemed to be related to the payload size. But my phone could decode them with no problems. The error output was extensive but rather useless for finding a solution.

scanned 0 barcode symbols from 1 images in 0 seconds


WARNING: barcode data was not detected in some image(s)
Things to check:
  - is the barcode type supported? Currently supported symbologies are:
	. EAN/UPC (EAN-13, EAN-8, EAN-2, EAN-5, UPC-A, UPC-E, ISBN-10, ISBN-13)
	. DataBar, DataBar Expanded
	. Code 128
	. Code 93
	. Code 39
	. Codabar
	. Interleaved 2 of 5
	. QR code
	. SQ code
  - is the barcode large enough in the image?
  - is the barcode mostly in focus?
  - is there sufficient contrast/illumination?
  - If the symbol is split in several barcodes, are they combined in one image?
  - Did you enable the barcode type?
    some EAN/UPC codes are disabled by default. To enable all, use:
    $ zbarimg -S*.enable <files>
    Please also notice that some variants take precedence over others.
    Due to that, if you want, for example, ISBN-10, you should do:
    $ zbarimg -Sisbn10.enable <files>

A short duckduckgo search showed me I was not the only one with this problem. And thankfully I found a good solution on a Stackoverflow page.

Imagemagick provides the super cool convert command which enables you to convert almost anything into almost anything with all kinds of advanced magic. Apparently you can also use it to make QR codes better readable for zbarimg.

Install imagemagick with:

sudo apt install imagemagick

The following code is copied from the SO page above:

convert input.png +repage -threshold 50% -morphology open square:1 output.png
zbarimg output.png

I did not have time nor motivation to find out what this does in detail. As long as it works for zbarimg right?

If we implement this step into the qr-scan script we get:

#!/bin/bash

flameshot gui -r \
    | convert - +repage -threshold 50% -morphology open square:1 - \
    | zbarimg - \
    | sed "s/^QR-Code://g" \
    | xclip -selection clipboard

Related posts

image
Thirty years of Debian!

Today, August 16 2023, marks the 30th anniversary of the Debian GNU/Linux distribution. It was the first linux version I installed after ditching Windows completely. And today, Debian is still very relevant.

Read more →

image
Smart generics in PHP

Type hinting in PHP8 has become powerful but it still has limitations. In this article I discuss some ways to use Generics to overcome some of these limitations.

Read more →

image
How to build a complete Mastodon API Client

Mastodon has an extensive API, but unfortunately no openapi spec. It was quite a challenge to build an API client and implement all methods and entities. Here's how I did it.

Read more →

image
Pass, the standard Unix password manager

Many people nowadays are using a password manager, like LastPass, 1Password, Keepass, etc. Not many are familiar with "pass, the unix password manager". That's a shame, because I think it is the best password manager for the tech savvy linux/unix user. Let me tell you why.

Read more →