The story of one QR-code...
Tags: python, bash, qr, cli
Published: 2023-09-26 14:09:53

As a beginner programmer, you may have heard of QR codes, those square-shaped patterns of black and white squares that store information such as URLs, contact information, or other types of data. But have you ever wondered how QR codes work or how you could generate one in Python? In this article, we'll explore a Python script that generates an ASCII QR code from a given set of data.

---

## The Code Breakdown
Let's start by breaking down the code step by step:

### 1. Importing Necessary Libraries

```python
import json
import base64
from typing import NamedTuple, Union
```

The code begins by importing two standard Python libraries: `json` for working with JSON data and `base64` for handling Base64-encoded strings. Additionally, it imports the `NamedTuple` class and the `Union` type hint from the typing module.

### 2. Defining a NamedTuple

```python
class TextToQR(NamedTuple):
    n0: int
    x: int
    c: str
```

Here, a NamedTuple named TextToQR is defined with three fields: `n0`, `x`, and `c`. This NamedTuple will be used to represent the data needed to generate the ASCII QR code.

### 3. Generating the ASCII QR Code

```python
def generate_ascii_qr_code(qr: TextToQR, margin: int = 2) -> list[str]:
    # Decode the Base64 string and convert it to a binary string
    decoded = bytes(base64.b64decode(qr.c)).decode('utf-8')
    binary = ''.join(list(map(lambda b: bin(ord(b)).replace('0b', '').zfill(8), decoded)))
    binary = binary[qr.n0:]

    x = qr.x

    rows = []
    rows.extend(['  ' * (x + margin * 2) for _ in range(margin)])

    for i in range(x):
        row = binary[i * x:(i + 1) * x]
        row = ''.join(list(map(lambda c: '█' * 2 if c == '1' else '  ', row)))
        rows.append(('  ' * margin) + row + ('  ' * margin))

    rows.extend(['  ' * (x + margin * 2) for _ in range(margin)])

    return rows
```

This function, `generate_ascii_qr_code`, takes a `TextToQR` object as input along with an optional margin parameter. It generates an ASCII QR code based on the provided data.

1. The Base64-encoded string `qr.c` is first decoded and converted to a binary string.

2. The binary string is sliced starting from the index `qr.n0`. This allows you to specify where in the binary string to begin generating the QR code.

3. The code then constructs the ASCII QR code by iterating through the binary string, replacing '1' with '██' (two filled squares) and '0' with ' ' (two spaces).

4. Rows of spaces are added to the top and bottom of the code to create a margin, as specified by the margin parameter.

5. The function returns a list of strings, where each string represents a row of the ASCII QR code.

### 4. Main Program

```python
if __name__ == "__main__":
    data = """
    {
    "n0": 7,
    "x": 29,
    "c": "AcO9wp5nw7ggBsKgw50Swp12w6rDnsKLwrdTwrJdwoLCh1oPw7VVX8OAKF4BF8K8b8Kcw5/CqGpPw69JdsOmEMORF8OnwoJOLMKeAMKkfQHCl8K/YMKnBXzCvcOjw61KEcOKB3fCuXQDMmBedsKfw7AAwp8Yw6fDt8OLw5dgwpLCti11wq1fwpvCpMOZF10Nw7JeCMKNw4/Cn8OTwolS"
    }
    """
    data = json.loads(data)

    qr = generate_ascii_qr_code(TextToQR(**data))
    for line in qr:
        print(line)
```

The main program begins by loading JSON data containing the QR code configuration. It then calls the `generate_ascii_qr_code` function with this data and prints each row of the generated ASCII QR code.

### Let's see how it works!

After running the code from the above it produces the following awesome output!

```
                                                                  
                                                                  
    ██████████████  ████    ████████    ████    ██████████████    
    ██          ██                    ████  ██  ██          ██    
    ██  ██████  ██      ██    ██  ██    ██████  ██  ██████  ██    
    ██  ██████  ██  ██  ████  ████████  ██      ██  ██████  ██    
    ██  ██████  ██  ██    ██████  ████    ██    ██  ██████  ██    
    ██          ██  ██        ██████  ██  ████  ██          ██    
    ██████████████  ██  ██  ██  ██  ██  ██  ██  ██████████████    
                    ██  ██        ██  ████████                    
    ██      ██  ████████  ████████      ████  ██████████    ██    
    ████    ████  ████████████  ██  ██        ████  ██  ██        
    ██    ██████████████  ████████  ██    ██    ██  ██████  ██    
    ██  ██████    ████        ██        ████  ██      ██          
    ██  ████████████    ████████          ██    ██    ██████      
        ██  ████    ██    ████████                  ██  ██        
    ██      ██████████  ██              ████    ██  ████████      
    ████████████  ████          ██  ██    ██████          ██      
    ██  ██████████    ██  ████████  ████████      ██████████      
    ████  ██  ██    ██  ██        ██      ██████    ██  ██        
            ██████  ██████  ████████  ██████    ██  ██████  ██    
                    ████    ████    ██    ████            ██      
    ████████    ██████  ████  ██    ██████████████████            
                    ██    ██████████      ████      ██████        
    ██████████████  ██████████    ██  ████████  ██  ██████  ██    
    ██          ██    ██    ██  ██  ████  ████      ██  ████      
    ██  ██████  ██  ████  ██  ████  ██  ██  ████████████    ██    
    ██  ██████  ██    ██    ████  ████    ██      ██  ██████      
    ██  ██████  ██        ████  ██████████    ██    ██  ██████    
    ██          ██      ██      ████  ██████    ██████████        
    ██████████████  ██    ██████      ██    ██  ██  ██    ██      
                                                                  


```

Can you read the code? ;)

### Tools
- the service used in the article: https://qrshare.io
- CLI tool for instant file upload from the console:

```bash
pip install qrshare-io-cli
```

Thanks for reading till then!
I hope this was useful to you, let me know in the comments what you think.