Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize QR code #64

Closed
robtex opened this issue May 21, 2022 · 9 comments · Fixed by #68
Closed

Optimize QR code #64

robtex opened this issue May 21, 2022 · 9 comments · Fixed by #68
Assignees

Comments

@robtex
Copy link

robtex commented May 21, 2022

by changing to uppercase a QR code only needs 5.5 bits instead of 8 bits
bech32 is designed to work in uppercase QR
the proposed strings are not 100% in the supported alphabet, but QR code has a mixed mode that means it can switch mode inside the same QR code
i suggest we simply uppercase the lightning invoice to start with, all wallets i know support uppercase lightning invoices.
bc1 on chain addresses should also be possible to uppercase in the same way since they are bech32
some wallets will probably have issues, but it is them that have to fix it.

small example, the example on https://bitcoinqr.dev/
image
only change is lightning invoice uppercased:
image
it is quite obvious that it needs fewer bits

image

@sbddesign
Copy link
Owner

some wallets will probably have issues, but it is them that have to fix it.

@robtex Yeah, I'm not too worried about wallet support for uppercasing. I think there's fairly wide support for it, actually. This data is from December 2020 but already has promising results. Wouldn't surprise me if some of these red Xs have become checkmarks in the past year and a half. btcpayserver/btcpayserver#2110

@sbddesign
Copy link
Owner

Ran some tests by generating QR codes with this tool. I decided to run this test with different variations, like changing number of URI params and changing the invoice.

In every case, the uppercase QR is a lower-resolution image. These codes are being generated with the qrcode NPM library. This lib is supposed to automatically choose the correct QR code mode for you based on what's most efficient for the input string. I imagine it's selecting "mixed" for most of these, but regardless, it's supposed to be choosing the most size efficient mode.

So I think this can serve as a proof of concept that the uppercasing can work very well.

URI with label and message

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file qr-bip21.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6&label=sbddesign&message=For%20lunch%20Tuesday

qr_bip21

URI with label and message (uppercase)

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file qr_bip21_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_uppercase

URI with label and message - alternate invoice

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3ff0wxpp5p3vchn8ehvpk2drll24x222crhx4auqj2aduxpuaxw9gj2jfprxsd8qfa3xummcd9hh2umv0ysxcmmwvusx6etddusz6gzzd96xxmmfdcsxjurnw4kjqer0d3hhygrnd96zqctdv46zugzyda6kymr994ehqetwvss8qun0vfkx2mfqwa5xjar9wpshqetjypf5ssfdxg6nvtpqv3hh2cnvv5khxur9dejzqurjda3xcetdypxk2untd3jjq4rjv4jjqmtfdejhygrzd3hkx6eqcqzpgxqzjcsp5ljee7p2gufjtda6jj5d3cxh977ew3npjx5ajhav68k3hf5xhd48q9qyyssqvjcg29x5jnas9lc5tmkstamgf8kghjqk2l0v326qgzq3s6xqftu9nmzkjt7t7607da9n44n0a8svtfuya0s4rtsr94tmtf7k8ng6tlsq2qdh2k' --file qr-bip21_longer.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=lnbc10u1p3ff0wxpp5p3vchn8ehvpk2drll24x222crhx4auqj2aduxpuaxw9gj2jfprxsd8qfa3xummcd9hh2umv0ysxcmmwvusx6etddusz6gzzd96xxmmfdcsxjurnw4kjqer0d3hhygrnd96zqctdv46zugzyda6kymr994ehqetwvss8qun0vfkx2mfqwa5xjar9wpshqetjypf5ssfdxg6nvtpqv3hh2cnvv5khxur9dejzqurjda3xcetdypxk2untd3jjq4rjv4jjqmtfdejhygrzd3hkx6eqcqzpgxqzjcsp5ljee7p2gufjtda6jj5d3cxh977ew3npjx5ajhav68k3hf5xhd48q9qyyssqvjcg29x5jnas9lc5tmkstamgf8kghjqk2l0v326qgzq3s6xqftu9nmzkjt7t7607da9n44n0a8svtfuya0s4rtsr94tmtf7k8ng6tlsq2qdh2k

qr-bip21_longer

URI with label and message - alternate invoice (uppercase)

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3FF0WXPP5P3VCHN8EHVPK2DRLL24X222CRHX4AUQJ2ADUXPUAXW9GJ2JFPRXSD8QFA3XUMMCD9HH2UMV0YSXCMMWVUSX6ETDDUSZ6GZZD96XXMMFDCSXJURNW4KJQER0D3HHYGRND96ZQCTDV46ZUGZYDA6KYMR994EHQETWVSS8QUN0VFKX2MFQWA5XJAR9WPSHQETJYPF5SSFDXG6NVTPQV3HH2CNVV5KHXUR9DEJZQURJDA3XCETDYPXK2UNTD3JJQ4RJV4JJQMTFDEJHYGRZD3HKX6EQCQZPGXQZJCSP5LJEE7P2GUFJTDA6JJ5D3CXH977EW3NPJX5AJHAV68K3HF5XHD48Q9QYYSSQVJCG29X5JNAS9LC5TMKSTAMGF8KGHJQK2L0V326QGZQ3S6XQFTU9NMZKJT7T7607DA9N44N0A8SVTFUYA0S4RTSR94TMTF7K8NG6TLSQ2QDH2K' --file qr_bip21-longer_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3FF0WXPP5P3VCHN8EHVPK2DRLL24X222CRHX4AUQJ2ADUXPUAXW9GJ2JFPRXSD8QFA3XUMMCD9HH2UMV0YSXCMMWVUSX6ETDDUSZ6GZZD96XXMMFDCSXJURNW4KJQER0D3HHYGRND96ZQCTDV46ZUGZYDA6KYMR994EHQETWVSS8QUN0VFKX2MFQWA5XJAR9WPSHQETJYPF5SSFDXG6NVTPQV3HH2CNVV5KHXUR9DEJZQURJDA3XCETDYPXK2UNTD3JJQ4RJV4JJQMTFDEJHYGRZD3HKX6EQCQZPGXQZJCSP5LJEE7P2GUFJTDA6JJ5D3CXH977EW3NPJX5AJHAV68K3HF5XHD48Q9QYYSSQVJCG29X5JNAS9LC5TMKSTAMGF8KGHJQK2L0V326QGZQ3S6XQFTU9NMZKJT7T7607DA9N44N0A8SVTFUYA0S4RTSR94TMTF7K8NG6TLSQ2QDH2K

qr_bip21-longer_uppercase

URI with amount

Build Command

npm run qr -- --amt=0.00001000 --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file=qr_bip21_non-memo.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6

qr_bip21_non-memo

URI with amount (uppercase)

Build Command

npm run qr -- --amt=0.00001000 --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file=qr_bip21_non-memo_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_non-memo_uppercase

URI with lightning param only

Build Command

npm run qr -- --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file=qr_bip21_1-param.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6

qr_bip21_1-param

URI with lightning param only (uppercase)

Build Command

npm run qr -- --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file=qr_bip21_1-param_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_1-param_uppercase

@sbddesign
Copy link
Owner

@robtex I'll make a PR to change the QR codes on the site as well as add some text to explain the value of uppercasing.

@sbddesign sbddesign self-assigned this May 30, 2022
@robtex
Copy link
Author

robtex commented May 30, 2022

nice research and awesome examples!
just some last minute comments and ideas:
there seems to be good support for BITCOIN: maybe should throw in that as well?

also i see no point in doing lightning= in lowercase since it is a brand new parameter. make that one uppercase and we might save another pixel. or why not just LN= ?

it is truly annoying that '?' and = breaks the flow of alphanumerics, but the : is supported so BITCOIN:BC1... part would become one single alphanumeric sequence. so your last example would be

1 BITCOIN:BC1... in alphanumeric
2 ? in text
3 LN (or LIGHTNING) in alphanumeric
4 = in text
5 LNBC1... in alphanumeric

probably 2,3,4 will be short enough to be optimizied into one text-mode sequence ?LN= without having to shift modes

1 BITCOIN:BC1... in alphanumeric
2 ?LN= in text
3 LNBC1... in alphanumeric

default:
image

error correction L (my favorite since bech has enough error correction):
image

BITCOIN:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?LN=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

@sbddesign
Copy link
Owner

I decided to do some investigation regarding the capitalizing the scheme and parameter, as well as changing from lightning to LN. While this is far from exhaustive, I have managed to collect a lot of data on this. What I have observed is that (with my example data) the bitcoin address and lightning invoice contribute the most "weight" to the QR code. Through almost all these variations, simply using bitcoin:BECH32 ... lightning=BECH32 is equally effective as BITCOIN:BECH32 ... LN=BECH32. The only exception to this is row 4 of my data. I even ran the tests again without lightning invoices out of curiosity. Same deal: upper-casing the scheme has no noticeable effect on QR size.

See data here. For each row, the green outlines indicate the smallest QR dimension (there are many ties per row). Orange outlines indicate the second smallest QR dimension (also many ties).

My conclusion:

  • Upper-casing scheme and protocol usually has no noticeable effect.
  • Switching to LN= may have a very small effect in some situations.
    • LN= does not seem to have good support. (I tested 6 lightning wallets and none recognized LN=).
  • Upper-casing the address and invoice have an outsized effect in all situations.
  • bitcoin:BECH32 ... lightning=BECH32 is the format we are within closest reach to in the industry.
  • Therefore, we should promote bitcoin:BECH32 ... lightning=BECH32.

Personally, I'd rather spend time discussing BOLT12 than trying to save 16 pixels in some situations.

@GBKS
Copy link

GBKS commented Jun 3, 2022

Wow, thorough analysis there. Your recommendation makes sense to me. ACK.

@robtex
Copy link
Author

robtex commented Jun 4, 2022

definitely exhaustive enough and also uppercase enough for me. very nice!
wasn't aware there were already wallets supporting this lightning= part, so let's not break them.
ACK

@Bosch-0
Copy link
Collaborator

Bosch-0 commented Jun 7, 2022

Nice research, makes sense to me!

A shame these iQR codes are proprietary: https://qrcode.meetheed.com/question40.php

"You could take an iQR Code and a QR Code of exactly the same size, and encode a lot more data within the iQR Code (up to 80% more)."

@sbddesign
Copy link
Owner

Thanks for pushing for this @robtex and others! Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants