diff --git a/CLAUDE.md b/CLAUDE.md index 47dc3e3d86..c317064255 120000 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1 @@ -AGENTS.md \ No newline at end of file +AGENTS.md diff --git a/skills/qr-code/SKILL.md b/skills/qr-code/SKILL.md new file mode 100644 index 0000000000..5d18fd4aee --- /dev/null +++ b/skills/qr-code/SKILL.md @@ -0,0 +1,86 @@ +--- +name: qr-code +description: Generate and read QR codes. Use when the user wants to create a QR code from text/URL, or decode/read a QR code from an image file. Supports PNG/JPG output and can read QR codes from screenshots or image files. +--- + +# QR Code + +Generate QR codes from text/URLs and decode QR codes from images. + +## Capabilities + +- Generate QR codes from any text, URL, or data +- Customize QR code size and error correction level +- Save as PNG or display in terminal +- Read/decode QR codes from image files (PNG, JPG, etc.) +- Read QR codes from screenshots + +## Requirements + +Install Python dependencies: + +### For Generation + +```bash +pip install qrcode pillow +``` + +### For Reading + +```bash +pip install pillow pyzbar +``` + +On Windows, pyzbar requires Visual C++ Redistributable. +On macOS: `brew install zbar` +On Linux: `apt install libzbar0` + +## Generate QR Code + +```bash +python scripts/qr_generate.py "https://example.com" output.png +``` + +Options: + +- `--size`: Box size in pixels (default: 10) +- `--border`: Border size in boxes (default: 4) +- `--error`: Error correction level L/M/Q/H (default: M) + +Example with options: + +```bash +python scripts/qr_generate.py "Hello World" hello.png --size 15 --border 2 +``` + +## Read QR Code + +```bash +python scripts/qr_read.py image.png +``` + +Returns the decoded text/URL from the QR code. + +## Quick Examples + +Generate QR for a URL: + +```python +import qrcode +img = qrcode.make("https://openclaw.ai") +img.save("openclaw.png") +``` + +Read QR from image: + +```python +from pyzbar.pyzbar import decode +from PIL import Image +data = decode(Image.open("qr.png")) +print(data[0].data.decode()) +``` + +## Scripts + +- `scripts/qr_generate.py` - Generate QR codes with customization options +- `scripts/qr_read.py` - Decode QR codes from image files diff --git a/skills/qr-code/scripts/qr_generate.py b/skills/qr-code/scripts/qr_generate.py new file mode 100644 index 0000000000..cecdd4be82 --- /dev/null +++ b/skills/qr-code/scripts/qr_generate.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +""" +QR Code Generator - Create QR codes from text/URLs +Author: Omar Khaleel +License: MIT +""" + +import argparse +import sys + +try: + import qrcode + from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H +except ImportError: + print("Error: qrcode package not installed. Run: pip install qrcode pillow") + sys.exit(1) + + +ERROR_LEVELS = { + 'L': ERROR_CORRECT_L, # 7% error correction + 'M': ERROR_CORRECT_M, # 15% error correction + 'Q': ERROR_CORRECT_Q, # 25% error correction + 'H': ERROR_CORRECT_H, # 30% error correction +} + + +def generate_qr(data: str, output_path: str, box_size: int = 10, border: int = 4, error_level: str = 'M'): + """Generate a QR code and save it to a file.""" + + # FIX: Use version=None to allow automatic sizing for large data + qr = qrcode.QRCode( + version=None, + error_correction=ERROR_LEVELS.get(error_level.upper(), ERROR_CORRECT_M), + box_size=box_size, + border=border, + ) + + qr.add_data(data) + qr.make(fit=True) + + img = qr.make_image(fill_color="black", back_color="white") + img.save(output_path) + + return output_path + + +def main(): + parser = argparse.ArgumentParser(description='Generate QR codes from text or URLs') + parser.add_argument('data', help='Text or URL to encode in QR code') + parser.add_argument('output', help='Output file path (PNG)') + parser.add_argument('--size', type=int, default=10, help='Box size in pixels (default: 10)') + parser.add_argument('--border', type=int, default=4, help='Border size in boxes (default: 4)') + parser.add_argument('--error', choices=['L', 'M', 'Q', 'H'], default='M', + help='Error correction level: L=7%%, M=15%%, Q=25%%, H=30%% (default: M)') + + args = parser.parse_args() + + try: + output = generate_qr( + data=args.data, + output_path=args.output, + box_size=args.size, + border=args.border, + error_level=args.error + ) + print(f"QR code saved to: {output}") + except Exception as e: + print(f"Error generating QR code: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/skills/qr-code/scripts/qr_read.py b/skills/qr-code/scripts/qr_read.py new file mode 100644 index 0000000000..ee08bf914b --- /dev/null +++ b/skills/qr-code/scripts/qr_read.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +QR Code Reader - Decode QR codes from images +Author: Omar Khaleel +License: MIT +""" + +import argparse +import sys +import json + +try: + from PIL import Image +except ImportError: + print("Error: Pillow package not installed. Run: pip install pillow") + sys.exit(1) + +try: + from pyzbar.pyzbar import decode, ZBarSymbol +except ImportError: + print("Error: pyzbar package not installed. Run: pip install pyzbar") + print("Also install zbar library:") + print(" - Windows: Install Visual C++ Redistributable") + print(" - macOS: brew install zbar") + print(" - Linux: apt install libzbar0") + sys.exit(1) + + +def read_qr(image_path: str): + """Read QR code(s) from an image file.""" + + try: + img = Image.open(image_path) + except Exception as e: + raise ValueError(f"Could not open image: {e}") + + # Decode all QR codes in the image + decoded_objects = decode(img, symbols=[ZBarSymbol.QRCODE]) + + if not decoded_objects: + return None + + results = [] + for obj in decoded_objects: + result = { + # FIX: Use errors='replace' to prevent crashes on non-UTF8 payloads + 'data': obj.data.decode('utf-8', errors='replace'), + 'type': obj.type, + 'rect': { + 'left': obj.rect.left, + 'top': obj.rect.top, + 'width': obj.rect.width, + 'height': obj.rect.height + } + } + results.append(result) + + return results + + +def main(): + parser = argparse.ArgumentParser(description='Read/decode QR codes from images') + parser.add_argument('image', help='Path to image file containing QR code') + parser.add_argument('--json', action='store_true', help='Output as JSON') + parser.add_argument('--all', action='store_true', help='Show all QR codes found (not just first)') + + args = parser.parse_args() + + try: + results = read_qr(args.image) + + if not results: + print("No QR code found in image") + sys.exit(1) + + if args.json: + if args.all: + print(json.dumps(results, indent=2)) + else: + print(json.dumps(results[0], indent=2)) + else: + if args.all: + for i, r in enumerate(results, 1): + print(f"[{i}] {r['data']}") + else: + print(results[0]['data']) + + except Exception as e: + print(f"Error reading QR code: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file