quirc 0.0.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|