diff --git a/.gitignore b/.gitignore index 55fcdd0..96fa716 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,35 @@ +# QR code output files qr_code_*.png qr_codes/ +output_test_file.txt + +# Python package build artifacts +dist/ +build/ +*.egg-info/ __pycache__/ -output_test_file.txt \ No newline at end of file +*.py[cod] +*$py.class +.eggs/ + +# Virtual environments +venv/ +env/ +ENV/ +.venv/ +.env/ + +# Development and testing +.pytest_cache/ +.coverage +htmlcov/ +.tox/ + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo +.DS_Store + +mise.toml \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..4734111 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include README.md +include LICENSE +include requirements.txt \ No newline at end of file diff --git a/binary_qr_converter/__init__.py b/binary_qr_converter/__init__.py new file mode 100644 index 0000000..ef379b6 --- /dev/null +++ b/binary_qr_converter/__init__.py @@ -0,0 +1,7 @@ +""" +Binary QR Converter - A utility to convert binary files to QR codes and back. +""" + +from binary_qr_converter.converter import BinaryQRConverter + +__version__ = '0.1.0' \ No newline at end of file diff --git a/binary_qr.py b/binary_qr_converter/binary_qr.py similarity index 75% rename from binary_qr.py rename to binary_qr_converter/binary_qr.py index 2f3fe8c..a6ccecc 100644 --- a/binary_qr.py +++ b/binary_qr_converter/binary_qr.py @@ -9,90 +9,102 @@ import sys from pathlib import Path from typing import List, Optional -from converter import BinaryQRConverter +from binary_qr_converter.converter import BinaryQRConverter -__version__ = '0.1.0' +__version__ = "0.1.0" # Configure logging logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) + def parse_args(): """Parse command line arguments.""" parser = argparse.ArgumentParser( description="Convert binary files to QR codes and back", - formatter_class=argparse.ArgumentDefaultsHelpFormatter + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) - + subparsers = parser.add_subparsers(dest="command", help="Command to execute") - + # Encode command - encode_parser = subparsers.add_parser("encode", help="Encode a binary file to QR codes") - encode_parser.add_argument("file", type=str, help="Path to the binary file to encode") + encode_parser = subparsers.add_parser( + "encode", help="Encode a binary file to QR codes" + ) encode_parser.add_argument( - "-o", "--output-dir", - type=str, + "file", type=str, help="Path to the binary file to encode" + ) + encode_parser.add_argument( + "-o", + "--output-dir", + type=str, default="./qrcodes", - help="Directory to save QR code images" + help="Directory to save QR code images", ) encode_parser.add_argument( - "-c", "--chunk-size", - type=int, + "-c", + "--chunk-size", + type=int, default=1024, - help="Size of binary chunks in bytes" + help="Size of binary chunks in bytes", ) encode_parser.add_argument( - "-v", "--qr-version", - type=int, + "-v", + "--qr-version", + type=int, default=40, choices=range(1, 41), - help="QR code version (1-40, higher means more capacity)" + help="QR code version (1-40, higher means more capacity)", ) encode_parser.add_argument( - "-z", "--compression-level", - type=int, + "-z", + "--compression-level", + type=int, default=9, - help="Zlib compression level (0-9)" + help="Zlib compression level (0-9)", ) - + # Decode command - decode_parser = subparsers.add_parser("decode", help="Decode QR codes back to a binary file") - decode_parser.add_argument( - "images", - type=str, - nargs="+", - help="Paths to QR code images or directory containing QR code images" + decode_parser = subparsers.add_parser( + "decode", help="Decode QR codes back to a binary file" ) decode_parser.add_argument( - "-o", "--output-dir", - type=str, + "images", + type=str, + nargs="+", + help="Paths to QR code images or directory containing QR code images", + ) + decode_parser.add_argument( + "-o", + "--output-dir", + type=str, default="./output", - help="Directory to save the reconstructed file" + help="Directory to save the reconstructed file", ) - + # Version command version_parser = subparsers.add_parser("version", help="Show version information") - + return parser.parse_args() + def get_image_paths(image_args: List[str]) -> List[Path]: """ Get a list of image paths from command line arguments. - + Args: image_args: List of image paths or directories from command line - + Returns: List of image file paths """ image_paths = [] - + for path_str in image_args: path = Path(path_str) - + if path.is_dir(): # If path is a directory, find all PNG files in it image_paths.extend(sorted(path.glob("*.png"))) @@ -104,31 +116,32 @@ def get_image_paths(image_args: List[str]) -> List[Path]: expanded_paths = list(Path().glob(path_str)) if expanded_paths: image_paths.extend(expanded_paths) - + return image_paths + def main(): """Main entry point for the command-line interface.""" args = parse_args() - + if args.command == "version": print(f"Binary QR Converter version {__version__}") return 0 - + if args.command == "encode": file_path = Path(args.file) output_dir = Path(args.output_dir) - + if not file_path.exists(): logger.error(f"File not found: {file_path}") return 1 - + converter = BinaryQRConverter( chunk_size=args.chunk_size, qr_version=args.qr_version, - compression_level=args.compression_level + compression_level=args.compression_level, ) - + try: qr_image_paths = converter.encode_file(file_path, output_dir) logger.info(f"Created {len(qr_image_paths)} QR code images in {output_dir}") @@ -136,19 +149,19 @@ def main(): except Exception as e: logger.error(f"Encoding failed: {str(e)}") return 1 - + elif args.command == "decode": image_paths = get_image_paths(args.images) output_dir = Path(args.output_dir) - + if not image_paths: logger.error("No image files found") return 1 - + logger.info(f"Found {len(image_paths)} image files") - + converter = BinaryQRConverter() - + try: output_path = converter.decode_qr_images(image_paths, output_dir) if output_path: @@ -160,10 +173,11 @@ def main(): except Exception as e: logger.error(f"Decoding failed: {str(e)}") return 1 - + else: logger.error("No command specified. Use --help for usage information.") return 1 + if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/converter.py b/binary_qr_converter/converter.py similarity index 100% rename from converter.py rename to binary_qr_converter/converter.py diff --git a/example.py b/binary_qr_converter/example.py similarity index 77% rename from example.py rename to binary_qr_converter/example.py index 93743df..c26c245 100644 --- a/example.py +++ b/binary_qr_converter/example.py @@ -7,54 +7,60 @@ import os import tempfile from pathlib import Path -from converter import BinaryQRConverter +from binary_qr_converter.converter import BinaryQRConverter + def main(): """Run an example of encoding and decoding a binary file.""" # Create a temporary directory for our example with tempfile.TemporaryDirectory() as temp_dir: temp_dir_path = Path(temp_dir) - + # Create a test binary file test_file_path = temp_dir_path / "test_file.bin" - with open(test_file_path, 'wb') as f: + with open(test_file_path, "wb") as f: f.write(os.urandom(1000000)) # 1MB of random data - + print(f"Created test file: {test_file_path}") - + # Create output directories qr_output_dir = temp_dir_path / "qrcodes" decode_output_dir = temp_dir_path / "output" - + # Create converter converter = BinaryQRConverter(chunk_size=500) - + # Encode the test file to QR codes print("Encoding file to QR codes...") qr_image_paths = converter.encode_file(test_file_path, qr_output_dir) - + print(f"Created {len(qr_image_paths)} QR code images:") for path in qr_image_paths: print(f" - {path}") - + # Decode the QR codes back to a file print("\nDecoding QR codes back to file...") - decoded_file_path = converter.decode_qr_images(qr_image_paths, decode_output_dir) - + decoded_file_path = converter.decode_qr_images( + qr_image_paths, decode_output_dir + ) + if decoded_file_path: print(f"Successfully decoded to: {decoded_file_path}") - + # Verify the decoded file matches the original - with open(test_file_path, 'rb') as f1, open(decoded_file_path, 'rb') as f2: + with open(test_file_path, "rb") as f1, open(decoded_file_path, "rb") as f2: original_data = f1.read() decoded_data = f2.read() - + if original_data == decoded_data: print("Verification successful: Decoded file matches the original!") else: - print("Verification failed: Decoded file does not match the original.") + print( + "Verification failed: Decoded file does not match the original." + ) else: print("Decoding failed.") + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ce1dbe9 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +from setuptools import setup, find_packages + +with open("README.md", "r", encoding="utf-8") as fh: + long_description = fh.read() + +setup( + name="binary-qr-converter", + version="0.1.0", + author="Your Name", + author_email="your.email@example.com", + description="Convert binary files to QR codes and back", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/yourusername/binary-qr-converter", + packages=find_packages(), + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + python_requires=">=3.6", + install_requires=[ + "qrcode>=7.0", + "pillow>=8.0.0", + "pyzbar>=0.1.8", + ], + entry_points={ + "console_scripts": [ + "binary-qr=binary_qr_converter.binary_qr:main", + ], + }, +) \ No newline at end of file