Terence Eden’s Blog<h2>Why are QR Codes with capital letters smaller than QR codes with lower-case letters?</h2><p><a href="https://shkspr.mobi/blog/2025/02/why-are-qr-codes-with-capital-letters-smaller-than-qr-codes-with-lower-case-letters/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">shkspr.mobi/blog/2025/02/why-a</span><span class="invisible">re-qr-codes-with-capital-letters-smaller-than-qr-codes-with-lower-case-letters/</span></a></p><p>Take a look at these two QR codes. Scan them if you like, I promise there's nothing dodgy in them.</p> <p><a class="" href="https://shkspr.mobi/blog/wp-content/uploads/2025/02/caps.png" rel="nofollow noopener noreferrer" target="_blank">[🖼 QR CODE]</a> <a class="" href="https://shkspr.mobi/blog/wp-content/uploads/2025/02/lower.png" rel="nofollow noopener noreferrer" target="_blank">[🖼 QR Code.]</a></p> <p>Left is upper-case <code>HTTPS://EDENT.TEL/</code> and right is lower-case <code>https://edent.tel/</code></p><p>You can clearly see that the one on the left is a "smaller" QR as it has fewer bits of data in it. Both go to the same URl, the only difference is the casing.</p><p>What's going on?</p><p>Your first thought might be that there's a different level of error-correction. QR codes can have increasing levels of redundancy in order to make sure they can be scanned when damaged. But, in this case, they both have <strong>L</strong>ow error correction.</p><p>The smaller code is "Type 1" - it is 21px * 21px. The larger is "Type 2" with 25px * 25px.</p><p>The <a href="https://www.qrcode.com/en/about/version.html" rel="nofollow noopener noreferrer" target="_blank">official specification</a> describes the versions in more details. The smaller code should be able to hold 25 alphanumeric character. But <code>https://edent.tel/</code> is only 18 characters long. So why is it bumped into a larger code?</p><p>Using a decoder like <a href="https://zxing.org/" rel="nofollow noopener noreferrer" target="_blank">ZXING</a> it is possible to see the raw bytes of each code.</p><p>UPPER</p><p></p><pre><code>20 93 1a a6 54 63 dd 28 <br>35 1b 50 e9 3b dc 00 ec<br>11 ec 11</code></pre><p>lower:</p><p></p><pre><code>41 26 87 47 47 07 33 a2 <br>f2 f6 56 46 56 e7 42 e7<br>46 56 c2 f0 ec 11 ec 11 <br>ec 11 ec 11 ec 11 ec 11<br>ec 11</code></pre><p>You might have noticed that they both end with the same sequence: <code>ec 11</code> Those are "padding bytes" because the data needs to completely fill the QR code. But - hang on! - not only does the UPPER one safely contain the text, it also has some spare padding?</p><p>The answer lies in the first couple of bytes.</p><p>Once the raw bytes have been read, a QR scanner needs to know exactly what sort of code it is dealing with. <a href="https://www.thonky.com/qr-code-tutorial/data-encoding#step-3-add-the-mode-indicator" rel="nofollow noopener noreferrer" target="_blank">The first four <em>bits</em> tell it the mode</a>. Let's convert the hex to binary and then split after the first four bits:</p>TypeHEXBINSplitUPPER<code>20 93</code><code>00100000 10010011</code><code>0010 000010010011</code>lower<code>41 26</code><code>01000001 00100110</code><code>0100 000100100110</code><p>The UPPER code is <code>0010</code> which indicates it is Alphanumeric - the standard says the next <strong>9</strong> bits show the length of data.</p><p>The lower code is <code>0100</code> which indicates it is Byte mode - the standard says the next <strong>8</strong> bits show the length of data.</p>TypeHEXBINSplitUPPER<code>20 93</code><code>00100000 10010011</code><code>0010 0000 10010</code>lower<code>41 26</code><code>01000001 00100110</code><code>0100 000 10010</code><p>Look at that! They both have a length of <code>10010</code> which, converted to binary, is 18 - the exact length of the text.</p><p>Alphanumeric users 11 bits for every two characters, Byte mode uses (you guessed it!) 8 bits per single character.</p><p>But why is the lower-case code pushed into Byte mode? Isn't it using letters and number?</p><p>Well, yes. But in order to store data efficiently, Alphanumeric mode only has <a href="https://www.thonky.com/qr-code-tutorial/alphanumeric-table" rel="nofollow noopener noreferrer" target="_blank">a limited subset of characters available</a>. Upper-case letters, and a handful of punctuation symbols: <code>space $ % * + - . / :</code></p><p>Luckily, that's enough for a protocol, domain, and path. Sadly, no GET parameters.</p><p>So, there you have it. If you want the smallest possible <em>physical</em> size for a QR code which contains a URl, make sure the text is all in capital letters.</p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/qr/" target="_blank">#qr</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/qr-codes/" target="_blank">#QRCodes</a></p>