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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/BUILD.md +482 -0
  3. data/CHANGELOG.md +51 -0
  4. data/CMakeLists.txt +126 -0
  5. data/CONTRIBUTING.md +63 -0
  6. data/DISTRIBUTION.md +730 -0
  7. data/INSTALL.md +171 -0
  8. data/LICENSE +39 -0
  9. data/PREBUILT.md +171 -0
  10. data/README.md +312 -0
  11. data/VERSION +1 -0
  12. data/bindings/nodejs/binding.gyp +38 -0
  13. data/bindings/nodejs/fastqr_node.cpp +125 -0
  14. data/bindings/nodejs/index.d.ts +80 -0
  15. data/bindings/nodejs/index.js +187 -0
  16. data/bindings/nodejs/lib/platform.js +72 -0
  17. data/bindings/nodejs/package.json +45 -0
  18. data/bindings/nodejs/test/test.js +45 -0
  19. data/bindings/php/fastqr_php.cpp +85 -0
  20. data/bindings/php/src/FastQR.php +316 -0
  21. data/bindings/php/tests/FastQRTest.php +97 -0
  22. data/bindings/ruby/extconf.rb +29 -0
  23. data/bindings/ruby/fastqr_ruby.cpp +122 -0
  24. data/bindings/ruby/lib/fastqr/platform.rb +70 -0
  25. data/bindings/ruby/lib/fastqr/version.rb +6 -0
  26. data/bindings/ruby/lib/fastqr.rb +129 -0
  27. data/bindings/ruby/prebuilt/macos-arm64.tar.gz +1 -0
  28. data/bindings/ruby/prebuilt/macos-x86_64.tar.gz +1 -0
  29. data/build.sh +109 -0
  30. data/cmake/fastqrConfig.cmake.in +6 -0
  31. data/composer.json +36 -0
  32. data/docs/CLI_USAGE.md +478 -0
  33. data/docs/NODEJS_USAGE.md +694 -0
  34. data/docs/PHP_USAGE.md +815 -0
  35. data/docs/README.md +191 -0
  36. data/docs/RUBY_USAGE.md +537 -0
  37. data/examples/CMakeLists.txt +7 -0
  38. data/examples/basic.cpp +58 -0
  39. data/include/fastqr.h +97 -0
  40. data/include/stb_image.h +7988 -0
  41. data/include/stb_image_write.h +1724 -0
  42. data/phpunit.xml +18 -0
  43. data/prebuilt/README.md +131 -0
  44. data/scripts/README.md +248 -0
  45. data/scripts/build-binaries.sh +98 -0
  46. data/scripts/build-local.sh +18 -0
  47. data/scripts/install.sh +87 -0
  48. data/scripts/release.sh +78 -0
  49. data/scripts/update-version.sh +58 -0
  50. data/src/cli.cpp +316 -0
  51. data/src/fastqr.cpp +665 -0
  52. data/test.sh +86 -0
  53. 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
+
@@ -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
+