mirror of
https://github.com/tcsenpai/qrare.git
synced 2025-06-03 01:40:10 +00:00
Revamped
This commit is contained in:
parent
e453676735
commit
5bde7ab10c
196
README.md
196
README.md
@ -1,122 +1,116 @@
|
||||
# QRare
|
||||
# Binary QR Converter
|
||||
|
||||
## Store files into QR Codes and decode them later!
|
||||
A simple CLI tool to convert binary files to QR codes and back.
|
||||
|
||||
### Now with gzip compression and fallback to qrtools!
|
||||
## Features
|
||||
|
||||
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` and `qrtools` libraries for decoding.
|
||||
- Convert any binary file to a series of QR codes
|
||||
- Decode QR codes back to the original binary file
|
||||
- Compression to reduce the number of QR codes needed
|
||||
- Error correction for reliable decoding
|
||||
- File integrity verification using SHA-256 hashing
|
||||
- Cross-platform compatibility (Windows, macOS, Linux)
|
||||
|
||||
## Installation
|
||||
## Prerequisites
|
||||
|
||||
### Using pip
|
||||
- Python 3.6 or higher
|
||||
- For decoding QR codes, you need to install the ZBar library:
|
||||
- On Ubuntu/Debian: `sudo apt-get install libzbar0`
|
||||
- On macOS: `brew install zbar`
|
||||
- On Windows: Download from [SourceForge](https://sourceforge.net/projects/zbar/)
|
||||
|
||||
Pubished at https://pypi.org/project/qrare/
|
||||
## Setup
|
||||
|
||||
`pip install qrare`
|
||||
1. Clone or download this repository
|
||||
2. Install dependencies:
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Make the script executable (Linux/macOS):
|
||||
```
|
||||
chmod +x binary_qr.py
|
||||
```
|
||||
|
||||
### From this repository
|
||||
## Usage
|
||||
|
||||
### Encoding a binary file to QR codes
|
||||
|
||||
```
|
||||
git clone https://github.com/tcsenpai/qrare/
|
||||
|
||||
cd qrare
|
||||
python binary_qr.py encode path/to/file.bin -o output_directory
|
||||
```
|
||||
|
||||
#### Install dependencies
|
||||
Options:
|
||||
- `-o, --output-dir`: Directory to save QR code images (default: ./qrcodes)
|
||||
- `-c, --chunk-size`: Size of binary chunks in bytes (default: 1024)
|
||||
- `-v, --qr-version`: QR code version (1-40, higher means more capacity) (default: 40)
|
||||
- `-z, --compression-level`: Zlib compression level (0-9) (default: 9)
|
||||
|
||||
- Python 3.x
|
||||
- qrcode
|
||||
- qrtools
|
||||
- compress
|
||||
- Pillow (PIL)
|
||||
- zxing
|
||||
|
||||
Install the required libraries using pip:
|
||||
|
||||
`pip install qrcode pillow zxing qrtools compress`
|
||||
|
||||
Or install the dependencies using:
|
||||
|
||||
`pip install -r requirements.txt`
|
||||
|
||||
## Functions & Usage
|
||||
|
||||
### 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. Compresses the binary data using gzip.
|
||||
2. Converts the binary data to a hexadecimal string.
|
||||
3. Splits the hex string into chunks of the specified size.
|
||||
4. Creates a QR code for each chunk, including chunk number and total chunk count.
|
||||
5. 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, falling back to qrtools if zxing cannot decode a qrcode.
|
||||
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.
|
||||
6. Decompresses the binary data using gzip.
|
||||
7. Returns the decompressed binary data.
|
||||
|
||||
## Usage Example
|
||||
|
||||
```python
|
||||
|
||||
# Encode binary data into QR codes
|
||||
import qrare
|
||||
|
||||
original_data = b"This is a binary string \x00\x01\x02 with some non-printable characters.
|
||||
qrare.bin_to_qr(original_data, chunk_size=50)
|
||||
```
|
||||
|
||||
And vice versa
|
||||
|
||||
```python
|
||||
# Decode QR codes back into binary data
|
||||
import qrare
|
||||
|
||||
decoded_data = qrare.qr_to_bin()
|
||||
print("Decoded data:", decoded_data)
|
||||
print("Original and decoded data match:", original_data == decoded_data)
|
||||
### Decoding QR codes back to a binary file
|
||||
|
||||
```
|
||||
python binary_qr.py decode path/to/qrcodes/*.png -o output_directory
|
||||
```
|
||||
|
||||
## Notes
|
||||
or
|
||||
|
||||
- The script automatically determines the appropriate QR code version based on the data size.
|
||||
- Data is compressed using gzip before being encoded into QR codes to maximize data capacity.
|
||||
- Data is then decompressed using gzip after being decoded from QR codes.
|
||||
- Error correction level is set to LOW (L) to maximize data capacity.
|
||||
- The script handles binary data, including non-printable characters.
|
||||
- THe script has a fallback method that (until now) allows for a 100% error free decoding.
|
||||
- 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.
|
||||
```
|
||||
python binary_qr.py decode path/to/qrcodes/ -o output_directory
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
Options:
|
||||
- `-o, --output-dir`: Directory to save the reconstructed file (default: ./output)
|
||||
|
||||
- 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.
|
||||
### Show version information
|
||||
|
||||
## Limitations
|
||||
```
|
||||
python binary_qr.py version
|
||||
```
|
||||
|
||||
- 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.
|
||||
## Examples
|
||||
|
||||
### Encode a PDF file to QR codes
|
||||
|
||||
```
|
||||
python binary_qr.py encode document.pdf -o qrcodes/
|
||||
```
|
||||
|
||||
### Decode QR codes back to the original PDF
|
||||
|
||||
```
|
||||
python binary_qr.py decode qrcodes/ -o recovered/
|
||||
```
|
||||
|
||||
### Run the example script
|
||||
|
||||
```
|
||||
python example.py
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
1. The binary file is compressed using zlib to reduce size
|
||||
2. The compressed data is split into chunks
|
||||
3. Each chunk is encoded with metadata (chunk index, total chunks, filename, file hash)
|
||||
4. Each chunk with metadata is converted to a QR code image
|
||||
5. When decoding, the QR codes are read, and the chunks are reassembled
|
||||
6. The reassembled data is decompressed to recover the original file
|
||||
7. The file hash is verified to ensure data integrity
|
||||
|
||||
## Tips for optimal use
|
||||
|
||||
- **Adjust chunk size**: For larger files, increasing the chunk size (`-c` option) can reduce the number of QR codes but may make them more complex and harder to scan.
|
||||
- **QR code version**: Higher versions (up to 40) can store more data but require higher resolution scanning.
|
||||
- **Compression level**: The default level (9) provides maximum compression but takes longer. Lower values (1-8) are faster but produce more QR codes.
|
||||
- **Printing QR codes**: When printing, ensure high quality and sufficient size for reliable scanning.
|
||||
- **Scanning**: Use a good camera in well-lit conditions for best results when scanning QR codes.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Missing ZBar library**: If you get an error about missing ZBar, install it using the instructions in the Prerequisites section.
|
||||
- **QR code decoding fails**: Make sure all QR codes are clearly visible and not damaged. Try increasing the error correction level.
|
||||
- **File too large**: Try increasing the chunk size or QR code version to reduce the number of QR codes.
|
||||
- **Invalid QR version**: Make sure to use a QR version between 1 and 40.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
@ -1,11 +0,0 @@
|
||||
import qrare
|
||||
|
||||
with open("pika.webp", "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
qrare.bin_to_qr(data, chunk_size=1000, box_size=10, border=4)
|
||||
|
||||
test_file = qrare.qr_to_bin()
|
||||
|
||||
with open("pika_out.webp", "wb") as f:
|
||||
f.write(test_file)
|
@ -1,9 +0,0 @@
|
||||
import qrare
|
||||
|
||||
# Example usage
|
||||
original_data = b"This is a binary string \x00\x01\x02 with some non-printable characters."
|
||||
qrare.bin_to_qr(original_data, chunk_size=50)
|
||||
|
||||
decoded_data = qrare.qr_to_bin()
|
||||
print("Decoded data:", decoded_data)
|
||||
print("Original and decoded data match:", original_data == decoded_data)
|
@ -1,5 +0,0 @@
|
||||
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.
|
82
qrare.py
82
qrare.py
@ -1,82 +0,0 @@
|
||||
import qrcode
|
||||
import zxing
|
||||
import qrtools
|
||||
from compress import Compressor
|
||||
|
||||
def bin_to_qr(data, chunk_size=100, filename_prefix="qr_code", box_size=10, border=4):
|
||||
compressed_data = compress_bytes(data)
|
||||
hex_data = compressed_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=box_size, border=border)
|
||||
qr.add_data(f"{i}/{total_chunks}:{chunk}")
|
||||
qr.make(fit=True)
|
||||
print(f"Generating QR code {i}", end="")
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
img.save(f"{filename_prefix}_{i}.png")
|
||||
print(f"[OK]")
|
||||
|
||||
print(f"Generated {total_chunks} QR codes.")
|
||||
print(f"Each QR code except the last one will contain {chunk_size} bytes of data.")
|
||||
print(f"The last QR code will contain the remaining bytes of data ({len(chunks[-1] )} bytes).")
|
||||
|
||||
def qr_to_bin(filename_prefix="qr_code"):
|
||||
chunks = {}
|
||||
i = 1
|
||||
reader = zxing.BarCodeReader()
|
||||
fallback_reader = qrtools.QR()
|
||||
|
||||
while True:
|
||||
try:
|
||||
filename = f"{filename_prefix}_{i}.png"
|
||||
print(f"Decoding QR code {i}...", end="")
|
||||
barcode = reader.decode(filename)
|
||||
print(f"decoded...", end="")
|
||||
if barcode and barcode.parsed:
|
||||
decoded = barcode.parsed
|
||||
else:
|
||||
print(f"Could not decode QR code {i}: {barcode.raw} with zxing, trying fallback reader...")
|
||||
fallback_reader.decode(filename)
|
||||
decoded = fallback_reader.data
|
||||
# split the decoded string into chunk_info and chunk_data
|
||||
chunk_info, chunk_data = decoded.split(':', 1)
|
||||
chunk_num, total_chunks = map(int, chunk_info.split('/'))
|
||||
chunks[chunk_num] = chunk_data
|
||||
# print(chunk_data)
|
||||
print(f"binary data extracted [OK]")
|
||||
if chunk_num == total_chunks:
|
||||
break
|
||||
# print(fallback_reader.data)
|
||||
if not chunks[i]:
|
||||
print(f"Error decoding QR code {i}: {barcode.raw}")
|
||||
exit(-1)
|
||||
print(f"binary data extracted [OK]")
|
||||
|
||||
i += 1
|
||||
except FileNotFoundError:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Error decoding QR code {i}: {e}")
|
||||
exit(-1)
|
||||
|
||||
if not chunks:
|
||||
print("No QR codes found.")
|
||||
return None
|
||||
|
||||
hex_data_compressed = ''.join(chunks[i] for i in range(1, len(chunks) + 1))
|
||||
bytes_compressed = bytes.fromhex(hex_data_compressed)
|
||||
return decompress_bytes(bytes_compressed)
|
||||
|
||||
# Compressing as much as possible
|
||||
|
||||
def compress_bytes(data):
|
||||
compressor = Compressor()
|
||||
compressor.use_gzip()
|
||||
return compressor.compress(data)
|
||||
|
||||
def decompress_bytes(data):
|
||||
compressor = Compressor()
|
||||
compressor.use_gzip()
|
||||
return compressor.decompress(data)
|
@ -1,5 +1,4 @@
|
||||
qrcode
|
||||
Pillow
|
||||
zxing
|
||||
qrtools
|
||||
compress
|
||||
# Core dependencies
|
||||
qrcode>=7.0
|
||||
pillow>=8.0.0
|
||||
pyzbar>=0.1.8
|
Loading…
x
Reference in New Issue
Block a user