commit 0f58e143910b9e79bc330b36c72d234a0ab4ccdb Author: tcsenpai Date: Sun Jul 21 00:52:26 2024 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..55fcdd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +qr_code_*.png +qr_codes/ +__pycache__/ +output_test_file.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..77a545c --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# QR Code Encoder and Decoder + +This Python module provides functionality to encode arbitrary binary data into a series of QR codes and decode them back into the original data. It uses the `qrcode` library for encoding and the `zxing` library for decoding. + +## Dependencies + +- Python 3.x +- qrcode +- Pillow (PIL) +- zxing + +Install the required libraries using pip: + +`pip install qrcode pillow zxing` + +Or install the dependencies using: + +`pip install -r requirements.txt` + +## Functions + +### bin_to_qr(data, chunk_size=100, filename_prefix="qr_code") + +Encodes binary data into a series of QR code images. + +Parameters: +- `data` (bytes): The binary data to encode. +- `chunk_size` (int, optional): The maximum number of hexadecimal characters per QR code. Default is 100. +- `filename_prefix` (str, optional): The prefix for the generated QR code image filenames. Default is "qr_code". + +This function performs the following steps: +1. Converts the binary data to a hexadecimal string. +2. Splits the hex string into chunks of the specified size. +3. Creates a QR code for each chunk, including chunk number and total chunk count. +4. Saves each QR code as a PNG image. + +### qr_to_bin(filename_prefix="qr_code") + +Decodes a series of QR code images back into the original binary data. + +Parameters: +- `filename_prefix` (str, optional): The prefix of the QR code image filenames to decode. Default is "qr_code". + +Returns: +- `bytes`: The decoded binary data, or `None` if no QR codes were found. + +This function performs the following steps: +1. Iterates through numbered QR code images with the given prefix. +2. Decodes each QR code using the zxing library. +3. Extracts chunk information and data from each decoded QR code. +4. Reconstructs the original hexadecimal string from the chunks. +5. Converts the hexadecimal string back to binary data. + +## Usage Example + +```python + +# Encode binary data into QR codes +import qraro + +original_data = b"This is a binary string \x00\x01\x02 with some non-printable characters. +qraro.bin_to_qr(original_data, chunk_size=50) + +# Decode QR codes back into binary data +import qraro + +decoded_data = qraro.qr_to_bin() +print("Decoded data:", decoded_data) +print("Original and decoded data match:", original_data == decoded_data) + +``` + +## Notes + +- The script automatically determines the appropriate QR code version based on the data size. +- Error correction level is set to LOW (L) to maximize data capacity. +- The script handles binary data, including non-printable characters. +- QR code images are saved and read from the current working directory. +- Ensure you have write permissions in the directory where the script is run. + +## Error Handling + +- The script includes basic error handling for file not found and decoding errors. +- If an error occurs during decoding, it will be printed to the console. + +## Limitations + +- The maximum data capacity depends on the QR code version and error correction level. +- Very large binary files may require a large number of QR codes. +- The script assumes that QR codes will be scanned in the correct order for decoding. \ No newline at end of file diff --git a/example_with_files.py b/example_with_files.py new file mode 100644 index 0000000..4eabed0 --- /dev/null +++ b/example_with_files.py @@ -0,0 +1,11 @@ +import qraro + +with open("input_test_file.txt", "rb") as f: + data = f.read() + +qraro.bin_to_qr(data, chunk_size=50) + +test_file = qraro.qr_to_bin() + +with open("output_test_file.txt", "wb") as f: + f.write(test_file) \ No newline at end of file diff --git a/example_with_string.py b/example_with_string.py new file mode 100644 index 0000000..31fc5f7 --- /dev/null +++ b/example_with_string.py @@ -0,0 +1,9 @@ +import qraro + +# Example usage +original_data = b"This is a binary string \x00\x01\x02 with some non-printable characters." +qraro.bin_to_qr(original_data, chunk_size=50) + +decoded_data = qraro.qr_to_bin() +print("Decoded data:", decoded_data) +print("Original and decoded data match:", original_data == decoded_data) \ No newline at end of file diff --git a/input_test_file.txt b/input_test_file.txt new file mode 100644 index 0000000..9b7c9c9 --- /dev/null +++ b/input_test_file.txt @@ -0,0 +1,5 @@ +This file can be used (and is used) as an example input file for the `example_with_files.py` script. + +Feel free to modify it as needed. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut purus eget sapien. \ No newline at end of file diff --git a/qraro.py b/qraro.py new file mode 100644 index 0000000..4b3b0d4 --- /dev/null +++ b/qraro.py @@ -0,0 +1,48 @@ +import qrcode +from PIL import Image +import zxing + +def bin_to_qr(data, chunk_size=100, filename_prefix="qr_code"): + hex_data = data.hex() + chunks = [hex_data[i:i+chunk_size] for i in range(0, len(hex_data), chunk_size)] + total_chunks = len(chunks) + + for i, chunk in enumerate(chunks, 1): + qr = qrcode.QRCode(version=None, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4) + qr.add_data(f"{i}/{total_chunks}:{chunk}") + qr.make(fit=True) + + img = qr.make_image(fill_color="black", back_color="white") + img.save(f"{filename_prefix}_{i}.png") + + print(f"Generated {total_chunks} QR codes.") + +def qr_to_bin(filename_prefix="qr_code"): + chunks = {} + i = 1 + reader = zxing.BarCodeReader() + + while True: + try: + filename = f"{filename_prefix}_{i}.png" + barcode = reader.decode(filename) + if barcode and barcode.parsed: + decoded = barcode.parsed + chunk_info, chunk_data = decoded.split(':', 1) + chunk_num, total_chunks = map(int, chunk_info.split('/')) + chunks[chunk_num] = chunk_data + if chunk_num == total_chunks: + break + i += 1 + except FileNotFoundError: + break + except Exception as e: + print(f"Error decoding QR code {i}: {e}") + break + + if not chunks: + print("No QR codes found.") + return None + + hex_data = ''.join(chunks[i] for i in range(1, len(chunks) + 1)) + return bytes.fromhex(hex_data) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6b2e1b1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +qrcode +Pillow +zxing \ No newline at end of file