[HN Gopher] Reading QR codes without a computer
       ___________________________________________________________________
        
       Reading QR codes without a computer
        
       Author : input_sh
       Score  : 458 points
       Date   : 2024-01-22 09:21 UTC (13 hours ago)
        
 (HTM) web link (qr.blinry.org)
 (TXT) w3m dump (qr.blinry.org)
        
       | DerCommodore wrote:
       | Fun article
        
         | ThePowerOfFuet wrote:
         | This kinda comment is best on reddit, not here. Just use the
         | upvote button and keep the SNR high!
        
           | subtra3t wrote:
           | I like how you were polite instead of lashing out at them
           | and/or flagging the comment.
        
       | Aachen wrote:
       | I tried reading them manually about ten years ago, but gave up
       | because of the mask. The mask pattern needs to be applied (xor)
       | before you can even tell as much as the data type...
       | 
       | Does anyone know how much it actually helps QR code readers to
       | have this mask pattern applied?
       | 
       | Last month, I tried to find out what the optimal error correction
       | setting is (answer: none, if the matrix isn't damaged, like in my
       | use-case where it's shown on a screen), which wasn't easy to
       | find. I didn't find anyone who actually went out into the real
       | world and tried out different settings and different scanning
       | implementations to see what the effect is of choosing a good mask
       | or choosing a good error correction value. In the end, a
       | theoretical answer was enough for my application because I can
       | assume the QRs to be pristine, but in a perfect world we also
       | wouldn't need a mask setting. I then tried to do some research of
       | my own by reading a small QR off my screen with different error
       | correction levels and an intentionally shaking camera to simulate
       | read issues when someone points a smartphone, but found no
       | significant difference between any of the settings. With there
       | being at least four alignment markers, a huge quiet area, and a
       | "timing pattern", does it really matter if there are white blobs
       | due to not having a mask?
       | 
       | (The secondary reason why I gave up trying to read QRs visually
       | is because I noticed they always have the URL written below as
       | fallback anyway. Since then, I did see a few times where there
       | was no fallback, but it's very rare)
        
         | Retr0id wrote:
         | The error correction is funny. If you don't use it, your
         | message takes up less space, and the QR is smaller. If you have
         | a fixed space to fit it in (e.g. printing to a sticker), that
         | means your pixels can be physically bigger. For reliable
         | reading, I found that physically bigger pixels helped more than
         | the error correction itself.
         | 
         | Depending on the length of your message, sometimes you can turn
         | up the error correction level without impacting the final QR
         | dimensions, and in those cases it's a win/win.
        
           | londons_explore wrote:
           | This is actually "cameras can't focus close, and QR scanners
           | aren't good at seeing a code which is tiny in the frame".
           | 
           | By making the pixels of the code bigger, the camera can be a
           | bit blurry to get the code big enough, and then it'll read.
        
             | Retr0id wrote:
             | I mean, that's kinda the whole point? The precise details
             | of the optic path don't really matter, bigger pixels will
             | always be easier to resolve.
             | 
             | One might reasonably expect error correction to help with
             | the decode of blurry inputs, but that wasn't really the
             | case in my experiments.
        
               | londons_explore wrote:
               | The 'proper' fix is to either engineer cameras that can
               | focus closer, or to engineer barcode scanning apps to be
               | able to see a code which is small somewhere in the frame.
               | 
               | I think people are working on both as we speak.
        
               | Retr0id wrote:
               | It doesn't matter how objectively good your
               | camera/decoder is, in absolute terms. There will always
               | be some minimum size or maximum distance, where the
               | detail can no longer be resolved (or errors no longer
               | corrected)
        
               | subtra3t wrote:
               | Why? Is this something that's a side effect of some
               | irrefutable physics law or a limitation of the current
               | technology?
        
               | Retr0id wrote:
               | Both. You can't have a measurable feature smaller than
               | the Planck length, but that's not relevant to QR decoding
               | in any practical sense.
               | 
               | As for the practical limits, try using your phone to take
               | a picture of something very far away, or very tiny, and
               | see what happens.
        
               | londons_explore wrote:
               | If we're talking theory, the pixel size doesn't matter -
               | it's the amount of information encoded in the QR code
               | that matters (ie. excluding ECC bits!). In turn, that
               | means it is theoretically possible to decode a QR code
               | where each 'pixel' of the code is smaller than the pixel
               | of the camera sensor observing the code.
               | 
               | While it is theoretically possible, nobody has yet done
               | so...
        
           | komlan wrote:
           | Physically bigger pixels help a lot indeed. The encoding mode
           | also helps make pixels bigger.
           | 
           | This is very convenient when you control the QR reader and
           | need to represent long numeric identifiers like UUIDs.
           | 
           | For example:
           | 9728983f-7d7d-4189-b624-f92781e36650 (lowercase UUID):
           | => length=36, 15 pixels between markers
           | JWM9GFVXFN0RKDH4Z4KR3RV6A0 (base32 UUID):         =>
           | length=26, 11 pixels between markers
           | 9728983F-7D7D-4189-B624-F92781E36650 (uppercase UUID):
           | => length=36, 11 pixels between markers
           | 200924207194334734815443970355691218512 (decimal UUID):
           | => length=39, 7 pixels between markers
           | 
           | The uppercase UUID has bigger pixels because it used a
           | different encoding, and gets the same results as the shorter
           | base32 uuid.
           | 
           | The decimal UUID is a _longer_ string, but results in _much_
           | bigger pixels because it can use numeric encoding.
           | 
           | I have a QR code base attendance tracker [1], where attendees
           | show the code [2] on their phones (glares, etc.), in bad
           | lighting conditions, etc. Bigger pixels means scanning stays
           | quick. Same with parcel tracking [3] where field agents might
           | need to scan QR codes in barely-lit hallways, etc.
           | 
           | [1] https://workspace.google.com/marketplace/app/qr_code_pass
           | _fo...
           | 
           | [2] https://share.darkaa.com/!qntvtzNPWJ
           | 
           | [3] https://admin.trak.codes/
        
         | RugnirViking wrote:
         | Last year I did some experimentation along these lines and I
         | also found that no error correction was best, at least when 3d
         | printing QR codes. I was trying to find how small I could print
         | it and still have it be detectable. Like the sibling comment, I
         | suspect it is because of individually larger pixels.
        
           | Aachen wrote:
           | The problem with that, as I understand it, is that your 3d
           | print (or any print or screen) cannot get damaged at all. The
           | pixels being bigger makes it easier to scan ...when it's
           | fully in view and fully intact. Any pixel fails, and you can
           | never recover the original data (besides some guesses, e.g.
           | if the protocol identifier gets damaged a la htwps://)
           | 
           | Error correction doesn't seem to be for easier scanning, but
           | for errors that might occur
           | 
           | (... and stupid logo overlays)
           | 
           | but this information is annoyingly hard to find. Hence my
           | question about the mask xor overlay: does that actually help?
           | Did anyone try it, or did it just sound like a good idea?
        
             | RugnirViking wrote:
             | the idea that a single pixel of the design would get
             | damaged absent the rest seems unlikely. What seems to be
             | more common is that a direction of light/some flaw in the
             | printing process causes many/all pixels to be flawed in the
             | same way past some threshold.
        
         | basil-rash wrote:
         | The error correction isn't meant for folks like us who think
         | about things like "how can I make this message smaller to
         | increase the readability of the QR code", it's for the people
         | that take their entire tracking parameter-infected URL and dump
         | it into a version 25 (117x117) code and plaster it onto a huge
         | sign out front where a bird promptly shits on it and a teenager
         | slaps a sticker on it and somehow the data remains.
        
       | cyco130 wrote:
       | Slightly off topic: One day in the late 90s or early 2000s, I
       | wanted to transfer the contents of my Atari 8-bit disks to my PC.
       | I did know about SIO2PC, a cable that converts between Atari's
       | SIO port and the PC's serial port and a piece of software to go
       | with it. But I didn't have the electronics skills to build one
       | (even though it is actually very easy).
       | 
       | So I ended up writing a Basic program on the Atari to read data
       | from the disk sector by sector and paint it on the screen (with
       | the large 4-color pixels of graphics mode 3). The Atari was
       | connected to the TV card of my PC and a Delphi program I wrote
       | was running on the PC that kept taking screen shots and trying to
       | decode the data from there. I quickly learned that empty sectors
       | threw off my pixel position calibration so I added a mask pattern
       | and a checksum. The sector address was also included. With that,
       | I was able to transfer all my disk contents to my PC. To this day
       | I consider it my greatest engineering achievement :)
       | 
       | Some ten years later, I went on to build an SIO2PC program called
       | AspeQt. A more up-to-date community fork called RespeQt is still
       | the most popular tool in that category used by the community. It
       | even has its own subforum on AtariAge[1].
       | 
       | [1] https://forums.atariage.com/forum/184-respeqt-sio2pc-
       | softwar...
        
         | efdee wrote:
         | Just wanted to say this sounds like a fun project and you must
         | have been pretty happy when it ended up working out!
        
           | cyco130 wrote:
           | I was so happy that I'm still boasting about it some 25 years
           | later!
        
         | xnx wrote:
         | I think there's definitely a future for this type of data
         | exfiltration via display as otherwise locked-down systems
         | become more common.
        
         | blakesmith wrote:
         | Reminds me of how the first generation iPod firmware and keys
         | were reverse engineered. They blinked out bit patterns on the
         | LCD backlight and used a camera to read the data in!
         | https://mastodon.social/@bagder/111538350617290554
        
       | NeoTar wrote:
       | Stupid 'trivia' question, but could someone generate the
       | 'darkest' (most black pixels) and 'brightest (most white pixels)
       | QR codes possible?
        
         | lekevicius wrote:
         | It's of course possible, but the spec is trying to avoid this.
         | There are multiple "masking patterns", and the algorithm should
         | choose one that gives fewest "penalty points". Large single
         | color areas are a lot of penalty points, so QR algorithm is
         | trying to avoid them.
        
           | NeoTar wrote:
           | Yes - I think it would be interesting to see them actually
           | produced. Could we get to 60% white pixels? Or 75%?
           | 
           | There could maybe be two solutions:
           | 
           | * Darkest/Brightest allowed by the QR algorithm,
           | 
           | * Darkest/Brightest technically valid, which would would not
           | be chosen by the algorithm (i.e. if one manually chooses the
           | masking pattern.
           | 
           | Perhaps also more solutions - 'Darkest/Brightest recognized
           | by software X/Y/Z'
        
           | Retr0id wrote:
           | An encoder _should_ try to avoid them, but in theory it doesn
           | 't have to, right?
        
             | lifthrasiir wrote:
             | Yeah, it's not mandatory. The specification itself
             | recommends a very concrete algorithm though, and one of its
             | criteria is literally the average density [1].
             | 
             | [1] https://github.com/lifthrasiir/qr.js/blob/52f0409a22c5e
             | ce6a5...
        
       | ajsnigrutin wrote:
       | > So is the rest all content? Not quite! There is also error
       | correction, which is used to make sure that the QR code can still
       | be read even if some parts are damaged, blurry, or missing. The
       | error correction is generated by some fancy math, and we don't
       | care about it here for the purpose of reading it by hand.
       | 
       | This should be explained better... I mean sure, the math can be
       | hard.. but is the error correction appended at the end? After
       | every byte? In the middle? Can we still read a qr code by hand if
       | it has error correction (assuming it's not damaged, and we can
       | skip the math part?)?
        
         | vrighter wrote:
         | the data in the code is encoded as a bitstream using possibly
         | different alphabets, byte is just one of them.
         | 
         | Then, depending on the size and error correction level (not
         | covered in the article where this is decoded from) the
         | bitstream is split up into blocks, ecc data is calculated for
         | both, and then the blocks are interleaved.
         | 
         | So this method _will_ fail for any qr version above 5 for any
         | level of ecc, and 3-5 with high levels of ecc.
        
         | andirk wrote:
         | Barcodes use the last digit as a checksum. The checksum is some
         | adding up the numbers and multiplying or something, then % 10
         | (only 0-9 possible values). As you can see with this math, the
         | error checking has a 1/10 of a chance of coincidentally showing
         | a correct checksum in cases where the data is incorrect. Either
         | way, that last digit on barcodes is insignificant to the actual
         | product's unique barcode ID.
         | 
         | Fun story: The barcode was ripped and the checksum # was frayed
         | off of an item I was returning to Home Depot. I frantically
         | tried to do the math quicker that the checker could manually
         | look it up. But they won and I'll never forget it.
         | 
         | https://www.gs1.org/services/how-calculate-check-digit-manua...
         | 
         | https://www.simplybarcodes.com/barcode_check_digit_calculato...
        
           | epcoa wrote:
           | A few common barcodes including UPC work this way but mostly
           | this is the exception. The 2D ones being discussed here like
           | QR and Aztec use actual error correcting codes, so none of
           | them. In the linear space Codabar (libraries) is a widely
           | used example that doesn't. GS-128 doesn't, etc.
        
           | js2 wrote:
           | Feynman could've done it, with a little luck anyway. :-)
           | 
           | https://www.ecb.torontomu.ca/~elf/abacus/feynman.html
        
           | greengrocer4567 wrote:
           | When I worked at a grocery store in the 2000s, you didn't
           | need the checksum digit when keying in a barcode by hand. In
           | fact, manually entering the checksum digit would result in a
           | "product not found" error.
           | 
           | So I wonder if the checker had to manually look anything up,
           | assuming it was only the checksum digit that was frayed off.
           | 
           | Perhaps some POS systems do require the checksum digit for
           | manually-entered barcodes, though.
        
             | akoboldfrying wrote:
             | >In fact, manually entering the checksum digit would result
             | in a "product not found" error.
             | 
             | That is hilarious to me. The obviously safer approach of
             | checking the check digit was not merely neglected, but
             | actively forbidden.
        
         | amenghra wrote:
         | An Artisanal QR Code [1] shows how to compute the checksum by
         | hand using arithmetic similar to a long division. There are
         | actually two slightly different codes (Reed-Solomon and BCH)
         | for different pieces of information.
         | 
         | [1] https://www.quaxio.com/an_artisanal_qr_code.html
        
       | SushiHippie wrote:
       | Related submissions:
       | 
       |  _Decoding small QR codes by hand (2012)_ -
       | https://news.ycombinator.com/item?id=36173441 - Jun 2023 (69
       | comments)
       | 
       |  _How a QR code works_ -
       | https://news.ycombinator.com/item?id=32837565 - Sep 2022 (114
       | comments)
       | 
       |  _Creating a QR Code step by step_ -
       | https://news.ycombinator.com/item?id=24119124 - Aug 2020 (41
       | comments)
       | 
       |  _Creating a QR Code step by step_ -
       | https://news.ycombinator.com/item?id=18360847 - Nov 2018 (34
       | comments)
        
       | yreg wrote:
       | My friends often joke that a person who is checking our tickets
       | is able to do precisely this mentally in their head - when that
       | person is satisfied by seeing a QR code rather than scanning it.
       | 
       | It became very popular over here with the Green Passes (EU
       | Digital Covid Vaccination Certificates). Waiters, etc. were
       | supposed to check whether the guests are vaccinated, but 99% of
       | them just demanded any random QR code to be shown to them, took a
       | look at it and considered it done.
       | 
       | Unless we are a country of hidden math geniuses :)
        
         | bluGill wrote:
         | It would probably only take a week of training/practice for
         | someone to get good enough to read them manually. Particularity
         | if the vaccination codes have a common pattern - the same mask,
         | format information and the like. I would expect you can look at
         | a few areas to see if the person is vaccinated (though this
         | wouldn't pick up on someone else's vaccinated status)
        
           | mr_mitm wrote:
           | There is a digital signature embedded in the QR code. No one
           | can verify that in their head.
        
             | bluGill wrote:
             | We don't need to verify everything though, just extract the
             | vaccinated/not field which is probably in the same location
             | on every QR code (or at least it should be possible to make
             | it in the same area), and maybe the name of the person the
             | QR code is for.
        
               | 418tpot wrote:
               | The signature is the whole point of the QR code though,
               | otherwise someone could just trivially create a QR code
               | that has their name and "vaccinated = yes".
        
           | tln wrote:
           | LOL, the EU's vaccination QR codes are 90+ modules wide, BASE
           | 45 encoded and compressed.
        
       | tamarlikesdata wrote:
       | How do you distinguish different encoding modes (numeric,
       | alphanumeric, byte, etc.) within the data region, especially when
       | dealing with a QR code that uses multiple encoding modes?
        
       | ao98 wrote:
       | Wonderful write up, thank you! One question I've been trying to
       | answer: I've been seeing more QR codes in the wild using dots
       | instead of squares, and rounded edges instead of hard corners.
       | 
       | All my research suggests these are reader implementation specific
       | and not guaranteed to work per the official spec.
       | 
       | But I find it hard to believe these codes are becoming more
       | prevalent if they aren't guaranteed to read.
       | 
       | Anyone have more info on this?
        
         | kqr wrote:
         | You'd be surprised how incompetent most adults are at what they
         | do. I'm sure some less technical person assumed QR reading
         | works the same way everywhere, tested it with their device and
         | went "Yess it works! Ship it!"
         | 
         | I also sometimes see QR codes that are inverted. Not all
         | readers detect them but many enough do that they end up in
         | print.
        
           | TonyTrapp wrote:
           | That being said, the QR code readers most people have in
           | their pockets already have to be able to deal with all sorts
           | of problems (blurry pictures, dust on lens, and many more
           | scenarios) that rounded corners are unlikely to have an
           | affect on any of them.
        
         | lights0123 wrote:
         | In reality,
         | 
         | - Apple's barcode reader
         | 
         | - Google's ML Kit
         | 
         | - and ZXing, probably behind most third party QR code scanning
         | apps
         | 
         | covers most QR code readers that users will actually use, so
         | testing them is fairly easy.
        
         | Isamu wrote:
         | Rounded corners is handled similarly to blurry images, one of
         | the main ideas is readers to be forgiving in what they accept,
         | and rely on the error detection bits to tell if it is way off.
         | With error correction you can tolerate stylistic mangling.
        
       | DeathArrow wrote:
       | Looking on Wikipedia I see that QR code was invented in 1994 by a
       | Japanese automotive components manufacturer to label car parts.
       | 
       | I wonder if QR code was invented today, could it be improved?
       | Maybe for compactness? Ease of read?
        
         | arccy wrote:
         | they would be hexagons
        
         | yreg wrote:
         | There's nothing stopping a new sufficiently better design. Bar
         | codes were already ubiquitous in 94 and they didn't prevent QR
         | codes taking off.
         | 
         | Maybe there's not that much left to improve. (unless changing
         | the concept drastically, e.g. NFC)
        
       | jr19mi wrote:
       | Great explanation of how to read QR codes, thanks for the write
       | up! Here's a nice one about 1D codes and how to decode your
       | average UPC codes you find on products in (American)
       | supermarkets:
       | 
       | https://scanbot.io/blog/how-do-barcodes-work/
        
       | nayuki wrote:
       | Someone's video on decoding from a decade ago:
       | https://www.youtube.com/watch?v=KA8hDldvfv0 (20 min)
       | 
       | My interactive web page on creating a QR code step by step (so
       | basically the inverse process):
       | https://www.nayuki.io/page/creating-a-qr-code-step-by-step
        
       | algem wrote:
       | pretty cool article
        
       | cybrox wrote:
       | Everyone praises the writeup itself but the fact that the article
       | dynamically generates all the graphics based on your input is
       | even more awesome!
        
       | Crypt0nomicon wrote:
       | You've got to watch out reading those QR codes with your mind as
       | you might contract a lethal mind-virus!
        
       | tylervigen wrote:
       | This made me very curious about the error correction. Apparently
       | you can design the codes to be variably durable from 7% to 30%
       | recoverable.[0] Neat!
       | 
       | [0] https://docs.beaconstac.com/en/articles/6018654-what-is-
       | erro...
        
         | kqr wrote:
         | Error correction is a fascinating topic. Shannon discovered in
         | the mid-20th century what the theoretical limit was, yet nobody
         | knew how to achieve it. When we suddenly got close in the 1990s
         | with the patent of turbocodes the community reacted with
         | disbelief!
         | 
         | Of course, that's what's enabled things like fast and reliable
         | mobile networks.
        
       | 83457 wrote:
       | My son, a freshman in high school, had an Apple Watch as his
       | first and only device for a while. One big annoyance for him was
       | not being able to scan QR codes that are common in high school
       | where we live. It is an affluent area and the assumption by many,
       | including teachers, is that all of the kids have phones. Not
       | required and they have computers, just comes up regularly.
       | 
       | I was considering doing a project with low quality camera to scan
       | QR codes. We got him a phone before I started down that path.
        
       | platzhirsch wrote:
       | This is useful. I tried to scan a QR code with my analog camera
       | and it didn't work. Now I can apply this algorithm to the
       | developed photo myself.
        
       | chipsrafferty wrote:
       | I would love a game where you learn to actually read QR codes by
       | eyesight - and quickly. Would be quite fun to have an impressive
       | and not very useful skill
        
         | poyu wrote:
         | Not sure if it's possible to be honest, it might be if you can
         | sit down with a pen a paper. But again we've seen human perform
         | seemingly impossible tasks before, so who knows.
        
           | Sohcahtoa82 wrote:
           | I've always wanted to see someone encode/decode Base64 in
           | their head.
           | 
           | At best, I've learned to recognize a base64 string that
           | begins with "eyJ" is likely JSON.
           | 
           | Also, if you asked me what the base64 encoding of "password"
           | is, but if you showed me "cGFzc3dvcmQ=" and asked me what the
           | decoded value is, I'd recognize it as "password". Though you
           | could probably change a few digits and fool me.
        
       | ehsankia wrote:
       | Semi-related, there was a recent puzzle (part of an offshoot of
       | the 2023 Mystery Hunt), which required you to decipher a really
       | broken QR code by hand (too far for error correction to work). We
       | ended up looking at all the guides listed in this comment
       | section, and while they were useful, none were super great. It's
       | always nice to have more detailed articles like this, and this
       | one definitely seems very polished!
       | 
       | Here's the puzzle for anyone curious, though the QR code
       | deciphering comes in the 2nd half:
       | https://puzzles.mit.edu/2023/abcde.puzzlefactory.place/puzzl...
        
       ___________________________________________________________________
       (page generated 2024-01-22 23:00 UTC)