quirc 0.0.1 → 0.1.3
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 +5 -5
- data/LICENSE +1 -1
- data/README.md +31 -1
- data/ext/quirc/embed/Makefile +1 -1
- data/ext/quirc/embed/lib/decode.c +11 -5
- data/ext/quirc/embed/lib/identify.c +5 -7
- data/ext/quirc/embed/lib/quirc.c +63 -14
- data/ext/quirc/embed/lib/quirc.h +1 -1
- data/ext/quirc/embed/lib/quirc_internal.h +1 -0
- data/ext/quirc/extconf.rb +2 -1
- data/lib/quirc.rb +4 -0
- data/lib/quirc/version.rb +1 -1
- data/test/fixtures/hello.gz +1 -0
- data/test/helper.rb +11 -2
- data/test/test_decode.rb +24 -1
- metadata +14 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 238e53d6dcadb8f91b5a227a343544d152494ca10657958e51a937b2cee09785
|
4
|
+
data.tar.gz: db1ff5a61049d9ecee487af9632939af22aa9f762c170725c3b4b08f19f48045
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c8078f8528ae8984060aa91f7603beb785cfa5fe9da9f2863ce648c94d4b0bcc03a8001545d4af85bf44076148dca27f93c046e121a163043366367a538833b
|
7
|
+
data.tar.gz: eff42614d61320a6df00bfb0c01c5b33bb03a4083f8c4376956b5e35f2dd7237895f9251ee38973f98028a31fd456edd700e21fc545168cd5b3500db8ac33f4d
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,37 @@
|
|
1
1
|
# Quirc bindings for Ruby
|
2
2
|
|
3
|
-
Quirc is a small C library for extracting and decode QR codes from images.
|
3
|
+
[Quirc](https://github.com/dlbeer/quirc) is a small C library for extracting and decode QR codes from images.
|
4
4
|
This project is a Ruby binding for that library with the library embedded.
|
5
5
|
|
6
|
+
## Example
|
7
|
+
You have to supply a [ChunkyPNG](http://chunkypng.com/) object or a binary string of the grayscale image with width and height.
|
8
|
+
```ruby
|
9
|
+
require 'chunky_png'
|
10
|
+
require 'quirc'
|
11
|
+
|
12
|
+
img = ChunkyPNG::Image.from_file('path_to_image.png')
|
13
|
+
res = Quirc.decode(img).first
|
14
|
+
puts res.payload
|
15
|
+
```
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require 'base64'
|
19
|
+
require 'zlib'
|
20
|
+
require 'quirc'
|
21
|
+
|
22
|
+
encoded = <<~EOD
|
23
|
+
eJzt0kEOwyAMRNHe/9LpFo1mwK1IYqQ/mwQDfl5wXYQQQgghT+cziZ7Tb+Ue
|
24
|
+
7vvurL76Vvvhvuvqu0jvqHoP9wx3dh73fHdWxz3Hrc5TvYfbx01RP83j7uH2
|
25
|
+
cCtzuf+7g7uvr74ZrY9r967cedxebrrjZtK9tMbt4Y7+L/V/Tdzn3DRH+td5
|
26
|
+
0hq3h5veR+qjNTcPbh+3Mpd7Qzt6497vat+Voe9Oa7j93GpdrXGt+7i9XO3j
|
27
|
+
+jknzYB7huvmGM+7GXHPcWeOM3B7upV5Rlvvun3cHm6K+qt5qibucy4hhBBC
|
28
|
+
yN58AXWDGDc=
|
29
|
+
EOD
|
30
|
+
|
31
|
+
img = Zlib::Inflate.inflate(Base64.decode64(encoded))
|
32
|
+
res = Quirc.decode(img, 120, 120).first
|
33
|
+
puts res.payload
|
34
|
+
```
|
35
|
+
|
6
36
|
## License
|
7
37
|
This software is licensed under the MIT License. [View the license](LICENSE).
|
data/ext/quirc/embed/Makefile
CHANGED
@@ -117,7 +117,7 @@ static const uint8_t gf256_log[256] = {
|
|
117
117
|
0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
|
118
118
|
};
|
119
119
|
|
120
|
-
const
|
120
|
+
static const struct galois_field gf256 = {
|
121
121
|
.p = 255,
|
122
122
|
.log = gf256_log,
|
123
123
|
.exp = gf256_exp
|
@@ -790,12 +790,18 @@ static quirc_decode_error_t decode_kanji(struct quirc_data *data,
|
|
790
790
|
|
791
791
|
for (i = 0; i < count; i++) {
|
792
792
|
int d = take_bits(ds, 13);
|
793
|
+
int msB = d / 0xc0;
|
794
|
+
int lsB = d % 0xc0;
|
795
|
+
int intermediate = (msB << 8) | lsB;
|
793
796
|
uint16_t sjw;
|
794
797
|
|
795
|
-
if (
|
796
|
-
|
797
|
-
|
798
|
-
|
798
|
+
if (intermediate + 0x8140 <= 0x9ffc) {
|
799
|
+
/* bytes are in the range 0x8140 to 0x9FFC */
|
800
|
+
sjw = intermediate + 0x8140;
|
801
|
+
} else {
|
802
|
+
/* bytes are in the range 0xE040 to 0xEBBF */
|
803
|
+
sjw = intermediate + 0xc140;
|
804
|
+
}
|
799
805
|
|
800
806
|
data->payload[data->payload_len++] = sjw >> 8;
|
801
807
|
data->payload[data->payload_len++] = sjw & 0xff;
|
@@ -196,9 +196,7 @@ static void threshold(struct quirc *q)
|
|
196
196
|
threshold_s = THRESHOLD_S_MIN;
|
197
197
|
|
198
198
|
for (y = 0; y < q->h; y++) {
|
199
|
-
|
200
|
-
|
201
|
-
memset(row_average, 0, sizeof(row_average));
|
199
|
+
memset(q->row_average, 0, q->w * sizeof(int));
|
202
200
|
|
203
201
|
for (x = 0; x < q->w; x++) {
|
204
202
|
int w, u;
|
@@ -216,12 +214,12 @@ static void threshold(struct quirc *q)
|
|
216
214
|
avg_u = (avg_u * (threshold_s - 1)) /
|
217
215
|
threshold_s + row[u];
|
218
216
|
|
219
|
-
row_average[w] += avg_w;
|
220
|
-
row_average[u] += avg_u;
|
217
|
+
q->row_average[w] += avg_w;
|
218
|
+
q->row_average[u] += avg_u;
|
221
219
|
}
|
222
220
|
|
223
221
|
for (x = 0; x < q->w; x++) {
|
224
|
-
if (row[x] < row_average[x] *
|
222
|
+
if (row[x] < q->row_average[x] *
|
225
223
|
(100 - THRESHOLD_T) / (200 * threshold_s))
|
226
224
|
row[x] = QUIRC_PIXEL_BLACK;
|
227
225
|
else
|
@@ -427,7 +425,7 @@ static void finder_scan(struct quirc *q, int y)
|
|
427
425
|
{
|
428
426
|
quirc_pixel_t *row = q->pixels + y * q->w;
|
429
427
|
int x;
|
430
|
-
int last_color;
|
428
|
+
int last_color = 0;
|
431
429
|
int run_length = 0;
|
432
430
|
int run_count = 0;
|
433
431
|
int pb[5];
|
data/ext/quirc/embed/lib/quirc.c
CHANGED
@@ -36,34 +36,83 @@ struct quirc *quirc_new(void)
|
|
36
36
|
|
37
37
|
void quirc_destroy(struct quirc *q)
|
38
38
|
{
|
39
|
-
|
40
|
-
|
39
|
+
free(q->image);
|
40
|
+
/* q->pixels may alias q->image when their type representation is of the
|
41
|
+
same size, so we need to be careful here to avoid a double free */
|
41
42
|
if (sizeof(*q->image) != sizeof(*q->pixels))
|
42
43
|
free(q->pixels);
|
43
|
-
|
44
|
+
free(q->row_average);
|
44
45
|
free(q);
|
45
46
|
}
|
46
47
|
|
47
48
|
int quirc_resize(struct quirc *q, int w, int h)
|
48
49
|
{
|
49
|
-
uint8_t
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
uint8_t *image = NULL;
|
51
|
+
quirc_pixel_t *pixels = NULL;
|
52
|
+
int *row_average = NULL;
|
53
|
+
|
54
|
+
/*
|
55
|
+
* XXX: w and h should be size_t (or at least unsigned) as negatives
|
56
|
+
* values would not make much sense. The downside is that it would break
|
57
|
+
* both the API and ABI. Thus, at the moment, let's just do a sanity
|
58
|
+
* check.
|
59
|
+
*/
|
60
|
+
if (w < 0 || h < 0)
|
61
|
+
goto fail;
|
62
|
+
|
63
|
+
/*
|
64
|
+
* alloc a new buffer for q->image. We avoid realloc(3) because we want
|
65
|
+
* on failure to be leave `q` in a consistant, unmodified state.
|
66
|
+
*/
|
67
|
+
image = calloc(w, h);
|
68
|
+
if (!image)
|
69
|
+
goto fail;
|
70
|
+
|
71
|
+
/* compute the "old" (i.e. currently allocated) and the "new"
|
72
|
+
(i.e. requested) image dimensions */
|
73
|
+
size_t olddim = q->w * q->h;
|
74
|
+
size_t newdim = w * h;
|
75
|
+
size_t min = (olddim < newdim ? olddim : newdim);
|
76
|
+
|
77
|
+
/*
|
78
|
+
* copy the data into the new buffer, avoiding (a) to read beyond the
|
79
|
+
* old buffer when the new size is greater and (b) to write beyond the
|
80
|
+
* new buffer when the new size is smaller, hence the min computation.
|
81
|
+
*/
|
82
|
+
(void)memcpy(image, q->image, min);
|
83
|
+
|
84
|
+
/* alloc a new buffer for q->pixels if needed */
|
54
85
|
if (sizeof(*q->image) != sizeof(*q->pixels)) {
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
return -1;
|
59
|
-
q->pixels = new_pixels;
|
86
|
+
pixels = calloc(newdim, sizeof(quirc_pixel_t));
|
87
|
+
if (!pixels)
|
88
|
+
goto fail;
|
60
89
|
}
|
61
90
|
|
62
|
-
q->
|
91
|
+
/* alloc a new buffer for q->row_average */
|
92
|
+
row_average = calloc(w, sizeof(int));
|
93
|
+
if (!row_average)
|
94
|
+
goto fail;
|
95
|
+
|
96
|
+
/* alloc succeeded, update `q` with the new size and buffers */
|
63
97
|
q->w = w;
|
64
98
|
q->h = h;
|
99
|
+
free(q->image);
|
100
|
+
q->image = image;
|
101
|
+
if (sizeof(*q->image) != sizeof(*q->pixels)) {
|
102
|
+
free(q->pixels);
|
103
|
+
q->pixels = pixels;
|
104
|
+
}
|
105
|
+
free(q->row_average);
|
106
|
+
q->row_average = row_average;
|
65
107
|
|
66
108
|
return 0;
|
109
|
+
/* NOTREACHED */
|
110
|
+
fail:
|
111
|
+
free(image);
|
112
|
+
free(pixels);
|
113
|
+
free(row_average);
|
114
|
+
|
115
|
+
return -1;
|
67
116
|
}
|
68
117
|
|
69
118
|
int quirc_count(const struct quirc *q)
|
data/ext/quirc/embed/lib/quirc.h
CHANGED
@@ -121,7 +121,7 @@ struct quirc_code {
|
|
121
121
|
* is a bitmask giving the actual values of cells. If the cell
|
122
122
|
* at (x, y) is black, then the following bit is set:
|
123
123
|
*
|
124
|
-
* cell_bitmap[i
|
124
|
+
* cell_bitmap[i >> 3] & (1 << (i & 7))
|
125
125
|
*
|
126
126
|
* where i = (y * size) + x.
|
127
127
|
*/
|
data/ext/quirc/extconf.rb
CHANGED
@@ -9,7 +9,7 @@ BUILD_DIR = File.join(TMP_DIR, "quirc-1.0")
|
|
9
9
|
LIB_FILE = File.join(BUILD_DIR, "libquirc.a")
|
10
10
|
|
11
11
|
def build_library
|
12
|
-
|
12
|
+
FileUtils.makedirs(BUILD_DIR)
|
13
13
|
system({ "BUILD_DIR" => BUILD_DIR }, "make", "-C", SRC_DIR) or raise "Error building quirc"
|
14
14
|
end
|
15
15
|
|
@@ -17,4 +17,5 @@ find_header("quirc.h", "#{SRC_DIR}/lib") or missing("quirc.h")
|
|
17
17
|
build_library
|
18
18
|
$LOCAL_LIBS << LIB_FILE
|
19
19
|
|
20
|
+
$CFLAGS << ' --std=c99'
|
20
21
|
create_makefile("quirc/quirc")
|
data/lib/quirc.rb
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module Quirc
|
4
4
|
def self.decode(image, width=nil, height=nil)
|
5
|
+
unless image.respond_to?(:to_grayscale_stream) || (width && height)
|
6
|
+
raise ArgumentError, "Arguments width and height are required if binary string is passed"
|
7
|
+
end
|
8
|
+
|
5
9
|
width ||= image.public_send(:width)
|
6
10
|
height ||= image.public_send(:height)
|
7
11
|
if image.respond_to?(:to_grayscale_stream)
|
data/lib/quirc/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
x���A� D������f��Hb�?�~^p]�B!O�3���o����V����H�z�wv�|wV�=ǭ�S����MQ?�����p+s����������k���y�^n��fҽ�����/�M���4G��y�����G�57n�2�{C;z���jߕ��Nk���j]�q����\���9'̀{���ϻq�qg�3p{��yF[�}�n���y�&�s.!�B��|u�7
|
data/test/helper.rb
CHANGED
@@ -1,15 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "zlib"
|
4
|
+
|
3
5
|
require "minitest/autorun"
|
4
6
|
require "oily_png"
|
7
|
+
|
5
8
|
require "quirc"
|
6
9
|
|
7
10
|
module TestHelpers
|
11
|
+
def binary_fixture(*path)
|
12
|
+
Zlib::Inflate.inflate(File.binread(File.join(__dir__, "fixtures", *path)))
|
13
|
+
end
|
14
|
+
|
8
15
|
def image_fixture(*path)
|
9
16
|
ChunkyPNG::Image.from_file(File.join(__dir__, "fixtures", *path))
|
10
17
|
end
|
11
18
|
end
|
12
19
|
|
13
|
-
|
14
|
-
|
20
|
+
module Minitest
|
21
|
+
class Spec
|
22
|
+
include TestHelpers
|
23
|
+
end
|
15
24
|
end
|
data/test/test_decode.rb
CHANGED
@@ -3,6 +3,14 @@
|
|
3
3
|
require "helper.rb"
|
4
4
|
|
5
5
|
describe Quirc do
|
6
|
+
describe "binary string" do
|
7
|
+
it "should decode" do
|
8
|
+
result = Quirc.decode(binary_fixture("hello.gz"), 120, 120).first
|
9
|
+
assert_equal 1, result.ecc_level
|
10
|
+
assert_equal "Hello World!", result.payload
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
describe "error levels" do
|
7
15
|
it "should decode all error levels" do
|
8
16
|
%i[m l h q].each_with_index do |level, no|
|
@@ -16,9 +24,24 @@ describe Quirc do
|
|
16
24
|
|
17
25
|
describe "errors" do
|
18
26
|
it "should throw error if image size is not equal to buffer" do
|
19
|
-
assert_raises ArgumentError
|
27
|
+
e = assert_raises ArgumentError do
|
20
28
|
Quirc::Decoder.new(1, 2).decode("abc")
|
21
29
|
end
|
30
|
+
assert_equal "Decoder is allocated for 1x2 images", e.message
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should throw error if width is not specified with binary string" do
|
34
|
+
e = assert_raises ArgumentError do
|
35
|
+
Quirc.decode("", nil, 1)
|
36
|
+
end
|
37
|
+
assert_equal "Arguments width and height are required if binary string is passed", e.message
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should throw error if width height not specified with binary string" do
|
41
|
+
e = assert_raises ArgumentError, "Decoder is allocated for 1x2 images" do
|
42
|
+
Quirc.decode("", nil, 1)
|
43
|
+
end
|
44
|
+
assert_equal "Arguments width and height are required if binary string is passed", e.message
|
22
45
|
end
|
23
46
|
end
|
24
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quirc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Middag
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: oily_png
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
@@ -39,33 +39,33 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake-compiler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
47
|
+
version: '1.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0.71'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0.71'
|
69
69
|
description: Ruby bindings for C library quirc that extracts and decode QR images
|
70
70
|
email: jacob@gaddim.nl
|
71
71
|
executables: []
|
@@ -91,9 +91,10 @@ files:
|
|
91
91
|
- test/fixtures/hello-120-utf8-l.png
|
92
92
|
- test/fixtures/hello-120-utf8-m.png
|
93
93
|
- test/fixtures/hello-120-utf8-q.png
|
94
|
+
- test/fixtures/hello.gz
|
94
95
|
- test/helper.rb
|
95
96
|
- test/test_decode.rb
|
96
|
-
homepage: https://github.com/middagj/quirc
|
97
|
+
homepage: https://github.com/middagj/quirc-ruby
|
97
98
|
licenses:
|
98
99
|
- MIT
|
99
100
|
metadata: {}
|
@@ -105,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
106
|
requirements:
|
106
107
|
- - ">="
|
107
108
|
- !ruby/object:Gem::Version
|
108
|
-
version: '2.
|
109
|
+
version: '2.3'
|
109
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
111
|
requirements:
|
111
112
|
- - ">="
|
112
113
|
- !ruby/object:Gem::Version
|
113
114
|
version: '0'
|
114
115
|
requirements: []
|
115
|
-
|
116
|
-
rubygems_version: 2.6.11
|
116
|
+
rubygems_version: 3.0.8
|
117
117
|
signing_key:
|
118
118
|
specification_version: 4
|
119
119
|
summary: QR decoder based on quirc
|
@@ -122,5 +122,6 @@ test_files:
|
|
122
122
|
- test/fixtures/hello-120-utf8-l.png
|
123
123
|
- test/fixtures/hello-120-utf8-m.png
|
124
124
|
- test/fixtures/hello-120-utf8-q.png
|
125
|
+
- test/fixtures/hello.gz
|
125
126
|
- test/helper.rb
|
126
127
|
- test/test_decode.rb
|