fastqr 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/BUILD.md +482 -0
- data/CHANGELOG.md +51 -0
- data/CMakeLists.txt +126 -0
- data/CONTRIBUTING.md +63 -0
- data/DISTRIBUTION.md +730 -0
- data/INSTALL.md +171 -0
- data/LICENSE +39 -0
- data/PREBUILT.md +171 -0
- data/README.md +312 -0
- data/VERSION +1 -0
- data/bindings/nodejs/binding.gyp +38 -0
- data/bindings/nodejs/fastqr_node.cpp +125 -0
- data/bindings/nodejs/index.d.ts +80 -0
- data/bindings/nodejs/index.js +187 -0
- data/bindings/nodejs/lib/platform.js +72 -0
- data/bindings/nodejs/package.json +45 -0
- data/bindings/nodejs/test/test.js +45 -0
- data/bindings/php/fastqr_php.cpp +85 -0
- data/bindings/php/src/FastQR.php +316 -0
- data/bindings/php/tests/FastQRTest.php +97 -0
- data/bindings/ruby/extconf.rb +29 -0
- data/bindings/ruby/fastqr_ruby.cpp +122 -0
- data/bindings/ruby/lib/fastqr/platform.rb +70 -0
- data/bindings/ruby/lib/fastqr/version.rb +6 -0
- data/bindings/ruby/lib/fastqr.rb +129 -0
- data/bindings/ruby/prebuilt/macos-arm64.tar.gz +1 -0
- data/bindings/ruby/prebuilt/macos-x86_64.tar.gz +1 -0
- data/build.sh +109 -0
- data/cmake/fastqrConfig.cmake.in +6 -0
- data/composer.json +36 -0
- data/docs/CLI_USAGE.md +478 -0
- data/docs/NODEJS_USAGE.md +694 -0
- data/docs/PHP_USAGE.md +815 -0
- data/docs/README.md +191 -0
- data/docs/RUBY_USAGE.md +537 -0
- data/examples/CMakeLists.txt +7 -0
- data/examples/basic.cpp +58 -0
- data/include/fastqr.h +97 -0
- data/include/stb_image.h +7988 -0
- data/include/stb_image_write.h +1724 -0
- data/phpunit.xml +18 -0
- data/prebuilt/README.md +131 -0
- data/scripts/README.md +248 -0
- data/scripts/build-binaries.sh +98 -0
- data/scripts/build-local.sh +18 -0
- data/scripts/install.sh +87 -0
- data/scripts/release.sh +78 -0
- data/scripts/update-version.sh +58 -0
- data/src/cli.cpp +316 -0
- data/src/fastqr.cpp +665 -0
- data/test.sh +86 -0
- metadata +155 -0
data/docs/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# FastQR Documentation
|
|
2
|
+
|
|
3
|
+
Complete documentation for FastQR - Fast QR Code Generator.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
FastQR is a fast, powerful QR code generator with full UTF-8 support, custom colors, logo embedding, and precise size control. Pre-built binaries are included in all language packages - no system dependencies required!
|
|
8
|
+
|
|
9
|
+
## Quick Links
|
|
10
|
+
|
|
11
|
+
### Installation & Setup
|
|
12
|
+
- [Installation Guide](../INSTALL.md) - Installation for all platforms
|
|
13
|
+
- [Build Instructions](../BUILD.md) - Build from source
|
|
14
|
+
- [Distribution Guide](../DISTRIBUTION.md) - Publishing to package managers
|
|
15
|
+
- [Pre-built Binaries](../PREBUILT.md) - About pre-compiled binaries
|
|
16
|
+
|
|
17
|
+
### Usage Guides
|
|
18
|
+
- **[CLI Usage](CLI_USAGE.md)** - Command-line tool complete guide
|
|
19
|
+
- **[Ruby Usage](RUBY_USAGE.md)** - Ruby and Rails integration
|
|
20
|
+
- **[Node.js Usage](NODEJS_USAGE.md)** - Node.js and Express integration
|
|
21
|
+
- **[PHP Usage](PHP_USAGE.md)** - PHP, Laravel, and WordPress integration
|
|
22
|
+
|
|
23
|
+
### Project Information
|
|
24
|
+
- [README](../README.md) - Project overview and features
|
|
25
|
+
- [Contributing](../CONTRIBUTING.md) - How to contribute
|
|
26
|
+
- [Changelog](../CHANGELOG.md) - Version history
|
|
27
|
+
- [License](../LICENSE) - LGPL 2.1 license
|
|
28
|
+
|
|
29
|
+
## Features at a Glance
|
|
30
|
+
|
|
31
|
+
### ✨ Core Features
|
|
32
|
+
- 🚀 **High Performance** - No process forking, 2.6x faster than qrencode
|
|
33
|
+
- 🌐 **Full UTF-8 Support** - Vietnamese, Japanese, Chinese, emoji, etc.
|
|
34
|
+
- 📐 **Exact Size Control** - Generate QR codes with precise pixel dimensions
|
|
35
|
+
- 🎨 **Custom Colors** - RGB colors for QR code and background
|
|
36
|
+
- 🖼️ **Logo Embedding** - Add company logos to QR codes
|
|
37
|
+
- 🛡️ **Error Correction** - 4 levels (L, M, Q, H) up to 30% recovery
|
|
38
|
+
- 💾 **Multiple Formats** - PNG, JPG, WebP
|
|
39
|
+
|
|
40
|
+
### 📦 No Dependencies!
|
|
41
|
+
Starting from v1.0.0, all language packages include pre-built binaries:
|
|
42
|
+
- Ruby: `gem install fastqr` ✅
|
|
43
|
+
- Node.js: `npm install fastqr` ✅
|
|
44
|
+
- PHP: `composer require fastqr/fastqr` ✅
|
|
45
|
+
|
|
46
|
+
No need to install libqrencode or libvips separately!
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### CLI
|
|
51
|
+
```bash
|
|
52
|
+
# Install
|
|
53
|
+
brew install fastqr # macOS
|
|
54
|
+
|
|
55
|
+
# Use
|
|
56
|
+
fastqr "Hello World" qr.png
|
|
57
|
+
fastqr -s 1000x1000 -f 255,0,0 "Large Red QR" large.png
|
|
58
|
+
```
|
|
59
|
+
[→ Full CLI Guide](CLI_USAGE.md)
|
|
60
|
+
|
|
61
|
+
### Ruby
|
|
62
|
+
```ruby
|
|
63
|
+
gem install fastqr
|
|
64
|
+
|
|
65
|
+
require 'fastqr'
|
|
66
|
+
FastQR.generate("Hello World", "qr.png", width: 500, height: 500)
|
|
67
|
+
```
|
|
68
|
+
[→ Full Ruby Guide](RUBY_USAGE.md)
|
|
69
|
+
|
|
70
|
+
### Node.js
|
|
71
|
+
```javascript
|
|
72
|
+
npm install fastqr
|
|
73
|
+
|
|
74
|
+
const fastqr = require('fastqr');
|
|
75
|
+
fastqr.generate('Hello World', 'qr.png', { width: 500, height: 500 });
|
|
76
|
+
```
|
|
77
|
+
[→ Full Node.js Guide](NODEJS_USAGE.md)
|
|
78
|
+
|
|
79
|
+
### PHP
|
|
80
|
+
```php
|
|
81
|
+
composer require fastqr/fastqr
|
|
82
|
+
|
|
83
|
+
use FastQR\FastQR;
|
|
84
|
+
FastQR::generate('Hello World', 'qr.png', ['width' => 500, 'height' => 500]);
|
|
85
|
+
```
|
|
86
|
+
[→ Full PHP Guide](PHP_USAGE.md)
|
|
87
|
+
|
|
88
|
+
## Common Use Cases
|
|
89
|
+
|
|
90
|
+
### 1. Website QR Codes
|
|
91
|
+
Generate QR codes for URLs with custom branding:
|
|
92
|
+
```bash
|
|
93
|
+
fastqr -s 600x600 -l logo.png -e H "https://example.com" website_qr.png
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2. Business Cards (vCard)
|
|
97
|
+
```bash
|
|
98
|
+
fastqr "BEGIN:VCARD
|
|
99
|
+
VERSION:3.0
|
|
100
|
+
FN:John Doe
|
|
101
|
+
EMAIL:john@example.com
|
|
102
|
+
TEL:+1234567890
|
|
103
|
+
END:VCARD" vcard.png
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. WiFi Credentials
|
|
107
|
+
```bash
|
|
108
|
+
fastqr "WIFI:T:WPA;S:NetworkName;P:password123;;" wifi.png
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. Event Information
|
|
112
|
+
With full UTF-8 support:
|
|
113
|
+
```bash
|
|
114
|
+
fastqr "Sự kiện: Hội thảo công nghệ
|
|
115
|
+
Thời gian: 20/10/2025
|
|
116
|
+
Địa điểm: TP.HCM
|
|
117
|
+
URL: https://event.com" event.png
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 5. Product Labels
|
|
121
|
+
High-resolution QR for printing:
|
|
122
|
+
```bash
|
|
123
|
+
fastqr -s 2000x2000 -q 100 -e H "SKU-12345" product_qr.png
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Platform Comparison
|
|
127
|
+
|
|
128
|
+
| Feature | CLI | Ruby | Node.js | PHP |
|
|
129
|
+
|---------|-----|------|---------|-----|
|
|
130
|
+
| **Installation** | `brew install` | `gem install` | `npm install` | `composer require` |
|
|
131
|
+
| **Dependencies** | ✅ None (binary) | ✅ None (bundled) | ✅ None (bundled) | ✅ None (bundled) |
|
|
132
|
+
| **UTF-8** | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
|
|
133
|
+
| **Colors** | ✅ RGB | ✅ RGB | ✅ RGB | ✅ RGB |
|
|
134
|
+
| **Logo** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
135
|
+
| **Async** | - | ✅ Yes | ✅ Yes | - |
|
|
136
|
+
| **TypeScript** | - | - | ✅ Yes | - |
|
|
137
|
+
|
|
138
|
+
## API Quick Reference
|
|
139
|
+
|
|
140
|
+
### Options (All Languages)
|
|
141
|
+
|
|
142
|
+
| Option | CLI | Ruby | Node.js | PHP | Default |
|
|
143
|
+
|--------|-----|------|---------|-----|---------|
|
|
144
|
+
| **Size** | `-s 500x500` | `width: 500, height: 500` | `{width: 500, height: 500}` | `['width' => 500, 'height' => 500]` | 300x300 |
|
|
145
|
+
| **Foreground** | `-f 255,0,0` | `foreground: [255,0,0]` | `{foreground: [255,0,0]}` | `['foreground' => [255,0,0]]` | [0,0,0] |
|
|
146
|
+
| **Background** | `-b 255,255,200` | `background: [255,255,200]` | `{background: [255,255,200]}` | `['background' => [255,255,200]]` | [255,255,255] |
|
|
147
|
+
| **Error Level** | `-e H` | `error_level: 'H'` | `{errorLevel: 'H'}` | `['errorLevel' => 'H']` | 'M' |
|
|
148
|
+
| **Logo** | `-l logo.png` | `logo: 'logo.png'` | `{logo: 'logo.png'}` | `['logo' => 'logo.png']` | - |
|
|
149
|
+
| **Logo Size** | `-p 25` | `logo_size: 25` | `{logoSize: 25}` | `['logoSize' => 25]` | 20 |
|
|
150
|
+
| **Quality** | `-q 95` | `quality: 95` | `{quality: 95}` | `['quality' => 95]` | 95 |
|
|
151
|
+
|
|
152
|
+
## Getting Help
|
|
153
|
+
|
|
154
|
+
- **Documentation**: You're here! Browse the usage guides above
|
|
155
|
+
- **Issues**: [GitHub Issues](https://github.com/tranhuucanh/fastqr/issues)
|
|
156
|
+
- **Contributing**: See [CONTRIBUTING.md](../CONTRIBUTING.md)
|
|
157
|
+
- **License**: See [LICENSE](../LICENSE) (LGPL 2.1)
|
|
158
|
+
|
|
159
|
+
## Architecture
|
|
160
|
+
|
|
161
|
+
FastQR is built on:
|
|
162
|
+
- **[libqrencode](https://fukuchi.org/works/qrencode/)** (LGPL v2.1) - QR code generation
|
|
163
|
+
- **[libvips](https://libvips.github.io/libvips/)** (LGPL v2.1+) - Image processing
|
|
164
|
+
|
|
165
|
+
Pre-built binaries are automatically generated for:
|
|
166
|
+
- macOS (Intel & Apple Silicon)
|
|
167
|
+
- Linux (x86_64 & ARM64)
|
|
168
|
+
|
|
169
|
+
See [PREBUILT.md](../PREBUILT.md) for details on the build process.
|
|
170
|
+
|
|
171
|
+
## Support
|
|
172
|
+
|
|
173
|
+
FastQR is open source software. For support:
|
|
174
|
+
|
|
175
|
+
1. Check the relevant usage guide above
|
|
176
|
+
2. Search [existing issues](https://github.com/tranhuucanh/fastqr/issues)
|
|
177
|
+
3. Open a new issue if needed
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
FastQR is licensed under LGPL 2.1. See [LICENSE](../LICENSE) for details.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
**Made with ❤️ by the FastQR Project**
|
|
186
|
+
|
|
187
|
+
[GitHub](https://github.com/tranhuucanh/fastqr) •
|
|
188
|
+
[npm](https://www.npmjs.com/package/fastqr) •
|
|
189
|
+
[RubyGems](https://rubygems.org/gems/fastqr) •
|
|
190
|
+
[Packagist](https://packagist.org/packages/fastqr/fastqr)
|
|
191
|
+
|
data/docs/RUBY_USAGE.md
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# FastQR Ruby/Rails Usage Guide
|
|
2
|
+
|
|
3
|
+
Complete guide for using FastQR in Ruby and Ruby on Rails applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
gem install fastqr
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or add to your `Gemfile`:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem 'fastqr', '~> 1.0'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then run:
|
|
18
|
+
```bash
|
|
19
|
+
bundle install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Note:** No system dependencies required! Pre-built binaries are included. 🎉
|
|
23
|
+
|
|
24
|
+
## Basic Usage
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
require 'fastqr'
|
|
28
|
+
|
|
29
|
+
# Generate QR code
|
|
30
|
+
FastQR.generate("Hello World", "qr.png")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API Reference
|
|
34
|
+
|
|
35
|
+
### `FastQR.generate(data, output_path, options = {})`
|
|
36
|
+
|
|
37
|
+
Generate a QR code and save to file.
|
|
38
|
+
|
|
39
|
+
**Parameters:**
|
|
40
|
+
- `data` (String, required) - Data to encode (UTF-8 supported)
|
|
41
|
+
- `output_path` (String, required) - Path to save the QR code image
|
|
42
|
+
- `options` (Hash, optional) - Generation options
|
|
43
|
+
|
|
44
|
+
**Returns:** `true` if successful
|
|
45
|
+
|
|
46
|
+
**Raises:** `FastQR::Error` if generation fails
|
|
47
|
+
|
|
48
|
+
### Options
|
|
49
|
+
|
|
50
|
+
| Option | Type | Default | Description |
|
|
51
|
+
|--------|------|---------|-------------|
|
|
52
|
+
| `:size` | Integer | `300` | Output size in pixels (QR codes are square) |
|
|
53
|
+
| `:optimize_size` | Boolean | `false` | Auto round-up for best performance |
|
|
54
|
+
| `:width` | Integer | - | (Deprecated) Use `:size` instead |
|
|
55
|
+
| `:height` | Integer | - | (Deprecated) Use `:size` instead |
|
|
56
|
+
| `:foreground` | Array[3] | `[0, 0, 0]` | QR code color (RGB) |
|
|
57
|
+
| `:background` | Array[3] | `[255, 255, 255]` | Background color (RGB) |
|
|
58
|
+
| `:error_level` | String | `'M'` | Error correction: 'L', 'M', 'Q', 'H' |
|
|
59
|
+
| `:logo` | String | `nil` | Path to logo image |
|
|
60
|
+
| `:logo_size` | Integer | `20` | Logo size as percentage (1-50) |
|
|
61
|
+
| `:quality` | Integer | `95` | Image quality (1-100) |
|
|
62
|
+
| `:format` | String | `'png'` | Output format: 'png', 'jpg', 'webp' |
|
|
63
|
+
|
|
64
|
+
### `FastQR.generate_batch(data_array, output_dir, options = {})`
|
|
65
|
+
|
|
66
|
+
Generate multiple QR codes at once - **7x faster** than calling `generate` multiple times!
|
|
67
|
+
|
|
68
|
+
**Parameters:**
|
|
69
|
+
- `data_array` (Array[String], required) - Array of strings to encode
|
|
70
|
+
- `output_dir` (String, required) - Directory to save QR codes (created if doesn't exist)
|
|
71
|
+
- `options` (Hash, optional) - Same options as `generate`
|
|
72
|
+
|
|
73
|
+
**Returns:** Hash with `:success` and `:failed` counts
|
|
74
|
+
|
|
75
|
+
**Example:**
|
|
76
|
+
```ruby
|
|
77
|
+
data = ["QR 1", "QR 2", "QR 3"]
|
|
78
|
+
FastQR.generate_batch(data, "output/", size: 500, optimize_size: true)
|
|
79
|
+
# Creates: output/1.png, output/2.png, output/3.png
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `FastQR.version`
|
|
83
|
+
|
|
84
|
+
Get library version.
|
|
85
|
+
|
|
86
|
+
**Returns:** String (e.g., "1.0.0")
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
puts FastQR.version
|
|
90
|
+
# => "1.0.0"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
### 1. Basic QR Code
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
FastQR.generate("https://example.com", "qr.png")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2. Custom Size
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
FastQR.generate("Large QR", "large.png",
|
|
105
|
+
size: 1000
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Optimized Size (faster generation)
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
FastQR.generate("Fast QR", "fast.png",
|
|
113
|
+
size: 500,
|
|
114
|
+
optimize_size: true
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 4. Colored QR Code
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
# Red QR on yellow background
|
|
122
|
+
FastQR.generate("Colored", "colored.png",
|
|
123
|
+
size: 500,
|
|
124
|
+
foreground: [255, 0, 0], # Red
|
|
125
|
+
background: [255, 255, 200] # Light yellow
|
|
126
|
+
)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 5. QR Code with Logo
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
FastQR.generate("Company", "company.png",
|
|
133
|
+
size: 800,
|
|
134
|
+
logo: "logo.png",
|
|
135
|
+
logo_size: 25,
|
|
136
|
+
error_level: 'H' # High error correction for logo
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 6. High Error Correction
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
FastQR.generate("Important Data", "qr.png",
|
|
144
|
+
error_level: 'H' # ~30% recovery capability
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 7. UTF-8 Support
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
# Vietnamese
|
|
152
|
+
FastQR.generate("Xin chào Việt Nam! 🇻🇳", "vietnamese.png")
|
|
153
|
+
|
|
154
|
+
# Japanese
|
|
155
|
+
FastQR.generate("こんにちは日本", "japanese.png")
|
|
156
|
+
|
|
157
|
+
# Emoji
|
|
158
|
+
FastQR.generate("Hello 👋 World 🌍", "emoji.png")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 8. Different Formats
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# PNG (default)
|
|
165
|
+
FastQR.generate("Data", "output.png")
|
|
166
|
+
|
|
167
|
+
# JPEG
|
|
168
|
+
FastQR.generate("Data", "output.jpg", quality: 90)
|
|
169
|
+
|
|
170
|
+
# WebP
|
|
171
|
+
FastQR.generate("Data", "output.webp", quality: 85)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 9. Batch Generation (7x faster!)
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
# Generate 1000 QR codes
|
|
178
|
+
data = (1..1000).map { |i| "Product #{i}" }
|
|
179
|
+
|
|
180
|
+
# Old way (slow - ~3 seconds)
|
|
181
|
+
# data.each_with_index do |text, i|
|
|
182
|
+
# FastQR.generate(text, "qr_#{i+1}.png", size: 500)
|
|
183
|
+
# end
|
|
184
|
+
|
|
185
|
+
# New way (fast - ~0.4 seconds!)
|
|
186
|
+
result = FastQR.generate_batch(data, "qr_codes/",
|
|
187
|
+
size: 500,
|
|
188
|
+
optimize_size: true
|
|
189
|
+
)
|
|
190
|
+
puts "Generated #{result[:success]} QR codes"
|
|
191
|
+
# Creates: qr_codes/1.png, qr_codes/2.png, ..., qr_codes/1000.png
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Rails Integration
|
|
195
|
+
|
|
196
|
+
### Controller Example
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
class QrCodesController < ApplicationController
|
|
200
|
+
def create
|
|
201
|
+
url = params[:url]
|
|
202
|
+
filename = "qr_#{SecureRandom.hex(8)}.png"
|
|
203
|
+
filepath = Rails.root.join('public', 'qrcodes', filename)
|
|
204
|
+
|
|
205
|
+
# Ensure directory exists
|
|
206
|
+
FileUtils.mkdir_p(File.dirname(filepath))
|
|
207
|
+
|
|
208
|
+
# Generate QR code
|
|
209
|
+
FastQR.generate(url, filepath.to_s,
|
|
210
|
+
width: 500,
|
|
211
|
+
height: 500,
|
|
212
|
+
error_level: 'M'
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Send file to user
|
|
216
|
+
send_file filepath, type: 'image/png', disposition: 'inline'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def generate_with_logo
|
|
220
|
+
data = params[:data]
|
|
221
|
+
logo_path = Rails.root.join('app', 'assets', 'images', 'logo.png')
|
|
222
|
+
output_path = Rails.root.join('tmp', "qr_#{Time.now.to_i}.png")
|
|
223
|
+
|
|
224
|
+
FastQR.generate(data, output_path.to_s,
|
|
225
|
+
width: 600,
|
|
226
|
+
height: 600,
|
|
227
|
+
logo: logo_path.to_s,
|
|
228
|
+
logo_size: 25,
|
|
229
|
+
error_level: 'H',
|
|
230
|
+
foreground: [0, 100, 200]
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
send_file output_path, type: 'image/png'
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Model Example
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
class Event < ApplicationRecord
|
|
242
|
+
after_create :generate_qr_code
|
|
243
|
+
|
|
244
|
+
def qr_code_path
|
|
245
|
+
Rails.root.join('public', 'events', 'qrcodes', "#{id}.png")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def generate_qr_code
|
|
249
|
+
FileUtils.mkdir_p(File.dirname(qr_code_path))
|
|
250
|
+
|
|
251
|
+
event_info = <<~INFO
|
|
252
|
+
Event: #{name}
|
|
253
|
+
Date: #{event_date.strftime('%d/%m/%Y')}
|
|
254
|
+
Location: #{location}
|
|
255
|
+
URL: #{url}
|
|
256
|
+
INFO
|
|
257
|
+
|
|
258
|
+
FastQR.generate(event_info, qr_code_path.to_s,
|
|
259
|
+
width: 500,
|
|
260
|
+
height: 500,
|
|
261
|
+
error_level: 'H'
|
|
262
|
+
)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def qr_code_url
|
|
266
|
+
"/events/qrcodes/#{id}.png"
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### View Helper
|
|
272
|
+
|
|
273
|
+
```ruby
|
|
274
|
+
# app/helpers/qr_code_helper.rb
|
|
275
|
+
module QrCodeHelper
|
|
276
|
+
def generate_inline_qr(data, options = {})
|
|
277
|
+
filename = "qr_#{Digest::MD5.hexdigest(data)}.png"
|
|
278
|
+
filepath = Rails.root.join('tmp', filename)
|
|
279
|
+
|
|
280
|
+
unless File.exist?(filepath)
|
|
281
|
+
FastQR.generate(data, filepath.to_s, options)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
image_tag("/tmp/#{filename}", alt: 'QR Code', class: 'qr-code')
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Background Job Example (Sidekiq)
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
class GenerateQrCodeJob < ApplicationJob
|
|
293
|
+
queue_as :default
|
|
294
|
+
|
|
295
|
+
def perform(user_id)
|
|
296
|
+
user = User.find(user_id)
|
|
297
|
+
vcard = generate_vcard(user)
|
|
298
|
+
output_path = Rails.root.join('public', 'users', 'qrcodes', "#{user.id}.png")
|
|
299
|
+
|
|
300
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
301
|
+
|
|
302
|
+
FastQR.generate(vcard, output_path.to_s,
|
|
303
|
+
width: 600,
|
|
304
|
+
height: 600,
|
|
305
|
+
error_level: 'H'
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
user.update(qr_code_generated: true)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
private
|
|
312
|
+
|
|
313
|
+
def generate_vcard(user)
|
|
314
|
+
<<~VCARD
|
|
315
|
+
BEGIN:VCARD
|
|
316
|
+
VERSION:3.0
|
|
317
|
+
FN:#{user.full_name}
|
|
318
|
+
EMAIL:#{user.email}
|
|
319
|
+
TEL:#{user.phone}
|
|
320
|
+
END:VCARD
|
|
321
|
+
VCARD
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### API Endpoint Example
|
|
327
|
+
|
|
328
|
+
```ruby
|
|
329
|
+
# app/controllers/api/v1/qr_codes_controller.rb
|
|
330
|
+
module Api
|
|
331
|
+
module V1
|
|
332
|
+
class QrCodesController < ApplicationController
|
|
333
|
+
def create
|
|
334
|
+
data = qr_params[:data]
|
|
335
|
+
options = build_options(qr_params)
|
|
336
|
+
|
|
337
|
+
# Generate to temp file
|
|
338
|
+
filename = "qr_#{SecureRandom.uuid}.png"
|
|
339
|
+
filepath = Rails.root.join('tmp', filename)
|
|
340
|
+
|
|
341
|
+
FastQR.generate(data, filepath.to_s, options)
|
|
342
|
+
|
|
343
|
+
# Return base64 encoded image
|
|
344
|
+
image_data = File.read(filepath)
|
|
345
|
+
base64_image = Base64.strict_encode64(image_data)
|
|
346
|
+
|
|
347
|
+
File.delete(filepath)
|
|
348
|
+
|
|
349
|
+
render json: {
|
|
350
|
+
success: true,
|
|
351
|
+
image: "data:image/png;base64,#{base64_image}",
|
|
352
|
+
filename: filename
|
|
353
|
+
}
|
|
354
|
+
rescue FastQR::Error => e
|
|
355
|
+
render json: { success: false, error: e.message }, status: :unprocessable_entity
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
private
|
|
359
|
+
|
|
360
|
+
def qr_params
|
|
361
|
+
params.permit(:data, :width, :height, :error_level, :quality)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def build_options(params)
|
|
365
|
+
{}.tap do |opts|
|
|
366
|
+
opts[:width] = params[:width].to_i if params[:width]
|
|
367
|
+
opts[:height] = params[:height].to_i if params[:height]
|
|
368
|
+
opts[:error_level] = params[:error_level] if params[:error_level]
|
|
369
|
+
opts[:quality] = params[:quality].to_i if params[:quality]
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Advanced Usage
|
|
378
|
+
|
|
379
|
+
### Batch Generation
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
urls = [
|
|
383
|
+
"https://example.com/page1",
|
|
384
|
+
"https://example.com/page2",
|
|
385
|
+
"https://example.com/page3"
|
|
386
|
+
]
|
|
387
|
+
|
|
388
|
+
urls.each_with_index do |url, index|
|
|
389
|
+
FastQR.generate(url, "qr_#{index + 1}.png",
|
|
390
|
+
width: 500,
|
|
391
|
+
height: 500
|
|
392
|
+
)
|
|
393
|
+
end
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Dynamic Colors
|
|
397
|
+
|
|
398
|
+
```ruby
|
|
399
|
+
def generate_branded_qr(data, brand_color)
|
|
400
|
+
r, g, b = brand_color
|
|
401
|
+
|
|
402
|
+
FastQR.generate(data, "branded_qr.png",
|
|
403
|
+
width: 600,
|
|
404
|
+
height: 600,
|
|
405
|
+
foreground: [r, g, b],
|
|
406
|
+
background: [255, 255, 255],
|
|
407
|
+
error_level: 'H'
|
|
408
|
+
)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
generate_branded_qr("Company Data", [0, 120, 215]) # Microsoft blue
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Error Handling
|
|
415
|
+
|
|
416
|
+
```ruby
|
|
417
|
+
begin
|
|
418
|
+
FastQR.generate("Data", "output.png",
|
|
419
|
+
width: 1000,
|
|
420
|
+
height: 1000
|
|
421
|
+
)
|
|
422
|
+
puts "✓ QR code generated successfully"
|
|
423
|
+
rescue FastQR::Error => e
|
|
424
|
+
puts "✗ Failed to generate QR code: #{e.message}"
|
|
425
|
+
# Log error or notify admin
|
|
426
|
+
Rails.logger.error("QR generation failed: #{e.message}")
|
|
427
|
+
end
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Validation Helper
|
|
431
|
+
|
|
432
|
+
```ruby
|
|
433
|
+
class QrCodeValidator
|
|
434
|
+
def self.valid_size?(width, height)
|
|
435
|
+
width.between?(100, 5000) && height.between?(100, 5000)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def self.valid_error_level?(level)
|
|
439
|
+
%w[L M Q H].include?(level.to_s.upcase)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def self.validate_options(options)
|
|
443
|
+
errors = []
|
|
444
|
+
|
|
445
|
+
if options[:width] || options[:height]
|
|
446
|
+
w = options[:width] || 300
|
|
447
|
+
h = options[:height] || 300
|
|
448
|
+
errors << "Invalid size" unless valid_size?(w, h)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
if options[:error_level]
|
|
452
|
+
errors << "Invalid error level" unless valid_error_level?(options[:error_level])
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
errors
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Testing
|
|
461
|
+
|
|
462
|
+
### RSpec Example
|
|
463
|
+
|
|
464
|
+
```ruby
|
|
465
|
+
# spec/services/qr_code_generator_spec.rb
|
|
466
|
+
require 'rails_helper'
|
|
467
|
+
|
|
468
|
+
RSpec.describe 'QR Code Generation' do
|
|
469
|
+
let(:output_path) { Rails.root.join('tmp', 'test_qr.png') }
|
|
470
|
+
|
|
471
|
+
after do
|
|
472
|
+
File.delete(output_path) if File.exist?(output_path)
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
it 'generates a basic QR code' do
|
|
476
|
+
result = FastQR.generate("Test Data", output_path.to_s)
|
|
477
|
+
|
|
478
|
+
expect(result).to be true
|
|
479
|
+
expect(File.exist?(output_path)).to be true
|
|
480
|
+
expect(File.size(output_path)).to be > 0
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it 'generates QR code with custom options' do
|
|
484
|
+
result = FastQR.generate("Test", output_path.to_s,
|
|
485
|
+
width: 500,
|
|
486
|
+
height: 500,
|
|
487
|
+
error_level: 'H'
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
expect(result).to be true
|
|
491
|
+
expect(File.exist?(output_path)).to be true
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
it 'raises error for empty data' do
|
|
495
|
+
expect {
|
|
496
|
+
FastQR.generate("", output_path.to_s)
|
|
497
|
+
}.to raise_error(FastQR::Error, /cannot be empty/)
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## Performance Tips
|
|
503
|
+
|
|
504
|
+
- Generate QR codes in background jobs for large batches
|
|
505
|
+
- Cache generated QR codes (use MD5 hash of data as filename)
|
|
506
|
+
- Use lower quality settings for web display (`quality: 75`)
|
|
507
|
+
- Use PNG for best quality, JPG for smaller files
|
|
508
|
+
|
|
509
|
+
## Troubleshooting
|
|
510
|
+
|
|
511
|
+
### "Library not found" Error
|
|
512
|
+
|
|
513
|
+
The gem includes pre-built binaries. If you see this error:
|
|
514
|
+
|
|
515
|
+
```ruby
|
|
516
|
+
# Check if binary is available
|
|
517
|
+
puts FastQR::Platform.platform
|
|
518
|
+
puts FastQR::Platform.lib_path
|
|
519
|
+
puts File.exist?(FastQR::Platform.lib_path)
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### QR Code Not Generated
|
|
523
|
+
|
|
524
|
+
Check file permissions and ensure output directory exists:
|
|
525
|
+
|
|
526
|
+
```ruby
|
|
527
|
+
require 'fileutils'
|
|
528
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## See Also
|
|
532
|
+
|
|
533
|
+
- [CLI Usage](CLI_USAGE.md) - Command-line usage
|
|
534
|
+
- [Node.js Usage](NODEJS_USAGE.md) - Node.js guide
|
|
535
|
+
- [PHP Usage](PHP_USAGE.md) - PHP guide
|
|
536
|
+
- [GitHub Repository](https://github.com/tranhuucanh/fastqr)
|
|
537
|
+
|