[ANN] Coder and Decoder of QR codes

Hey guys!! I’m excited to announce two packages that I’ve recently completed as main works of the OSPP’22 project.

Features of QRCoders

QRCoders.jl is a rewrite of QRCode.jl that was discussed here before.

The latter provides a very nice sketch of realization, but has defects with correctness and performance. So I correct these errors and provide a more flexible and efficient implementation, with the help of @johnnychen94.

Here are examples of version 1 and 40(max version) respectively.

using BenchmarkTools
using QRCoders: qrcode
using QRCode:qrcode as orgqrcode
mat1 = @btime qrcode("Hello world!"; compact=true);
mat2 = @btime orgqrcode("Hello world!"; compact=true);
mat1 = @btime qrcode("Hello world!"^190; compact=true);
mat2 = @btime orgqrcode("Hello world!"^190; compact=true);

Benchmark results:

repo version cost
QRCoders.jl 1 149.392 μs (370 allocations: 32.28 KiB)
QRCode.jl 1 4.040 ms (175888 allocations: 8.43 MiB)
QRCoders.jl 40 21.700 ms (29459 allocations: 4.84 MiB)
QRCode.jl 40 509.677 ms (19128212 allocations: 922.52 MiB)

As shown above, the memory is about 200 times less than the original one, and the time-cost is about 30 times less. In fact, almost all functions are rewritten to achieve this.

Features of QRDecoders

First and foremost, two algorithms are implemented for error correction:

The first one is written with optimized performance (benchmark results comparing with other decoders will be added in the later works).

Future works

The Berlekamp-Massey algorithm needs more tricks in detail. We might optimize the performance in the future, while there are some more worthwhile works.

For image processing, the decoder can only deal with standard QR image. The next plan is to enhance the image detecting ability, so that it can deal with more complex cases.

There are much more to do with QRCoders.jl as well. For instance, the QR code style has a creative room that beyond one’s imaginations, like


This is the first package that I developed, and it goes well smoothly thanks to @johnnychen94.
Look forward to feedback and suggestions, and feel free to criticize or discuss.

33 Likes

I’m happy to discuss with you the recent work of QRCoders!! Most of them follow the suggestions of a previous discussion (2019). Now I am writing this post for more advice.
Moreover, if you also find these ideas interesting, welcome to contribute! Feel free to give your valuable suggestions to help improve this package!

New features:

  1. Introduce a new type QRCode as suggested by @Chris_Foster in the comment. The new type do help in the design of styles!

  2. Unicode plot, either by UnicodePlots.jl suggested by @carstenbauer, or by Unicode characters ['█', '▀', '▄', ' '] mentioned in issue#25
    image

  3. Add support for .jpg and .gif images

    exportqrcode(["Hello", "Julia", "!"], "hello.gif")
    

    hello

More importantly, the styling plan is drawn on the schedule! Here is a draft.

Pixel drawing

Most of the QR code styles follow the same strategy: First build the QR code, then beautify the image.

However, pixel drawing use a strategy of free-bits-calculation and error-correction-bits-modification, to similar the image by real QR-bits. This requires some decoding tricks. In this regard, I am very much grateful to Saar Ibuki for the helpful and creative advice.

Here are applications by pixel drawing:

  1. Direct drawing

    using QRCoders, TestImages, ImageTransformations
    img = testimage("cam")
    code = QRCode("Hello Julia!", version=13)
    inlen = fitimgwidth(code)
    bitimg = .!(Bool.(round.(imresize(img, (inlen, inlen)))))
    mat = imageinqrcode(code, bitimg, rate=1, fillaligment=true)
    mat |> exportbitmat("cam.png")
    
  2. Enlarging the logo in the center of an image
    logo-QRCoders
    In general, the logo should be small, otherwise it might destroy the message. However, by pixel drawing, the logo itself stores part of the message, and thus the size can be enlarged.

  3. Playing games – Tetris

    1. Convert the image to a Union{Bool, Nothing} matrix: set value 1 for the background, set 0 for the light block, and set nothing to the free area
    2. Generate a QR matrix by pixel drawing
    3. Color the QR code matrix by the image
  4. Playing videos – BadApples
    badapple_fullinside

  5. More idea, like Nest QR codes
    logo-QRCoders

Due to my limited time and energy, I am currently focusing on the implementation of this part only. When QRCoders can plot images, it can play everything in fact!

Strategies for other styles

  1. Colorful QR Code

    • For colorful pixels: use RGB values instead of black and white pixels
    • For gradient drawing: treat the black pixels as transparent ones, then draw the QR matrix onto the background
  2. Scatter plot: use scatterplot from UnicodePlots, or use the Kronecker product kron which served as a map of pixels to matrices

  3. Theme plot, like the Pac-Man
    202916368-688fa7bd-5082-46c0-898f-d64232c5f860

    1. Draw the usual QR code
    2. Randomly select some continuous black pixels to connect them as walls
    3. Randomly select some 2x2 black pixels to replace with Pacman
    4. Replace other black pixels with beans

    The package Luxor.jl, mentioned in this comment, might be a good choice for handling svg files.


BTW, the style plan proposed in issue#33 is also asked in the juliacn-meetingup-website.
If you have good ideas suitable for newcomers, welcome to the bounty issue to ask more questions. :grinning:

6 Likes