mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
feat(skills): add QR code skill (#8817)
feat(skills): add QR code generation and reading skill Adds qr-code skill with: - qr_generate.py - Generate QR codes with customizable size/error correction - qr_read.py - Decode QR codes from images - SKILL.md documentation Co-authored-by: Omar-Khaleel
This commit is contained in:
86
skills/qr-code/SKILL.md
Normal file
86
skills/qr-code/SKILL.md
Normal file
@@ -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
|
||||||
73
skills/qr-code/scripts/qr_generate.py
Normal file
73
skills/qr-code/scripts/qr_generate.py
Normal file
@@ -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()
|
||||||
94
skills/qr-code/scripts/qr_read.py
Normal file
94
skills/qr-code/scripts/qr_read.py
Normal file
@@ -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()
|
||||||
Reference in New Issue
Block a user