11

I am doing some work with QR codes, and to test my code, I was comparing it against the example QR code at the top of the Wikipedia page for QR codes:

While working on my code to attempt to re-generate this QR code and ensure I got the same output, I encountered a surprise. In the QR standard Section 4.15 says that remainder bits must be appended to the code data, and they must all be zeros. I believe the Wikipedia example is using ones.

My script (code at the bottom of this question) generates the following QR code when attempting to recover Wikipedia's QR code:

You will notice that almost all the pixels are identical. The exception is in the lower left. At the far left edge, immediately above the lower-left Finder target, my script produces a shape that looks like a left-facing pitchfork, or the number 3. The Wikipedia one does not. The discrepant pixels are exactly those pixels marked with the "X" in this other Wikipedia image, indicating them as the remainder:

Now, based on this, the Python QR code library could be wrong, or Wikipedia could be wrong. The QR Code Mask (which XORs the code with one of 8 predefined patterns) makes it hard to tell which code is right. We want to know which code is encoding zeros at those 7 pixels. To work that out, my script (again, code below) runs through all 8 possible Mask patterns, un-masks them, and shows the codes. They should all mostly match (proving that the unmasking was successful), and indeed they do, and they show pure white in that region:

And in a QR code, white is a "0" bit. This leads me to conclude that my generator is correctly using zeros for the remainder, and Wikipedia's generator did not.

Of course, these remainder bits are meaningless and should be ignored by any QR decoder. That's why this mistake has persisted for so many years on Wikipedia. But a standard is a standard, and the example QR code at the top of the page ought to be a fully standard-compliant one.

Am I correct in believing that I have demonstrated that Wikipedia has a mistake? Does my logic (and code) check out?

Code here, relies on qrcode:

import qrcode
import numpy as np
import matplotlib.pyplot as plt

payload = "http://en.m.wikipedia.org"
version = 3
QR_size = 17 + 4 * version
# Generate a list of the 8 QR codes with the 8 possible masks
all_8_codes = []
for mask_num in range(8):
    code_maker = qrcode.QRCode(version = version,
                               error_correction = 3,
                               mask_pattern = mask_num)
    code_maker.add_data(payload)
    code_maker.make()
    all_8_codes.append(np.array(code_maker.modules))
plt.title(f"Wikipedia's QR code (Almost)")
plt.imshow(all_8_codes[1], cmap = "Greys")
# Across the 8 codes, identify any pixels which are constant and should not get the mask
anti_mask = np.zeros([QR_size, QR_size])
for i in range(QR_size):
    for j in range(QR_size):
        px_cast = [arr[i][j] for arr in all_8_codes]
        anti_mask[i][j] = all(x == px_cast[0] for x in px_cast)
# Iterate through the 8 codes, re-applying the XOR mask and therefore removing it
for mask_num, code in enumerate(all_8_codes):
    # Using the library, get the lambda function that indicates whether a bit flips
    mask_lambda = qrcode.util.mask_func(mask_num)
    for i in range(QR_size):
        for j in range(QR_size):
            # Don't apply the mask to areas identified as anti-mask
            if not anti_mask[i][j]:
                code[i][j] ^= mask_lambda(i,j)
    # Show what should be 8 nearly-identical codes with the masks removed
    # This proves we successfully demasked the message.
    plt.figure()
    plt.title(f"Demasked {mask_num}")
    plt.imshow(code, cmap = "Greys")
plt.show()

Edit: as a second point of reference, it appears this post has been linked on the Talk page for that Wikipedia article. Responses there, should they appear, could be insightful for this question. Link: https://en.m.wikipedia.org/wiki/Talk:QR_code

2
  • 2
    Is this essentially the same as your previous closed question? (note: I do not agree with the closure, but it may have been preferable to edit/reopen it with the Python code included) Commented Oct 9 at 15:47
  • 3
    @wim It is sort of a spinoff. Before I identified a discrepancy, but now I have used code to go from a discrepancy to an identification of which of the two systems is incorrect, which is a stronger claim. The total lack of interaction on the previous question made it unclear to me exactly what the issue was, so I figured I should start from a clean slate since the nature of the question is quite different, despite coming from the same roots. Further, the previous question asked effort of answerers to identify A vs B being wrong. This one is only asking validation of my own identification. Commented Oct 9 at 16:00

1 Answer 1

5

You are correct. The barcode that you generated, titled "Wikipedia's QR code (Almost)", exactly matches the output from my QR Code generator library, module for module. Since my code is an independent implementation compared to the Python qrcode package that you are using, I came to the same understanding from reading the QR Code specification. So the example barcode on Wikipedia must be wrong, and it must have non-zero junk in its remainder bits.

Screenshot of my output:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect! Exactly the confirmation I was looking for. If only the Wikipedia barcode had reported its provenance for comparison. For now, this should suffice for confirming that my identification of the problem is legitimate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.