Reverse printing the QR Code in the terminal

TL;DR

There’s an update to Terminal QR Code with Unicode characters.

In post Terminal QR Code with Unicode characters I introduced a small program to print QR codes in the terminal, leveraging some clever Unicode characters.

Then I used it and I got mixed results. Using the camera from my smartphone, the QR code was being read fine. Using another application from the same phone… no. I guess they are using different libraries, and the latter program has a less advanced algorithm.

It turned out that the chocking program was expecting to read black contents on a white background, whereas the camera was fine with the reverse too (white on black). So I introduced a little update to the program to address this, setting the reverse option to a true value because… I like my terminal windows to have a black background.

The code has been updated but it’s still in its former location:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';

use Text::QRCode;

sub terminalize ($encoded, $reverse = 1) {
   state $direct_char_for = [
      ' ',                    # 0
      "\N{LOWER HALF BLOCK}", # 1
      "\N{UPPER HALF BLOCK}", # 2
      "\N{FULL BLOCK}",       # 3
   ];
   state $c2i = sub ($c) { $c eq ' ' ? 0 : 1 };

   my @char_for = $direct_char_for->@*;
   @char_for = reverse @char_for if $reverse;

   my $first_row_id = 0;
   my @output;
   while ($first_row_id <= $encoded->$#*) {
      my $first_row = $encoded->[$first_row_id++];
      my $second_row = $first_row_id <= $encoded->$#*
         ? $encoded->[$first_row_id++]
         : [ (' ') x scalar($first_row->@*) ];
      push @output, join '', ($char_for[0] x 2), map {
         my $id = $c2i->($first_row->[$_]) * 2 + $c2i->($second_row->[$_]);
         $char_for[$id];
      } 0 .. $first_row->$#*;
      $output[-1] .= $char_for[0] x 2;
   }
   my $blank = $output[0] =~ s{.}{$char_for[0]}grmxs;
   return [$blank, @output, $blank];
}

binmode STDOUT, ':encoding(utf-8)';
say for terminalize(Text::QRCode->new->plot(shift // '!'))->@*;

Local version here.

I guess this is it for today, stay safe!


Comments? Octodon, , GitHub, Reddit, or drop me a line!