quirc 0.1.3 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 238e53d6dcadb8f91b5a227a343544d152494ca10657958e51a937b2cee09785
4
- data.tar.gz: db1ff5a61049d9ecee487af9632939af22aa9f762c170725c3b4b08f19f48045
3
+ metadata.gz: d88ac4b65801a83205e14ffa1b9b7154bc53410dcab9110f3e397c320c415e09
4
+ data.tar.gz: 305c828b7db112e3ecff1bf7ee6a082a437c8a3cbd1292430401494847b84c13
5
5
  SHA512:
6
- metadata.gz: 6c8078f8528ae8984060aa91f7603beb785cfa5fe9da9f2863ce648c94d4b0bcc03a8001545d4af85bf44076148dca27f93c046e121a163043366367a538833b
7
- data.tar.gz: eff42614d61320a6df00bfb0c01c5b33bb03a4083f8c4376956b5e35f2dd7237895f9251ee38973f98028a31fd456edd700e21fc545168cd5b3500db8ac33f4d
6
+ metadata.gz: 19d8b284668492e248faf07f6c68ce23c873f38d0d2b1242157b59f41332107e4ec5886c8e5d8f50f3bf5b34b2b25eef29d1b803b15001b67fd64eefb40537a1
7
+ data.tar.gz: 29fee645c7acdedf4f242c6138164641ae79109e57de7950d0ccdb729744eead0a0354f0f2e0240098266bc76024098027244c0e7c524cf4696652db8cad53e2
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2019 Jacob Middag
3
+ Copyright (c) 2017-2021 Jacob Middag
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -409,7 +409,6 @@ struct datastream {
409
409
  static inline int grid_bit(const struct quirc_code *code, int x, int y)
410
410
  {
411
411
  int p = y * code->size + x;
412
-
413
412
  return (code->cell_bitmap[p >> 3] >> (p & 7)) & 1;
414
413
  }
415
414
 
@@ -874,7 +873,7 @@ static quirc_decode_error_t decode_payload(struct quirc_data *data,
874
873
  done:
875
874
 
876
875
  /* Add nul terminator to all payloads */
877
- if (data->payload_len >= sizeof(data->payload))
876
+ if (data->payload_len >= (int) sizeof(data->payload))
878
877
  data->payload_len--;
879
878
  data->payload[data->payload_len] = 0;
880
879
 
@@ -917,3 +916,18 @@ quirc_decode_error_t quirc_decode(const struct quirc_code *code,
917
916
 
918
917
  return QUIRC_SUCCESS;
919
918
  }
919
+
920
+ void quirc_flip(struct quirc_code *code)
921
+ {
922
+ struct quirc_code flipped = {0};
923
+ unsigned int offset = 0;
924
+ for (int y = 0; y < code->size; y++) {
925
+ for (int x = 0; x < code->size; x++) {
926
+ if (grid_bit(code, y, x)) {
927
+ flipped.cell_bitmap[offset >> 3u] |= (1u << (offset & 7u));
928
+ }
929
+ offset++;
930
+ }
931
+ }
932
+ memcpy(&code->cell_bitmap, &flipped.cell_bitmap, sizeof(flipped.cell_bitmap));
933
+ }
@@ -14,6 +14,7 @@
14
14
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
15
  */
16
16
 
17
+ #include <limits.h>
17
18
  #include <string.h>
18
19
  #include <stdlib.h>
19
20
  #include <math.h>
@@ -98,8 +99,8 @@ static void perspective_map(const double *c,
98
99
  double x = (c[0]*u + c[1]*v + c[2]) / den;
99
100
  double y = (c[3]*u + c[4]*v + c[5]) / den;
100
101
 
101
- ret->x = rint(x);
102
- ret->y = rint(y);
102
+ ret->x = (int) rint(x);
103
+ ret->y = (int) rint(y);
103
104
  }
104
105
 
105
106
  static void perspective_unmap(const double *c,
@@ -174,60 +175,55 @@ static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to,
174
175
  * Adaptive thresholding
175
176
  */
176
177
 
177
- #define THRESHOLD_S_MIN 1
178
- #define THRESHOLD_S_DEN 8
179
- #define THRESHOLD_T 5
180
-
181
- static void threshold(struct quirc *q)
178
+ static uint8_t otsu(const struct quirc *q)
182
179
  {
183
- int x, y;
184
- int avg_w = 0;
185
- int avg_u = 0;
186
- int threshold_s = q->w / THRESHOLD_S_DEN;
187
- quirc_pixel_t *row = q->pixels;
188
-
189
- /*
190
- * Ensure a sane, non-zero value for threshold_s.
191
- *
192
- * threshold_s can be zero if the image width is small. We need to avoid
193
- * SIGFPE as it will be used as divisor.
194
- */
195
- if (threshold_s < THRESHOLD_S_MIN)
196
- threshold_s = THRESHOLD_S_MIN;
197
-
198
- for (y = 0; y < q->h; y++) {
199
- memset(q->row_average, 0, q->w * sizeof(int));
200
-
201
- for (x = 0; x < q->w; x++) {
202
- int w, u;
180
+ int numPixels = q->w * q->h;
181
+
182
+ // Calculate histogram
183
+ unsigned int histogram[UINT8_MAX + 1];
184
+ (void)memset(histogram, 0, sizeof(histogram));
185
+ uint8_t* ptr = q->image;
186
+ int length = numPixels;
187
+ while (length--) {
188
+ uint8_t value = *ptr++;
189
+ histogram[value]++;
190
+ }
203
191
 
204
- if (y & 1) {
205
- w = x;
206
- u = q->w - 1 - x;
207
- } else {
208
- w = q->w - 1 - x;
209
- u = x;
210
- }
192
+ // Calculate weighted sum of histogram values
193
+ unsigned int sum = 0;
194
+ unsigned int i = 0;
195
+ for (i = 0; i <= UINT8_MAX; ++i) {
196
+ sum += i * histogram[i];
197
+ }
211
198
 
212
- avg_w = (avg_w * (threshold_s - 1)) /
213
- threshold_s + row[w];
214
- avg_u = (avg_u * (threshold_s - 1)) /
215
- threshold_s + row[u];
199
+ // Compute threshold
200
+ int sumB = 0;
201
+ int q1 = 0;
202
+ double max = 0;
203
+ uint8_t threshold = 0;
204
+ for (i = 0; i <= UINT8_MAX; ++i) {
205
+ // Weighted background
206
+ q1 += histogram[i];
207
+ if (q1 == 0)
208
+ continue;
216
209
 
217
- q->row_average[w] += avg_w;
218
- q->row_average[u] += avg_u;
219
- }
210
+ // Weighted foreground
211
+ const int q2 = numPixels - q1;
212
+ if (q2 == 0)
213
+ break;
220
214
 
221
- for (x = 0; x < q->w; x++) {
222
- if (row[x] < q->row_average[x] *
223
- (100 - THRESHOLD_T) / (200 * threshold_s))
224
- row[x] = QUIRC_PIXEL_BLACK;
225
- else
226
- row[x] = QUIRC_PIXEL_WHITE;
215
+ sumB += i * histogram[i];
216
+ const double m1 = (double)sumB / q1;
217
+ const double m2 = ((double)sum - sumB) / q2;
218
+ const double m1m2 = m1 - m2;
219
+ const double variance = m1m2 * m1m2 * q1 * q2;
220
+ if (variance >= max) {
221
+ threshold = i;
222
+ max = variance;
227
223
  }
228
-
229
- row += q->w;
230
224
  }
225
+
226
+ return threshold;
231
227
  }
232
228
 
233
229
  static void area_count(void *user_data, int y, int left, int right)
@@ -660,8 +656,11 @@ static int measure_timing_pattern(struct quirc *q, int index)
660
656
  /* Choose the nearest allowable grid size */
661
657
  size = scan * 2 + 13;
662
658
  ver = (size - 15) / 4;
663
- qr->grid_size = ver * 4 + 17;
659
+ if (ver > QUIRC_MAX_VERSION) {
660
+ return -1;
661
+ }
664
662
 
663
+ qr->grid_size = ver * 4 + 17;
665
664
  return 0;
666
665
  }
667
666
 
@@ -856,8 +855,8 @@ static void rotate_capstone(struct quirc_capstone *cap,
856
855
  {
857
856
  struct quirc_point copy[4];
858
857
  int j;
859
- int best;
860
- int best_score;
858
+ int best = 0;
859
+ int best_score = INT_MAX;
861
860
 
862
861
  for (j = 0; j < 4; j++) {
863
862
  struct quirc_point *p = &cap->corners[j];
@@ -1074,17 +1073,18 @@ static void test_grouping(struct quirc *q, int i)
1074
1073
  test_neighbours(q, i, &hlist, &vlist);
1075
1074
  }
1076
1075
 
1077
- static void pixels_setup(struct quirc *q)
1076
+ static void pixels_setup(struct quirc *q, uint8_t threshold)
1078
1077
  {
1079
- if (sizeof(*q->image) == sizeof(*q->pixels)) {
1078
+ if (QUIRC_PIXEL_ALIAS_IMAGE) {
1080
1079
  q->pixels = (quirc_pixel_t *)q->image;
1081
- } else {
1082
- int x, y;
1083
- for (y = 0; y < q->h; y++) {
1084
- for (x = 0; x < q->w; x++) {
1085
- q->pixels[y * q->w + x] = q->image[y * q->w + x];
1086
- }
1087
- }
1080
+ }
1081
+
1082
+ uint8_t* source = q->image;
1083
+ quirc_pixel_t* dest = q->pixels;
1084
+ int length = q->w * q->h;
1085
+ while (length--) {
1086
+ uint8_t value = *source++;
1087
+ *dest++ = (value < threshold) ? QUIRC_PIXEL_BLACK : QUIRC_PIXEL_WHITE;
1088
1088
  }
1089
1089
  }
1090
1090
 
@@ -1106,8 +1106,8 @@ void quirc_end(struct quirc *q)
1106
1106
  {
1107
1107
  int i;
1108
1108
 
1109
- pixels_setup(q);
1110
- threshold(q);
1109
+ uint8_t threshold = otsu(q);
1110
+ pixels_setup(q, threshold);
1111
1111
 
1112
1112
  for (i = 0; i < q->h; i++)
1113
1113
  finder_scan(q, i);
@@ -1138,11 +1138,10 @@ void quirc_extract(const struct quirc *q, int index,
1138
1138
 
1139
1139
  for (y = 0; y < qr->grid_size; y++) {
1140
1140
  int x;
1141
-
1142
1141
  for (x = 0; x < qr->grid_size; x++) {
1143
- if (read_cell(q, index, x, y) > 0)
1142
+ if (read_cell(q, index, x, y) > 0) {
1144
1143
  code->cell_bitmap[i >> 3] |= (1 << (i & 7));
1145
-
1144
+ }
1146
1145
  i++;
1147
1146
  }
1148
1147
  }
@@ -39,9 +39,8 @@ void quirc_destroy(struct quirc *q)
39
39
  free(q->image);
40
40
  /* q->pixels may alias q->image when their type representation is of the
41
41
  same size, so we need to be careful here to avoid a double free */
42
- if (sizeof(*q->image) != sizeof(*q->pixels))
42
+ if (!QUIRC_PIXEL_ALIAS_IMAGE)
43
43
  free(q->pixels);
44
- free(q->row_average);
45
44
  free(q);
46
45
  }
47
46
 
@@ -49,7 +48,6 @@ int quirc_resize(struct quirc *q, int w, int h)
49
48
  {
50
49
  uint8_t *image = NULL;
51
50
  quirc_pixel_t *pixels = NULL;
52
- int *row_average = NULL;
53
51
 
54
52
  /*
55
53
  * XXX: w and h should be size_t (or at least unsigned) as negatives
@@ -82,35 +80,27 @@ int quirc_resize(struct quirc *q, int w, int h)
82
80
  (void)memcpy(image, q->image, min);
83
81
 
84
82
  /* alloc a new buffer for q->pixels if needed */
85
- if (sizeof(*q->image) != sizeof(*q->pixels)) {
83
+ if (!QUIRC_PIXEL_ALIAS_IMAGE) {
86
84
  pixels = calloc(newdim, sizeof(quirc_pixel_t));
87
85
  if (!pixels)
88
86
  goto fail;
89
87
  }
90
88
 
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
89
  /* alloc succeeded, update `q` with the new size and buffers */
97
90
  q->w = w;
98
91
  q->h = h;
99
92
  free(q->image);
100
93
  q->image = image;
101
- if (sizeof(*q->image) != sizeof(*q->pixels)) {
94
+ if (!QUIRC_PIXEL_ALIAS_IMAGE) {
102
95
  free(q->pixels);
103
96
  q->pixels = pixels;
104
97
  }
105
- free(q->row_average);
106
- q->row_average = row_average;
107
98
 
108
99
  return 0;
109
100
  /* NOTREACHED */
110
101
  fail:
111
102
  free(image);
112
103
  free(pixels);
113
- free(row_average);
114
104
 
115
105
  return -1;
116
106
  }
@@ -78,7 +78,9 @@ typedef enum {
78
78
  const char *quirc_strerror(quirc_decode_error_t err);
79
79
 
80
80
  /* Limits on the maximum size of QR-codes and their content. */
81
- #define QUIRC_MAX_BITMAP 3917
81
+ #define QUIRC_MAX_VERSION 40
82
+ #define QUIRC_MAX_GRID_SIZE (QUIRC_MAX_VERSION * 4 + 17)
83
+ #define QUIRC_MAX_BITMAP (((QUIRC_MAX_GRID_SIZE * QUIRC_MAX_GRID_SIZE) + 7) / 8)
82
84
  #define QUIRC_MAX_PAYLOAD 8896
83
85
 
84
86
  /* QR-code ECC types. */
@@ -166,6 +168,9 @@ void quirc_extract(const struct quirc *q, int index,
166
168
  quirc_decode_error_t quirc_decode(const struct quirc_code *code,
167
169
  struct quirc_data *data);
168
170
 
171
+ /* Flip a QR-code according to optional mirror feature of ISO 18004:2015 */
172
+ void quirc_flip(struct quirc_code *code);
173
+
169
174
  #ifdef __cplusplus
170
175
  }
171
176
  #endif
@@ -28,12 +28,13 @@
28
28
  #endif
29
29
  #define QUIRC_MAX_CAPSTONES 32
30
30
  #define QUIRC_MAX_GRIDS 8
31
-
32
31
  #define QUIRC_PERSPECTIVE_PARAMS 8
33
32
 
34
33
  #if QUIRC_MAX_REGIONS < UINT8_MAX
34
+ #define QUIRC_PIXEL_ALIAS_IMAGE 1
35
35
  typedef uint8_t quirc_pixel_t;
36
36
  #elif QUIRC_MAX_REGIONS < UINT16_MAX
37
+ #define QUIRC_PIXEL_ALIAS_IMAGE 0
37
38
  typedef uint16_t quirc_pixel_t;
38
39
  #else
39
40
  #error "QUIRC_MAX_REGIONS > 65534 is not supported"
@@ -77,7 +78,6 @@ struct quirc_grid {
77
78
  struct quirc {
78
79
  uint8_t *image;
79
80
  quirc_pixel_t *pixels;
80
- int *row_average; /* used by threshold() */
81
81
  int w;
82
82
  int h;
83
83
 
@@ -17,5 +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
+ $CFLAGS << " --std=c99"
21
21
  create_makefile("quirc/quirc")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quirc
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "helper.rb"
3
+ require "helper"
4
4
 
5
5
  describe Quirc do
6
6
  describe "binary string" do
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.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Middag
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-17 00:00:00.000000000 Z
11
+ date: 2021-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.71'
61
+ version: 1.4.1
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: '0.71'
68
+ version: 1.4.1
69
69
  description: Ruby bindings for C library quirc that extracts and decode QR images
70
70
  email: jacob@gaddim.nl
71
71
  executables: []
@@ -106,14 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="
108
108
  - !ruby/object:Gem::Version
109
- version: '2.3'
109
+ version: '2.4'
110
110
  required_rubygems_version: !ruby/object:Gem::Requirement
111
111
  requirements:
112
112
  - - ">="
113
113
  - !ruby/object:Gem::Version
114
114
  version: '0'
115
115
  requirements: []
116
- rubygems_version: 3.0.8
116
+ rubygems_version: 3.0.6
117
117
  signing_key:
118
118
  specification_version: 4
119
119
  summary: QR decoder based on quirc