fastqr 1.0.21 → 1.0.22
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 +4 -4
- data/CMakeLists.txt +1 -1
- data/README.md +40 -10
- data/VERSION +1 -1
- data/bindings/nodejs/README.md +40 -10
- data/bindings/nodejs/package.json +1 -1
- data/bindings/php/src/FastQR.php +89 -127
- data/bindings/ruby/lib/fastqr/version.rb +1 -1
- data/bindings/ruby/prebuilt/linux-aarch64/bin/fastqr +0 -0
- data/bindings/ruby/prebuilt/linux-aarch64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/linux-x86_64/bin/fastqr +0 -0
- data/bindings/ruby/prebuilt/linux-x86_64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/macos-arm64/bin/fastqr +0 -0
- data/bindings/ruby/prebuilt/macos-arm64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/macos-x86_64/bin/fastqr +0 -0
- data/bindings/ruby/prebuilt/macos-x86_64.tar.gz +0 -0
- data/composer.json +1 -2
- data/src/fastqr.cpp +2 -44
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aff7c95cab07028186bd084c85b41df28746894da389a71fdd118802a7d12865
|
|
4
|
+
data.tar.gz: 801a340686726e8f3cbb89e7dd8f22654b3492a1cf9f807268b8755d8193a924
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a825cb5a67dabe337adc4ce871fe193f3f80431474c6d7f820013cc474a5be7e1ec298d95b92be6467ac72aaa0d8f645d620dbb5cb3d362d825e6acf16ff46d
|
|
7
|
+
data.tar.gz: 9f0bf9ca976913710ff145dea0b5b05be1cce18936729dcac0741dacd83c356cf83258ef851126f10ee1b8615efa2861d1552641bff93ce35799fbb3380f40b2
|
data/CMakeLists.txt
CHANGED
data/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
18
18
|
|
|
19
19
|
## 🔥 Performance Benchmarks
|
|
20
20
|
|
|
21
|
-
### CLI Performance: FastQR vs qrencode
|
|
21
|
+
### ⌨️ CLI Performance: FastQR vs qrencode
|
|
22
22
|
|
|
23
23
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
-
### Ruby Performance: FastQR vs rqrcode
|
|
34
|
+
### 💎 Ruby Performance: FastQR vs rqrcode
|
|
35
35
|
|
|
36
36
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
37
37
|
|
|
@@ -44,7 +44,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
### Node.js Performance: FastQR vs qrcode
|
|
47
|
+
### 🟢 Node.js Performance: FastQR vs qrcode
|
|
48
48
|
|
|
49
49
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
50
50
|
|
|
@@ -57,17 +57,31 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
+
### 🐘 PHP Performance: FastQR vs endroid/qr-code
|
|
61
|
+
|
|
62
|
+
*Task: Generate 1,000 QR codes (500×500px)*
|
|
63
|
+
|
|
64
|
+
| Library | Sequential Mode | Batch Mode | Speedup |
|
|
65
|
+
|---------|----------------|------------|---------|
|
|
66
|
+
| **FastQR** | 1.75s 🚀 | **0.64s** ⚡ | **8.4x faster** with batch |
|
|
67
|
+
| endroid/qr-code | 14.72s 🐌 | ❌ Not supported | - |
|
|
68
|
+
|
|
69
|
+
**FastQR is 8.4x faster in sequential mode and 23x faster with batch mode!**
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
60
73
|
## 💪 Why FastQR Dominates
|
|
61
74
|
|
|
62
75
|
### Speed Comparison Summary
|
|
63
76
|
|
|
64
77
|
| Platform | Library | Sequential | Batch | FastQR Advantage |
|
|
65
78
|
|----------|---------|------------|-------|------------------|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
79
|
+
| **⌨️ CLI** | qrencode | 2.97s | ❌ | **8x faster** ⚡ |
|
|
80
|
+
| **💎 Ruby** | rqrcode | 59.45s | ❌ | **157x faster** 🚀 |
|
|
81
|
+
| **🟢 Node.js** | qrcode | 17.25s | ❌ | **37x faster** ⚡ |
|
|
82
|
+
| **🐘 PHP** | endroid/qr-code | 14.72s | ❌ | **23x faster** 🚀 |
|
|
69
83
|
|
|
70
|
-
**Average: FastQR with batch mode is
|
|
84
|
+
**Average: FastQR with batch mode is 56x faster than popular alternatives!**
|
|
71
85
|
|
|
72
86
|
---
|
|
73
87
|
|
|
@@ -111,10 +125,26 @@ brew tap tranhuucanh/fastqr
|
|
|
111
125
|
brew install fastqr
|
|
112
126
|
```
|
|
113
127
|
|
|
114
|
-
**
|
|
128
|
+
**Linux (x86_64):**
|
|
129
|
+
```bash
|
|
130
|
+
# Download latest release (replace VERSION with latest version, e.g., 1.0.21)
|
|
131
|
+
VERSION="1.0.21"
|
|
132
|
+
wget https://github.com/tranhuucanh/fastqr/releases/download/v${VERSION}/fastqr-${VERSION}-linux-x86_64.tar.gz
|
|
133
|
+
tar -xzf fastqr-${VERSION}-linux-x86_64.tar.gz
|
|
134
|
+
sudo cp linux-x86_64/bin/fastqr /usr/local/bin/
|
|
135
|
+
sudo chmod +x /usr/local/bin/fastqr
|
|
136
|
+
|
|
137
|
+
# Verify installation
|
|
138
|
+
fastqr --version
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Linux (ARM64/aarch64):**
|
|
115
142
|
```bash
|
|
116
|
-
|
|
117
|
-
|
|
143
|
+
VERSION="1.0.21"
|
|
144
|
+
wget https://github.com/tranhuucanh/fastqr/releases/download/v${VERSION}/fastqr-${VERSION}-linux-aarch64.tar.gz
|
|
145
|
+
tar -xzf fastqr-${VERSION}-linux-aarch64.tar.gz
|
|
146
|
+
sudo cp linux-aarch64/bin/fastqr /usr/local/bin/
|
|
147
|
+
sudo chmod +x /usr/local/bin/fastqr
|
|
118
148
|
```
|
|
119
149
|
|
|
120
150
|
### Language Packages
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.22
|
data/bindings/nodejs/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
18
18
|
|
|
19
19
|
## 🔥 Performance Benchmarks
|
|
20
20
|
|
|
21
|
-
### CLI Performance: FastQR vs qrencode
|
|
21
|
+
### ⌨️ CLI Performance: FastQR vs qrencode
|
|
22
22
|
|
|
23
23
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
-
### Ruby Performance: FastQR vs rqrcode
|
|
34
|
+
### 💎 Ruby Performance: FastQR vs rqrcode
|
|
35
35
|
|
|
36
36
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
37
37
|
|
|
@@ -44,7 +44,7 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
### Node.js Performance: FastQR vs qrcode
|
|
47
|
+
### 🟢 Node.js Performance: FastQR vs qrcode
|
|
48
48
|
|
|
49
49
|
*Task: Generate 1,000 QR codes (500×500px)*
|
|
50
50
|
|
|
@@ -57,17 +57,31 @@ Generate 1,000 QR codes in **0.37 seconds**. Full UTF-8 support. Custom colors.
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
+
### 🐘 PHP Performance: FastQR vs endroid/qr-code
|
|
61
|
+
|
|
62
|
+
*Task: Generate 1,000 QR codes (500×500px)*
|
|
63
|
+
|
|
64
|
+
| Library | Sequential Mode | Batch Mode | Speedup |
|
|
65
|
+
|---------|----------------|------------|---------|
|
|
66
|
+
| **FastQR** | 1.75s 🚀 | **0.64s** ⚡ | **8.4x faster** with batch |
|
|
67
|
+
| endroid/qr-code | 14.72s 🐌 | ❌ Not supported | - |
|
|
68
|
+
|
|
69
|
+
**FastQR is 8.4x faster in sequential mode and 23x faster with batch mode!**
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
60
73
|
## 💪 Why FastQR Dominates
|
|
61
74
|
|
|
62
75
|
### Speed Comparison Summary
|
|
63
76
|
|
|
64
77
|
| Platform | Library | Sequential | Batch | FastQR Advantage |
|
|
65
78
|
|----------|---------|------------|-------|------------------|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
79
|
+
| **⌨️ CLI** | qrencode | 2.97s | ❌ | **8x faster** ⚡ |
|
|
80
|
+
| **💎 Ruby** | rqrcode | 59.45s | ❌ | **157x faster** 🚀 |
|
|
81
|
+
| **🟢 Node.js** | qrcode | 17.25s | ❌ | **37x faster** ⚡ |
|
|
82
|
+
| **🐘 PHP** | endroid/qr-code | 14.72s | ❌ | **23x faster** 🚀 |
|
|
69
83
|
|
|
70
|
-
**Average: FastQR with batch mode is
|
|
84
|
+
**Average: FastQR with batch mode is 56x faster than popular alternatives!**
|
|
71
85
|
|
|
72
86
|
---
|
|
73
87
|
|
|
@@ -111,10 +125,26 @@ brew tap tranhuucanh/fastqr
|
|
|
111
125
|
brew install fastqr
|
|
112
126
|
```
|
|
113
127
|
|
|
114
|
-
**
|
|
128
|
+
**Linux (x86_64):**
|
|
129
|
+
```bash
|
|
130
|
+
# Download latest release (replace VERSION with latest version, e.g., 1.0.21)
|
|
131
|
+
VERSION="1.0.21"
|
|
132
|
+
wget https://github.com/tranhuucanh/fastqr/releases/download/v${VERSION}/fastqr-${VERSION}-linux-x86_64.tar.gz
|
|
133
|
+
tar -xzf fastqr-${VERSION}-linux-x86_64.tar.gz
|
|
134
|
+
sudo cp linux-x86_64/bin/fastqr /usr/local/bin/
|
|
135
|
+
sudo chmod +x /usr/local/bin/fastqr
|
|
136
|
+
|
|
137
|
+
# Verify installation
|
|
138
|
+
fastqr --version
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Linux (ARM64/aarch64):**
|
|
115
142
|
```bash
|
|
116
|
-
|
|
117
|
-
|
|
143
|
+
VERSION="1.0.21"
|
|
144
|
+
wget https://github.com/tranhuucanh/fastqr/releases/download/v${VERSION}/fastqr-${VERSION}-linux-aarch64.tar.gz
|
|
145
|
+
tar -xzf fastqr-${VERSION}-linux-aarch64.tar.gz
|
|
146
|
+
sudo cp linux-aarch64/bin/fastqr /usr/local/bin/
|
|
147
|
+
sudo chmod +x /usr/local/bin/fastqr
|
|
118
148
|
```
|
|
119
149
|
|
|
120
150
|
### Language Packages
|
data/bindings/php/src/FastQR.php
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* FastQR - Fast QR Code Generator
|
|
5
|
-
* PHP Binding using FFI
|
|
5
|
+
* PHP Binding using CLI binary (no FFI needed!)
|
|
6
6
|
*
|
|
7
7
|
* Copyright (C) 2025 FastQR Project
|
|
8
8
|
* Licensed under LGPL-2.1
|
|
@@ -10,21 +10,19 @@
|
|
|
10
10
|
|
|
11
11
|
namespace FastQR;
|
|
12
12
|
|
|
13
|
-
use FFI;
|
|
14
13
|
use RuntimeException;
|
|
15
14
|
|
|
16
15
|
class FastQR
|
|
17
16
|
{
|
|
18
|
-
private static ?
|
|
19
|
-
private static bool $initialized = false;
|
|
17
|
+
private static ?string $cliPath = null;
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
|
-
*
|
|
20
|
+
* Find CLI binary
|
|
23
21
|
*/
|
|
24
|
-
private static function
|
|
22
|
+
private static function findBinary(): string
|
|
25
23
|
{
|
|
26
|
-
if (self::$
|
|
27
|
-
return;
|
|
24
|
+
if (self::$cliPath !== null) {
|
|
25
|
+
return self::$cliPath;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
// Detect platform
|
|
@@ -33,58 +31,30 @@ class FastQR
|
|
|
33
31
|
if ($arch === 'x86_64' || $arch === 'amd64') {
|
|
34
32
|
$arch = 'x86_64';
|
|
35
33
|
} elseif ($arch === 'aarch64' || $arch === 'arm64') {
|
|
36
|
-
$arch = 'arm64';
|
|
34
|
+
$arch = $os === 'macos' ? 'arm64' : 'aarch64';
|
|
37
35
|
}
|
|
38
36
|
$platform = "$os-$arch";
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'/usr/
|
|
45
|
-
'/
|
|
46
|
-
__DIR__ . '/../../../build/libfastqr.' . $ext, // Local build
|
|
37
|
+
|
|
38
|
+
// Try to find the binary (pre-built first, then system)
|
|
39
|
+
$binaryPaths = [
|
|
40
|
+
__DIR__ . "/../../prebuilt/$platform/bin/fastqr", // Pre-built binary
|
|
41
|
+
'/usr/local/bin/fastqr', // System install
|
|
42
|
+
'/usr/bin/fastqr',
|
|
43
|
+
__DIR__ . '/../../../build/fastqr', // Local build
|
|
47
44
|
];
|
|
48
45
|
|
|
49
|
-
$
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
break;
|
|
46
|
+
foreach ($binaryPaths as $path) {
|
|
47
|
+
if (file_exists($path) && is_executable($path)) {
|
|
48
|
+
self::$cliPath = $path;
|
|
49
|
+
return $path;
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Define C interface
|
|
65
|
-
$header = '
|
|
66
|
-
typedef struct {
|
|
67
|
-
int size;
|
|
68
|
-
int optimize_size;
|
|
69
|
-
unsigned char foreground_r;
|
|
70
|
-
unsigned char foreground_g;
|
|
71
|
-
unsigned char foreground_b;
|
|
72
|
-
unsigned char background_r;
|
|
73
|
-
unsigned char background_g;
|
|
74
|
-
unsigned char background_b;
|
|
75
|
-
int ec_level;
|
|
76
|
-
const char* logo_path;
|
|
77
|
-
int logo_size_percent;
|
|
78
|
-
const char* format;
|
|
79
|
-
int quality;
|
|
80
|
-
} QROptions;
|
|
81
|
-
|
|
82
|
-
bool fastqr_generate(const char* data, const char* output_path, QROptions* options);
|
|
83
|
-
const char* fastqr_version(void);
|
|
84
|
-
';
|
|
85
|
-
|
|
86
|
-
self::$ffi = FFI::cdef($header, $libPath);
|
|
87
|
-
self::$initialized = true;
|
|
53
|
+
throw new RuntimeException(
|
|
54
|
+
"FastQR CLI binary not found for platform: $platform\n" .
|
|
55
|
+
"Searched in:\n" . implode("\n", $binaryPaths) . "\n" .
|
|
56
|
+
"Please install fastqr or build from source."
|
|
57
|
+
);
|
|
88
58
|
}
|
|
89
59
|
|
|
90
60
|
/**
|
|
@@ -127,8 +97,6 @@ class FastQR
|
|
|
127
97
|
*/
|
|
128
98
|
public static function generate(string $data, string $outputPath, array $options = []): bool
|
|
129
99
|
{
|
|
130
|
-
self::init();
|
|
131
|
-
|
|
132
100
|
if (empty($data)) {
|
|
133
101
|
throw new RuntimeException('Data cannot be empty');
|
|
134
102
|
}
|
|
@@ -136,56 +104,64 @@ class FastQR
|
|
|
136
104
|
throw new RuntimeException('Output path cannot be empty');
|
|
137
105
|
}
|
|
138
106
|
|
|
139
|
-
|
|
140
|
-
|
|
107
|
+
$cliPath = self::findBinary();
|
|
108
|
+
|
|
109
|
+
// Build command arguments
|
|
110
|
+
$args = [
|
|
111
|
+
escapeshellarg($cliPath),
|
|
112
|
+
escapeshellarg($data),
|
|
113
|
+
escapeshellarg($outputPath)
|
|
114
|
+
];
|
|
141
115
|
|
|
142
116
|
// Size (preferred) or width/height (backward compatibility)
|
|
143
117
|
if (isset($options['size'])) {
|
|
144
|
-
$
|
|
118
|
+
$args[] = '-s ' . (int)$options['size'];
|
|
145
119
|
} elseif (isset($options['width']) || isset($options['height'])) {
|
|
146
|
-
$
|
|
147
|
-
|
|
148
|
-
$opts->size = 300;
|
|
120
|
+
$size = $options['width'] ?? $options['height'] ?? 300;
|
|
121
|
+
$args[] = '-s ' . (int)$size;
|
|
149
122
|
}
|
|
150
123
|
|
|
151
124
|
// Optimize size
|
|
152
|
-
|
|
125
|
+
if (!empty($options['optimizeSize'])) {
|
|
126
|
+
$args[] = '-o';
|
|
127
|
+
}
|
|
153
128
|
|
|
154
129
|
// Foreground color
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
130
|
+
if (isset($options['foreground'])) {
|
|
131
|
+
$fg = $options['foreground'];
|
|
132
|
+
$args[] = '-f ' . implode(',', $fg);
|
|
133
|
+
}
|
|
159
134
|
|
|
160
135
|
// Background color
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
136
|
+
if (isset($options['background'])) {
|
|
137
|
+
$bg = $options['background'];
|
|
138
|
+
$args[] = '-b ' . implode(',', $bg);
|
|
139
|
+
}
|
|
165
140
|
|
|
166
141
|
// Error correction level
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
'M' => 1,
|
|
171
|
-
'Q' => 2,
|
|
172
|
-
'H' => 3,
|
|
173
|
-
default => 1
|
|
174
|
-
};
|
|
142
|
+
if (isset($options['errorLevel'])) {
|
|
143
|
+
$args[] = '-e ' . escapeshellarg($options['errorLevel']);
|
|
144
|
+
}
|
|
175
145
|
|
|
176
146
|
// Logo
|
|
177
|
-
|
|
178
|
-
|
|
147
|
+
if (isset($options['logo'])) {
|
|
148
|
+
$args[] = '-l ' . escapeshellarg($options['logo']);
|
|
149
|
+
}
|
|
150
|
+
if (isset($options['logoSize'])) {
|
|
151
|
+
$args[] = '-p ' . (int)$options['logoSize'];
|
|
152
|
+
}
|
|
179
153
|
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
154
|
+
// Quality
|
|
155
|
+
if (isset($options['quality'])) {
|
|
156
|
+
$args[] = '-q ' . (int)$options['quality'];
|
|
157
|
+
}
|
|
183
158
|
|
|
184
|
-
//
|
|
185
|
-
$
|
|
159
|
+
// Execute command
|
|
160
|
+
$cmd = implode(' ', $args) . ' 2>&1';
|
|
161
|
+
exec($cmd, $output, $returnCode);
|
|
186
162
|
|
|
187
|
-
if (
|
|
188
|
-
throw new RuntimeException('Failed to generate QR code');
|
|
163
|
+
if ($returnCode !== 0) {
|
|
164
|
+
throw new RuntimeException('Failed to generate QR code: ' . implode("\n", $output));
|
|
189
165
|
}
|
|
190
166
|
|
|
191
167
|
return true;
|
|
@@ -198,8 +174,15 @@ class FastQR
|
|
|
198
174
|
*/
|
|
199
175
|
public static function version(): string
|
|
200
176
|
{
|
|
201
|
-
self::
|
|
202
|
-
|
|
177
|
+
$cliPath = self::findBinary();
|
|
178
|
+
$cmd = escapeshellarg($cliPath) . ' -v 2>&1';
|
|
179
|
+
$output = shell_exec($cmd);
|
|
180
|
+
|
|
181
|
+
if ($output === null) {
|
|
182
|
+
return 'unknown';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return trim(str_replace('FastQR v', '', $output));
|
|
203
186
|
}
|
|
204
187
|
|
|
205
188
|
/**
|
|
@@ -241,65 +224,45 @@ class FastQR
|
|
|
241
224
|
try {
|
|
242
225
|
file_put_contents($tempFile, implode("\n", $dataArray));
|
|
243
226
|
|
|
244
|
-
|
|
245
|
-
$os = PHP_OS_FAMILY === 'Darwin' ? 'macos' : (PHP_OS_FAMILY === 'Linux' ? 'linux' : 'unknown');
|
|
246
|
-
$arch = php_uname('m');
|
|
247
|
-
if ($arch === 'x86_64' || $arch === 'amd64') {
|
|
248
|
-
$arch = 'x86_64';
|
|
249
|
-
} elseif ($arch === 'aarch64' || $arch === 'arm64') {
|
|
250
|
-
$arch = 'arm64';
|
|
251
|
-
}
|
|
252
|
-
$platform = "$os-$arch";
|
|
253
|
-
|
|
254
|
-
$cliPaths = [
|
|
255
|
-
__DIR__ . "/../../prebuilt/$platform/bin/fastqr",
|
|
256
|
-
'/usr/local/bin/fastqr',
|
|
257
|
-
__DIR__ . '/../../../build/fastqr',
|
|
258
|
-
];
|
|
259
|
-
|
|
260
|
-
$cliPath = null;
|
|
261
|
-
foreach ($cliPaths as $path) {
|
|
262
|
-
if (file_exists($path)) {
|
|
263
|
-
$cliPath = $path;
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if ($cliPath === null) {
|
|
269
|
-
throw new RuntimeException("FastQR CLI not found for platform: $platform");
|
|
270
|
-
}
|
|
227
|
+
$cliPath = self::findBinary();
|
|
271
228
|
|
|
272
229
|
// Build command
|
|
273
|
-
$
|
|
230
|
+
$args = [
|
|
231
|
+
escapeshellarg($cliPath),
|
|
232
|
+
'-F',
|
|
233
|
+
escapeshellarg($tempFile),
|
|
234
|
+
escapeshellarg($outputDir)
|
|
235
|
+
];
|
|
274
236
|
|
|
275
237
|
if (isset($options['size'])) {
|
|
276
|
-
$
|
|
238
|
+
$args[] = '-s ' . (int)$options['size'];
|
|
277
239
|
}
|
|
278
240
|
if (!empty($options['optimizeSize'])) {
|
|
279
|
-
$
|
|
241
|
+
$args[] = '-o';
|
|
280
242
|
}
|
|
281
243
|
if (isset($options['foreground'])) {
|
|
282
244
|
$fg = $options['foreground'];
|
|
283
|
-
$
|
|
245
|
+
$args[] = '-f ' . implode(',', $fg);
|
|
284
246
|
}
|
|
285
247
|
if (isset($options['background'])) {
|
|
286
248
|
$bg = $options['background'];
|
|
287
|
-
$
|
|
249
|
+
$args[] = '-b ' . implode(',', $bg);
|
|
288
250
|
}
|
|
289
251
|
if (isset($options['errorLevel'])) {
|
|
290
|
-
$
|
|
252
|
+
$args[] = '-e ' . escapeshellarg($options['errorLevel']);
|
|
291
253
|
}
|
|
292
254
|
if (isset($options['logo'])) {
|
|
293
|
-
$
|
|
255
|
+
$args[] = '-l ' . escapeshellarg($options['logo']);
|
|
294
256
|
}
|
|
295
257
|
if (isset($options['logoSize'])) {
|
|
296
|
-
$
|
|
258
|
+
$args[] = '-p ' . (int)$options['logoSize'];
|
|
297
259
|
}
|
|
298
260
|
if (isset($options['quality'])) {
|
|
299
|
-
$
|
|
261
|
+
$args[] = '-q ' . (int)$options['quality'];
|
|
300
262
|
}
|
|
301
263
|
|
|
302
|
-
|
|
264
|
+
$cmd = implode(' ', $args) . ' 2>&1';
|
|
265
|
+
exec($cmd, $output, $returnCode);
|
|
303
266
|
|
|
304
267
|
if ($returnCode !== 0) {
|
|
305
268
|
throw new RuntimeException('Batch generation failed: ' . implode("\n", $output));
|
|
@@ -313,4 +276,3 @@ class FastQR
|
|
|
313
276
|
}
|
|
314
277
|
}
|
|
315
278
|
}
|
|
316
|
-
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/composer.json
CHANGED
data/src/fastqr.cpp
CHANGED
|
@@ -20,12 +20,8 @@
|
|
|
20
20
|
#include <vector>
|
|
21
21
|
#include <algorithm>
|
|
22
22
|
#include <cstdio>
|
|
23
|
-
#include <chrono>
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
// #define FASTQR_BENCHMARK
|
|
27
|
-
|
|
28
|
-
#define FASTQR_VERSION "1.0.21"
|
|
24
|
+
#define FASTQR_VERSION "1.0.22"
|
|
29
25
|
|
|
30
26
|
namespace fastqr {
|
|
31
27
|
|
|
@@ -343,21 +339,12 @@ static void add_logo_to_image(std::vector<unsigned char>& qr_img, int qr_size, i
|
|
|
343
339
|
}
|
|
344
340
|
|
|
345
341
|
bool generate(const std::string& data, const std::string& output_path, const QROptions& options) {
|
|
346
|
-
#ifdef FASTQR_BENCHMARK
|
|
347
|
-
auto t_start = std::chrono::high_resolution_clock::now();
|
|
348
|
-
#endif
|
|
349
|
-
|
|
350
342
|
// Generate QR code
|
|
351
343
|
auto qr = generate_qr_code(data, options.ec_level);
|
|
352
344
|
if (!qr) {
|
|
353
345
|
return false;
|
|
354
346
|
}
|
|
355
347
|
|
|
356
|
-
#ifdef FASTQR_BENCHMARK
|
|
357
|
-
auto t_qr_gen = std::chrono::high_resolution_clock::now();
|
|
358
|
-
auto dur_qr = std::chrono::duration_cast<std::chrono::microseconds>(t_qr_gen - t_start).count();
|
|
359
|
-
#endif
|
|
360
|
-
|
|
361
348
|
int qr_size = qr->width;
|
|
362
349
|
unsigned char* qr_data = qr->data;
|
|
363
350
|
|
|
@@ -381,15 +368,6 @@ bool generate(const std::string& data, const std::string& output_path, const QRO
|
|
|
381
368
|
// Pack 8 pixels into 1 byte
|
|
382
369
|
int scale = final_size / qr_size;
|
|
383
370
|
|
|
384
|
-
#ifdef FASTQR_BENCHMARK
|
|
385
|
-
FILE* debug_log = fopen("/tmp/fastqr_debug.log", "a");
|
|
386
|
-
if (debug_log) {
|
|
387
|
-
fprintf(debug_log, "DEBUG: is_bw=%d, qr_size=%d, final_size=%d, scale=%d, scale*qr=%d\n",
|
|
388
|
-
is_bw, qr_size, final_size, scale, scale*qr_size);
|
|
389
|
-
fclose(debug_log);
|
|
390
|
-
}
|
|
391
|
-
#endif
|
|
392
|
-
|
|
393
371
|
if (scale * qr_size == final_size) {
|
|
394
372
|
// Integer scaling - optimized bit packing
|
|
395
373
|
int bytes_per_row = (final_size + 7) / 8;
|
|
@@ -424,27 +402,7 @@ bool generate(const std::string& data, const std::string& output_path, const QRO
|
|
|
424
402
|
}
|
|
425
403
|
}
|
|
426
404
|
|
|
427
|
-
|
|
428
|
-
auto t_scale = std::chrono::high_resolution_clock::now();
|
|
429
|
-
auto dur_scale = std::chrono::duration_cast<std::chrono::microseconds>(t_scale - t_qr_gen).count();
|
|
430
|
-
#endif
|
|
431
|
-
|
|
432
|
-
bool result = write_indexed_png(output_path.c_str(), packed_data, final_size, final_size);
|
|
433
|
-
|
|
434
|
-
#ifdef FASTQR_BENCHMARK
|
|
435
|
-
auto t_write = std::chrono::high_resolution_clock::now();
|
|
436
|
-
auto dur_write = std::chrono::duration_cast<std::chrono::microseconds>(t_write - t_scale).count();
|
|
437
|
-
auto dur_total = std::chrono::duration_cast<std::chrono::microseconds>(t_write - t_start).count();
|
|
438
|
-
|
|
439
|
-
FILE* timing_log = fopen("/tmp/fastqr_timing.log", "a");
|
|
440
|
-
if (timing_log) {
|
|
441
|
-
fprintf(timing_log, "TIMING: QR=%ldus, Scale=%ldus, Write=%ldus, Total=%ldus\n",
|
|
442
|
-
dur_qr, dur_scale, dur_write, dur_total);
|
|
443
|
-
fclose(timing_log);
|
|
444
|
-
}
|
|
445
|
-
#endif
|
|
446
|
-
|
|
447
|
-
return result;
|
|
405
|
+
return write_indexed_png(output_path.c_str(), packed_data, final_size, final_size);
|
|
448
406
|
} else {
|
|
449
407
|
// Non-integer scaling - use grayscale
|
|
450
408
|
std::vector<unsigned char> final_image(final_size * final_size);
|