pdf417 0.1.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.
- data/.document +5 -0
- data/.gitignore +15 -0
- data/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/ext/pdf417/Makefile +157 -0
- data/ext/pdf417/extconf.rb +4 -0
- data/ext/pdf417/pdf417.c +291 -0
- data/ext/pdf417/pdf417.h +27 -0
- data/ext/pdf417/pdf417lib.c +860 -0
- data/ext/pdf417/pdf417lib.h +91 -0
- data/ext/pdf417/pdf417libimp.h +514 -0
- data/ext/pdf417/test.rb +52 -0
- data/lib/pdf417.rb +24 -0
- data/test/pdf417_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +74 -0
data/ext/pdf417/pdf417.h
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
// strfunctions from Nokogiri
|
2
|
+
#define PDF417_STR_NEW2(str) \
|
3
|
+
rb_str_new2((const char *)(str))
|
4
|
+
|
5
|
+
#define PDF417_STR_NEW(str, len) \
|
6
|
+
rb_str_new((const char *)(str), (long)(len))
|
7
|
+
|
8
|
+
#define RBSTR_OR_QNIL(_str) \
|
9
|
+
(_str ? PDF417_STR_NEW2(_str) : Qnil)
|
10
|
+
|
11
|
+
VALUE rb_cPdf417;
|
12
|
+
static VALUE rb_pdf417_encode_text(VALUE self, VALUE text);
|
13
|
+
static VALUE rb_pdf417_codewords(VALUE self);
|
14
|
+
static VALUE rb_pdf417_to_blob(VALUE self);
|
15
|
+
static VALUE rb_pdf417_new(VALUE class, VALUE text);
|
16
|
+
static void rb_pdf417_cleanup(void *p);
|
17
|
+
static VALUE rb_pdf417_init(VALUE self, VALUE text);
|
18
|
+
static VALUE rb_pdf417_bitColumns(VALUE self);
|
19
|
+
static VALUE rb_pdf417_lenBits(VALUE self);
|
20
|
+
static VALUE rb_pdf417_codeRows(VALUE self);
|
21
|
+
static VALUE rb_pdf417_codeColumns(VALUE self);
|
22
|
+
static VALUE rb_pdf417_lenCodewords(VALUE self);
|
23
|
+
static VALUE rb_pdf417_errorLevel(VALUE self);
|
24
|
+
static VALUE rb_pdf417_options(VALUE self);
|
25
|
+
static VALUE rb_pdf417_aspectRatio(VALUE self);
|
26
|
+
static VALUE rb_pdf417_yHeight(VALUE self);
|
27
|
+
static VALUE rb_pdf417_error(VALUE self);
|
@@ -0,0 +1,860 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2003-2005 by Paulo Soares.
|
3
|
+
*
|
4
|
+
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
5
|
+
* (the "License"); you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
|
7
|
+
*
|
8
|
+
* Software distributed under the License is distributed on an "AS IS" basis,
|
9
|
+
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
10
|
+
* for the specific language governing rights and limitations under the License.
|
11
|
+
*
|
12
|
+
* The Original Code is 'pdf417lib, a library to generate the bidimensional barcode PDF417'.
|
13
|
+
*
|
14
|
+
* The Initial Developer of the Original Code is Paulo Soares. Portions created by
|
15
|
+
* the Initial Developer are Copyright (C) 2003 by Paulo Soares.
|
16
|
+
* All Rights Reserved.
|
17
|
+
*
|
18
|
+
* Contributor(s): all the names of the contributors are added in the source code
|
19
|
+
* where applicable.
|
20
|
+
*
|
21
|
+
* Alternatively, the contents of this file may be used under the terms of the
|
22
|
+
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
|
23
|
+
* provisions of LGPL are applicable instead of those above. If you wish to
|
24
|
+
* allow use of your version of this file only under the terms of the LGPL
|
25
|
+
* License and not to allow others to use your version of this file under
|
26
|
+
* the MPL, indicate your decision by deleting the provisions above and
|
27
|
+
* replace them with the notice and other provisions required by the LGPL.
|
28
|
+
* If you do not delete the provisions above, a recipient may use your version
|
29
|
+
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
|
30
|
+
*
|
31
|
+
* This library is free software; you can redistribute it and/or modify it
|
32
|
+
* under the terms of the MPL as stated above or under the terms of the GNU
|
33
|
+
* Library General Public License as published by the Free Software Foundation;
|
34
|
+
* either version 2 of the License, or any later version.
|
35
|
+
*
|
36
|
+
* This library is distributed in the hope that it will be useful, but WITHOUT
|
37
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
38
|
+
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
|
39
|
+
* details.
|
40
|
+
*
|
41
|
+
* If you didn't download this code from the following link, you should check if
|
42
|
+
* you aren't using an obsolete version:
|
43
|
+
* http://sourceforge.net/projects/pdf417lib
|
44
|
+
*/
|
45
|
+
|
46
|
+
|
47
|
+
// #ifndef __APPLE__
|
48
|
+
// #include <malloc.h>
|
49
|
+
// #endif
|
50
|
+
|
51
|
+
#include <string.h>
|
52
|
+
#include <stdio.h>
|
53
|
+
#include <stdlib.h>
|
54
|
+
#include <math.h>
|
55
|
+
#include <ruby.h>
|
56
|
+
|
57
|
+
|
58
|
+
#ifdef __cplusplus
|
59
|
+
extern "C" {
|
60
|
+
#endif
|
61
|
+
|
62
|
+
#define __INCLUDE_PDF417LIBIMP_H__
|
63
|
+
#include "pdf417libimp.h"
|
64
|
+
#undef __INCLUDE_PDF417LIBIMP_H__
|
65
|
+
#include "pdf417lib.h"
|
66
|
+
|
67
|
+
#ifndef NULL
|
68
|
+
#ifdef __cplusplus
|
69
|
+
#define NULL 0
|
70
|
+
#else
|
71
|
+
#define NULL ((void *)0)
|
72
|
+
#endif
|
73
|
+
#endif
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
char* MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^";
|
78
|
+
char* PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'";
|
79
|
+
|
80
|
+
typedef struct _listElement {
|
81
|
+
char type;
|
82
|
+
int start;
|
83
|
+
int end;
|
84
|
+
} listElement, *pListElement;
|
85
|
+
|
86
|
+
typedef struct _arrayList {
|
87
|
+
pListElement array;
|
88
|
+
int size;
|
89
|
+
int capacity;
|
90
|
+
} arrayList, *pArrayList;
|
91
|
+
|
92
|
+
typedef struct _pdf417class {
|
93
|
+
int bitPtr;
|
94
|
+
int cwPtr;
|
95
|
+
pdf417param *param;
|
96
|
+
} pdf417class, *pPdf417class;
|
97
|
+
|
98
|
+
|
99
|
+
static void listInit(pArrayList list) {
|
100
|
+
list->capacity = 20;
|
101
|
+
list->size = 0;
|
102
|
+
list->array = ALLOC_N(listElement, (list->capacity * sizeof(listElement))); //(pListElement)malloc(list->capacity * sizeof(listElement));
|
103
|
+
}
|
104
|
+
|
105
|
+
static void listFree(pArrayList list) {
|
106
|
+
free(list->array);
|
107
|
+
list->array = NULL;
|
108
|
+
}
|
109
|
+
|
110
|
+
static void listAdd(pArrayList list, char type, int start, int end) {
|
111
|
+
if (list->size == list->capacity) {
|
112
|
+
pListElement temp;
|
113
|
+
list->capacity *= 2;
|
114
|
+
temp = ALLOC_N(listElement, (list->capacity * sizeof(listElement))); //(pListElement)malloc(list->capacity * sizeof(listElement));
|
115
|
+
memcpy(temp, list->array, list->size * sizeof(listElement));
|
116
|
+
free(list->array);
|
117
|
+
list->array = temp;
|
118
|
+
}
|
119
|
+
list->array[list->size].type = type;
|
120
|
+
list->array[list->size].start = start;
|
121
|
+
list->array[list->size].end = end;
|
122
|
+
++list->size;
|
123
|
+
}
|
124
|
+
|
125
|
+
static pListElement listGet(pArrayList list, int idx) {
|
126
|
+
if (idx >= list->size || idx < 0)
|
127
|
+
return NULL;
|
128
|
+
return list->array + idx;
|
129
|
+
}
|
130
|
+
|
131
|
+
static void listRemove(pArrayList list, int idx) {
|
132
|
+
if (idx >= list->size || idx < 0)
|
133
|
+
return;
|
134
|
+
--list->size;
|
135
|
+
memmove(list->array + idx, list->array + (idx + 1), (list->size - idx) * sizeof(listElement));
|
136
|
+
}
|
137
|
+
|
138
|
+
static int checkElementType(pListElement p, char type) {
|
139
|
+
if (!p)
|
140
|
+
return 0;
|
141
|
+
return (p->type == type);
|
142
|
+
}
|
143
|
+
|
144
|
+
static int getElementLength(pListElement p) {
|
145
|
+
if (!p)
|
146
|
+
return 0;
|
147
|
+
return p->end - p->start;
|
148
|
+
}
|
149
|
+
|
150
|
+
void pdf417init(pPdf417param param) {
|
151
|
+
param->options = 0;
|
152
|
+
param->outBits = NULL;
|
153
|
+
param->lenBits = 0;
|
154
|
+
param->error = 0;
|
155
|
+
param->lenText = -1;
|
156
|
+
param->text = "";
|
157
|
+
param->yHeight = 3;
|
158
|
+
param->aspectRatio = 0.5;
|
159
|
+
}
|
160
|
+
|
161
|
+
void pdf417free(pPdf417param param) {
|
162
|
+
if (param->outBits != NULL) {
|
163
|
+
free(param->outBits);
|
164
|
+
param->outBits = NULL;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
static void outCodeword17(pPdf417class p, int codeword) {
|
169
|
+
int bytePtr = p->bitPtr / 8;
|
170
|
+
int bit = p->bitPtr - bytePtr * 8;
|
171
|
+
p->param->outBits[bytePtr++] |= codeword >> (9 + bit);
|
172
|
+
p->param->outBits[bytePtr++] |= codeword >> (1 + bit);
|
173
|
+
codeword <<= 8;
|
174
|
+
p->param->outBits[bytePtr] |= codeword >> (1 + bit);
|
175
|
+
p->bitPtr += 17;
|
176
|
+
}
|
177
|
+
|
178
|
+
static void outCodeword18(pPdf417class p, int codeword) {
|
179
|
+
int bytePtr = p->bitPtr / 8;
|
180
|
+
int bit = p->bitPtr - bytePtr * 8;
|
181
|
+
p->param->outBits[bytePtr++] |= codeword >> (10 + bit);
|
182
|
+
p->param->outBits[bytePtr++] |= codeword >> (2 + bit);
|
183
|
+
codeword <<= 8;
|
184
|
+
p->param->outBits[bytePtr] |= codeword >> (2 + bit);
|
185
|
+
if (bit == 7)
|
186
|
+
p->param->outBits[++bytePtr] |= 0x80;
|
187
|
+
p->bitPtr += 18;
|
188
|
+
}
|
189
|
+
|
190
|
+
static void outCodeword(pPdf417class p, int codeword) {
|
191
|
+
outCodeword17(p, codeword);
|
192
|
+
}
|
193
|
+
|
194
|
+
static void outStopPattern(pPdf417class p) {
|
195
|
+
outCodeword18(p, STOP_PATTERN);
|
196
|
+
}
|
197
|
+
|
198
|
+
static void outStartPattern(pPdf417class p) {
|
199
|
+
outCodeword17(p, START_PATTERN);
|
200
|
+
}
|
201
|
+
|
202
|
+
static void outPaintCode(pPdf417class p) {
|
203
|
+
int codePtr = 0;
|
204
|
+
int row;
|
205
|
+
int rowMod;
|
206
|
+
int *cluster;
|
207
|
+
int edge;
|
208
|
+
int column;
|
209
|
+
p->param->bitColumns = START_CODE_SIZE * (p->param->codeColumns + 3) + STOP_SIZE;
|
210
|
+
p->param->lenBits = ((p->param->bitColumns - 1) / 8 + 1) * p->param->codeRows;
|
211
|
+
p->param->outBits = ALLOC_N(char, p->param->lenBits); //(char*)malloc(p->param->lenBits);
|
212
|
+
memset(p->param->outBits, 0, p->param->lenBits);
|
213
|
+
for (row = 0; row < p->param->codeRows; ++row) {
|
214
|
+
p->bitPtr = ((p->param->bitColumns - 1) / 8 + 1) * 8 * row;
|
215
|
+
rowMod = row % 3;
|
216
|
+
cluster = CLUSTERS[rowMod];
|
217
|
+
outStartPattern(p);
|
218
|
+
edge = 0;
|
219
|
+
switch (rowMod) {
|
220
|
+
case 0:
|
221
|
+
edge = 30 * (row / 3) + ((p->param->codeRows - 1) / 3);
|
222
|
+
break;
|
223
|
+
case 1:
|
224
|
+
edge = 30 * (row / 3) + p->param->errorLevel * 3 + ((p->param->codeRows - 1) % 3);
|
225
|
+
break;
|
226
|
+
default:
|
227
|
+
edge = 30 * (row / 3) + p->param->codeColumns - 1;
|
228
|
+
break;
|
229
|
+
}
|
230
|
+
outCodeword(p, cluster[edge]);
|
231
|
+
|
232
|
+
for (column = 0; column < p->param->codeColumns; ++column) {
|
233
|
+
outCodeword(p, cluster[p->param->codewords[codePtr++]]);
|
234
|
+
}
|
235
|
+
|
236
|
+
switch (rowMod) {
|
237
|
+
case 0:
|
238
|
+
edge = 30 * (row / 3) + p->param->codeColumns - 1;
|
239
|
+
break;
|
240
|
+
case 1:
|
241
|
+
edge = 30 * (row / 3) + ((p->param->codeRows - 1) / 3);
|
242
|
+
break;
|
243
|
+
default:
|
244
|
+
edge = 30 * (row / 3) + p->param->errorLevel * 3 + ((p->param->codeRows - 1) % 3);
|
245
|
+
break;
|
246
|
+
}
|
247
|
+
outCodeword(p, cluster[edge]);
|
248
|
+
outStopPattern(p);
|
249
|
+
}
|
250
|
+
if (p->param->options & PDF417_INVERT_BITMAP) {
|
251
|
+
char* pm = p->param->outBits;
|
252
|
+
char* end = pm + p->param->lenBits;
|
253
|
+
while (pm < end)
|
254
|
+
*(pm++) ^= 0xff;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
static void calculateErrorCorrection(pPdf417class p, int dest) {
|
259
|
+
int t1 = 0;
|
260
|
+
int t2 = 0;
|
261
|
+
int t3 = 0;
|
262
|
+
int *A;
|
263
|
+
int Alength;
|
264
|
+
int *E;
|
265
|
+
int lastE;
|
266
|
+
int k, e, j;
|
267
|
+
if (p->param->errorLevel < 0 || p->param->errorLevel > 8)
|
268
|
+
p->param->errorLevel = 0;
|
269
|
+
A = ERROR_LEVEL[p->param->errorLevel];
|
270
|
+
Alength = 2 << p->param->errorLevel;
|
271
|
+
E = p->param->codewords + dest;
|
272
|
+
memset(E, 0, Alength * sizeof(int));
|
273
|
+
lastE = Alength - 1;
|
274
|
+
for (k = 0; k < p->param->lenCodewords; ++k) {
|
275
|
+
t1 = p->param->codewords[k] + E[0];
|
276
|
+
for (e = 0; e <= lastE; ++e) {
|
277
|
+
t2 = (t1 * A[lastE - e]) % MOD;
|
278
|
+
t3 = MOD - t2;
|
279
|
+
E[e] = ((e == lastE ? 0 : E[e + 1]) + t3) % MOD;
|
280
|
+
}
|
281
|
+
}
|
282
|
+
for (j = 0; j < Alength; ++j)
|
283
|
+
E[j] = (MOD - E[j]) % MOD;
|
284
|
+
}
|
285
|
+
|
286
|
+
static int getTextTypeAndValue(char* text, int size, int idx) {
|
287
|
+
int c;
|
288
|
+
char *ms, *ps;
|
289
|
+
if (idx >= size)
|
290
|
+
return 0;
|
291
|
+
c = text[idx];
|
292
|
+
if (c >= 'A' && c <= 'Z')
|
293
|
+
return (ALPHA + c - 'A');
|
294
|
+
if (c >= 'a' && c <= 'z')
|
295
|
+
return (LOWER + c - 'a');
|
296
|
+
if (c == ' ')
|
297
|
+
return (ALPHA + LOWER + MIXED + SPACE);
|
298
|
+
ms = strchr(MIXED_SET, c);
|
299
|
+
ps = strchr(PUNCTUATION_SET, c);
|
300
|
+
if (!ms && !ps)
|
301
|
+
return (ISBYTE + (c & 0xff));
|
302
|
+
if (ms - MIXED_SET == ps - PUNCTUATION_SET)
|
303
|
+
return (MIXED + PUNCTUATION + (ms - MIXED_SET));
|
304
|
+
if (ms != NULL)
|
305
|
+
return (MIXED + (ms - MIXED_SET));
|
306
|
+
return (PUNCTUATION + (ps - PUNCTUATION_SET));
|
307
|
+
}
|
308
|
+
|
309
|
+
static void textCompaction(pPdf417class p, int start, int length) {
|
310
|
+
int dest[ABSOLUTE_MAX_TEXT_SIZE * 2];
|
311
|
+
char* text = p->param->text;
|
312
|
+
int mode = ALPHA;
|
313
|
+
int ptr = 0;
|
314
|
+
int fullBytes = 0;
|
315
|
+
int v = 0;
|
316
|
+
int k;
|
317
|
+
int size;
|
318
|
+
memset(dest, 0, sizeof(dest));
|
319
|
+
length += start;
|
320
|
+
for (k = start; k < length; ++k) {
|
321
|
+
v = getTextTypeAndValue(text, length, k);
|
322
|
+
if ((v & mode) != 0) {
|
323
|
+
dest[ptr++] = v & 0xff;
|
324
|
+
continue;
|
325
|
+
}
|
326
|
+
if ((v & ISBYTE) != 0) {
|
327
|
+
if ((ptr & 1) != 0) {
|
328
|
+
dest[ptr++] = (mode & PUNCTUATION) != 0 ? PAL : PS;
|
329
|
+
mode = (mode & PUNCTUATION) != 0 ? ALPHA : mode;
|
330
|
+
}
|
331
|
+
dest[ptr++] = BYTESHIFT;
|
332
|
+
dest[ptr++] = v & 0xff;
|
333
|
+
fullBytes += 2;
|
334
|
+
continue;
|
335
|
+
}
|
336
|
+
switch (mode) {
|
337
|
+
case ALPHA:
|
338
|
+
if ((v & LOWER) != 0) {
|
339
|
+
dest[ptr++] = LL;
|
340
|
+
dest[ptr++] = v & 0xff;
|
341
|
+
mode = LOWER;
|
342
|
+
}
|
343
|
+
else if ((v & MIXED) != 0) {
|
344
|
+
dest[ptr++] = ML;
|
345
|
+
dest[ptr++] = v & 0xff;
|
346
|
+
mode = MIXED;
|
347
|
+
}
|
348
|
+
else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
|
349
|
+
dest[ptr++] = ML;
|
350
|
+
dest[ptr++] = PL;
|
351
|
+
dest[ptr++] = v & 0xff;
|
352
|
+
mode = PUNCTUATION;
|
353
|
+
}
|
354
|
+
else {
|
355
|
+
dest[ptr++] = PS;
|
356
|
+
dest[ptr++] = v & 0xff;
|
357
|
+
}
|
358
|
+
break;
|
359
|
+
case LOWER:
|
360
|
+
if ((v & ALPHA) != 0) {
|
361
|
+
if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & ALPHA) != 0) {
|
362
|
+
dest[ptr++] = ML;
|
363
|
+
dest[ptr++] = AL;
|
364
|
+
mode = ALPHA;
|
365
|
+
}
|
366
|
+
else {
|
367
|
+
dest[ptr++] = AS;
|
368
|
+
}
|
369
|
+
dest[ptr++] = v & 0xff;
|
370
|
+
}
|
371
|
+
else if ((v & MIXED) != 0) {
|
372
|
+
dest[ptr++] = ML;
|
373
|
+
dest[ptr++] = v & 0xff;
|
374
|
+
mode = MIXED;
|
375
|
+
}
|
376
|
+
else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
|
377
|
+
dest[ptr++] = ML;
|
378
|
+
dest[ptr++] = PL;
|
379
|
+
dest[ptr++] = v & 0xff;
|
380
|
+
mode = PUNCTUATION;
|
381
|
+
}
|
382
|
+
else {
|
383
|
+
dest[ptr++] = PS;
|
384
|
+
dest[ptr++] = v & 0xff;
|
385
|
+
}
|
386
|
+
break;
|
387
|
+
case MIXED:
|
388
|
+
if ((v & LOWER) != 0) {
|
389
|
+
dest[ptr++] = LL;
|
390
|
+
dest[ptr++] = v & 0xff;
|
391
|
+
mode = LOWER;
|
392
|
+
}
|
393
|
+
else if ((v & ALPHA) != 0) {
|
394
|
+
dest[ptr++] = AL;
|
395
|
+
dest[ptr++] = v & 0xff;
|
396
|
+
mode = ALPHA;
|
397
|
+
}
|
398
|
+
else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
|
399
|
+
dest[ptr++] = PL;
|
400
|
+
dest[ptr++] = v & 0xff;
|
401
|
+
mode = PUNCTUATION;
|
402
|
+
}
|
403
|
+
else {
|
404
|
+
dest[ptr++] = PS;
|
405
|
+
dest[ptr++] = v & 0xff;
|
406
|
+
}
|
407
|
+
break;
|
408
|
+
case PUNCTUATION:
|
409
|
+
dest[ptr++] = PAL;
|
410
|
+
mode = ALPHA;
|
411
|
+
--k;
|
412
|
+
break;
|
413
|
+
}
|
414
|
+
}
|
415
|
+
if ((ptr & 1) != 0)
|
416
|
+
dest[ptr++] = PS;
|
417
|
+
size = (ptr + fullBytes) / 2;
|
418
|
+
if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
|
419
|
+
p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
|
420
|
+
return;
|
421
|
+
}
|
422
|
+
length = ptr;
|
423
|
+
ptr = 0;
|
424
|
+
while (ptr < length) {
|
425
|
+
v = dest[ptr++];
|
426
|
+
if (v >= 30) {
|
427
|
+
p->param->codewords[p->cwPtr++] = v;
|
428
|
+
p->param->codewords[p->cwPtr++] = dest[ptr++];
|
429
|
+
}
|
430
|
+
else
|
431
|
+
p->param->codewords[p->cwPtr++] = v * 30 + dest[ptr++];
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
435
|
+
static void basicNumberCompaction(pPdf417class p, int start, int length) {
|
436
|
+
char* text = p->param->text;
|
437
|
+
int* ret = p->param->codewords + p->cwPtr;
|
438
|
+
int retLast = length / 3;
|
439
|
+
int ni, k;
|
440
|
+
p->cwPtr += retLast + 1;
|
441
|
+
memset(ret, 0, (retLast + 1) * sizeof(int));
|
442
|
+
ret[retLast] = 1;
|
443
|
+
length += start;
|
444
|
+
for (ni = start; ni < length; ++ni) {
|
445
|
+
// multiply by 10
|
446
|
+
for (k = retLast; k >= 0; --k)
|
447
|
+
ret[k] *= 10;
|
448
|
+
// add the digit
|
449
|
+
ret[retLast] += text[ni] - '0';
|
450
|
+
// propagate carry
|
451
|
+
for (k = retLast; k > 0; --k) {
|
452
|
+
ret[k - 1] += ret[k] / 900;
|
453
|
+
ret[k] %= 900;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
static void numberCompaction(pPdf417class p, int start, int length) {
|
459
|
+
int full = (length / 44) * 15;
|
460
|
+
int size = length % 44;
|
461
|
+
int k;
|
462
|
+
if (size == 0)
|
463
|
+
size = full;
|
464
|
+
else
|
465
|
+
size = full + size / 3 + 1;
|
466
|
+
if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
|
467
|
+
p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
|
468
|
+
return;
|
469
|
+
}
|
470
|
+
length += start;
|
471
|
+
for (k = start; k < length; k += 44) {
|
472
|
+
size = length - k < 44 ? length - k : 44;
|
473
|
+
basicNumberCompaction(p, k, size);
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
static void byteCompaction6(pPdf417class p, int start) {
|
478
|
+
int length = 6;
|
479
|
+
char* text = p->param->text;
|
480
|
+
int* ret = p->param->codewords + p->cwPtr;
|
481
|
+
int retLast = 4;
|
482
|
+
int ni, k;
|
483
|
+
p->cwPtr += retLast + 1;
|
484
|
+
memset(ret, 0, (retLast + 1) * sizeof(int));
|
485
|
+
length += start;
|
486
|
+
for (ni = start; ni < length; ++ni) {
|
487
|
+
// multiply by 256
|
488
|
+
for (k = retLast; k >= 0; --k)
|
489
|
+
ret[k] *= 256;
|
490
|
+
// add the digit
|
491
|
+
ret[retLast] += (int)text[ni] & 0xff;
|
492
|
+
// propagate carry
|
493
|
+
for (k = retLast; k > 0; --k) {
|
494
|
+
ret[k - 1] += ret[k] / 900;
|
495
|
+
ret[k] %= 900;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
}
|
499
|
+
|
500
|
+
static void byteCompaction(pPdf417class p, int start, int length) {
|
501
|
+
int k, j;
|
502
|
+
int size = (length / 6) * 5 + (length % 6);
|
503
|
+
if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
|
504
|
+
p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
|
505
|
+
return;
|
506
|
+
}
|
507
|
+
length += start;
|
508
|
+
for (k = start; k < length; k += 6) {
|
509
|
+
size = length - k < 44 ? length - k : 6;
|
510
|
+
if (size < 6) {
|
511
|
+
for (j = 0; j < size; ++j)
|
512
|
+
p->param->codewords[p->cwPtr++] = (int)p->param->text[k + j] & 0xff;
|
513
|
+
}
|
514
|
+
else {
|
515
|
+
byteCompaction6(p, k);
|
516
|
+
}
|
517
|
+
}
|
518
|
+
}
|
519
|
+
|
520
|
+
static void breakString(pPdf417class p, pArrayList list) {
|
521
|
+
char* text = p->param->text;
|
522
|
+
int textLength = p->param->lenText;
|
523
|
+
int lastP = 0;
|
524
|
+
int startN = 0;
|
525
|
+
int nd = 0;
|
526
|
+
char c = 0;
|
527
|
+
int k, ptrS, lastTxt, j, txt;
|
528
|
+
pListElement v;
|
529
|
+
pListElement vp;
|
530
|
+
pListElement vn;
|
531
|
+
list->size = 0;
|
532
|
+
for (k = 0; k < textLength; ++k) {
|
533
|
+
c = text[k];
|
534
|
+
if (c >= '0' && c <= '9') {
|
535
|
+
if (nd == 0)
|
536
|
+
startN = k;
|
537
|
+
++nd;
|
538
|
+
continue;
|
539
|
+
}
|
540
|
+
if (nd >= 13) {
|
541
|
+
if (lastP != startN) {
|
542
|
+
c = text[lastP];
|
543
|
+
ptrS = lastP;
|
544
|
+
lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
|
545
|
+
for (j = lastP; j < startN; ++j) {
|
546
|
+
c = text[j];
|
547
|
+
txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
|
548
|
+
if (txt != lastTxt) {
|
549
|
+
listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
|
550
|
+
lastP = j;
|
551
|
+
lastTxt = txt;
|
552
|
+
}
|
553
|
+
}
|
554
|
+
listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
|
555
|
+
}
|
556
|
+
listAdd(list, 'N', startN, k);
|
557
|
+
lastP = k;
|
558
|
+
}
|
559
|
+
nd = 0;
|
560
|
+
}
|
561
|
+
if (nd < 13)
|
562
|
+
startN = textLength;
|
563
|
+
if (lastP != startN) {
|
564
|
+
c = text[lastP];
|
565
|
+
ptrS = lastP;
|
566
|
+
lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
|
567
|
+
for (j = lastP; j < startN; ++j) {
|
568
|
+
c = text[j];
|
569
|
+
txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
|
570
|
+
if (txt != lastTxt) {
|
571
|
+
listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
|
572
|
+
lastP = j;
|
573
|
+
lastTxt = txt;
|
574
|
+
}
|
575
|
+
}
|
576
|
+
listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
|
577
|
+
}
|
578
|
+
if (nd >= 13)
|
579
|
+
listAdd(list, 'N', startN, textLength);
|
580
|
+
//optimize
|
581
|
+
//merge short binary
|
582
|
+
for (k = 0; k < list->size; ++k) {
|
583
|
+
v = listGet(list, k);
|
584
|
+
vp = listGet(list, k - 1);
|
585
|
+
vn = listGet(list, k + 1);;
|
586
|
+
if (checkElementType(v, 'B') && getElementLength(v) == 1) {
|
587
|
+
if (checkElementType(vp, 'T') && checkElementType(vn, 'T')
|
588
|
+
&& getElementLength(vp) + getElementLength(vn) >= 3) {
|
589
|
+
vp->end = vn->end;
|
590
|
+
listRemove(list, k);
|
591
|
+
listRemove(list, k);
|
592
|
+
k = -1;
|
593
|
+
continue;
|
594
|
+
}
|
595
|
+
}
|
596
|
+
}
|
597
|
+
//merge text sections
|
598
|
+
for (k = 0; k < list->size; ++k) {
|
599
|
+
v = listGet(list, k);
|
600
|
+
vp = listGet(list, k - 1);
|
601
|
+
vn = listGet(list, k + 1);;
|
602
|
+
if (checkElementType(v, 'T') && getElementLength(v) >= 5) {
|
603
|
+
int redo = 0;
|
604
|
+
if ((checkElementType(vp, 'B') && getElementLength(vp) == 1) || checkElementType(vp, 'T')) {
|
605
|
+
redo = 1;
|
606
|
+
v->start = vp->start;
|
607
|
+
listRemove(list, k - 1);
|
608
|
+
--k;
|
609
|
+
}
|
610
|
+
if ((checkElementType(vn, 'B') && getElementLength(vn) == 1) || checkElementType(vn, 'T')) {
|
611
|
+
redo = 1;
|
612
|
+
v->end = vn->end;
|
613
|
+
listRemove(list, k + 1);
|
614
|
+
}
|
615
|
+
if (redo) {
|
616
|
+
k = -1;
|
617
|
+
continue;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
}
|
621
|
+
//merge binary sections
|
622
|
+
for (k = 0; k < list->size; ++k) {
|
623
|
+
v = listGet(list, k);
|
624
|
+
vp = listGet(list, k - 1);
|
625
|
+
vn = listGet(list, k + 1);;
|
626
|
+
if (checkElementType(v, 'B')) {
|
627
|
+
int redo = 0;
|
628
|
+
if ((checkElementType(vp, 'T') && getElementLength(vp) < 5) || checkElementType(vp, 'B')) {
|
629
|
+
redo = 1;
|
630
|
+
v->start = vp->start;
|
631
|
+
listRemove(list, k - 1);
|
632
|
+
--k;
|
633
|
+
}
|
634
|
+
if ((checkElementType(vn, 'T') && getElementLength(vn) < 5) || checkElementType(vn, 'B')) {
|
635
|
+
redo = 1;
|
636
|
+
v->end = vn->end;
|
637
|
+
listRemove(list, k + 1);
|
638
|
+
}
|
639
|
+
if (redo) {
|
640
|
+
k = -1;
|
641
|
+
continue;
|
642
|
+
}
|
643
|
+
}
|
644
|
+
}
|
645
|
+
// check if all numbers
|
646
|
+
if (list->size == 1 && (v = listGet(list, 0))->type == 'T' && getElementLength(v) >= 8) {
|
647
|
+
for (k = v->start; k < v->end; ++k) {
|
648
|
+
c = text[k];
|
649
|
+
if (c < '0' || c > '9')
|
650
|
+
break;
|
651
|
+
}
|
652
|
+
if (k == v->end)
|
653
|
+
v->type = 'N';
|
654
|
+
}
|
655
|
+
}
|
656
|
+
|
657
|
+
static void assemble(pPdf417class p, pArrayList list) {
|
658
|
+
int k;
|
659
|
+
if (list->size == 0)
|
660
|
+
return;
|
661
|
+
p->cwPtr = 1;
|
662
|
+
for (k = 0; k < list->size; ++k) {
|
663
|
+
pListElement v = listGet(list, k);
|
664
|
+
switch (v->type) {
|
665
|
+
case 'T':
|
666
|
+
if (k != 0)
|
667
|
+
p->param->codewords[p->cwPtr++] = TEXT_MODE;
|
668
|
+
textCompaction(p, v->start, v->end - v->start);
|
669
|
+
break;
|
670
|
+
case 'N':
|
671
|
+
p->param->codewords[p->cwPtr++] = NUMERIC_MODE;
|
672
|
+
numberCompaction(p, v->start, v->end - v->start);
|
673
|
+
break;
|
674
|
+
case 'B':
|
675
|
+
p->param->codewords[p->cwPtr++] = (v->end - v->start) % 6 ? BYTE_MODE : BYTE_MODE_6;
|
676
|
+
byteCompaction(p, v->start, v->end - v->start);
|
677
|
+
break;
|
678
|
+
}
|
679
|
+
if (p->param->error)
|
680
|
+
return;
|
681
|
+
}
|
682
|
+
}
|
683
|
+
|
684
|
+
static int maxPossibleErrorLevel(int remain) {
|
685
|
+
int level = 8;
|
686
|
+
int size = 512;
|
687
|
+
while (level > 0) {
|
688
|
+
if (remain >= size)
|
689
|
+
return level;
|
690
|
+
--level;
|
691
|
+
size >>= 1;
|
692
|
+
}
|
693
|
+
return 0;
|
694
|
+
}
|
695
|
+
|
696
|
+
static void dumpList(pPdf417class p, pArrayList list) {
|
697
|
+
int k;
|
698
|
+
if (list->size == 0)
|
699
|
+
return;
|
700
|
+
for (k = 0; k < list->size; ++k) {
|
701
|
+
pListElement v = listGet(list, k);
|
702
|
+
printf("%c%.*s\n", v->type, v->end - v->start, p->param->text + v->start);
|
703
|
+
}
|
704
|
+
}
|
705
|
+
|
706
|
+
static int getMaxSquare(pPdf417param p) {
|
707
|
+
if (p->codeColumns > 21) {
|
708
|
+
p->codeColumns = 29;
|
709
|
+
p->codeRows = 32;
|
710
|
+
}
|
711
|
+
else {
|
712
|
+
p->codeColumns = 16;
|
713
|
+
p->codeRows = 58;
|
714
|
+
}
|
715
|
+
return MAX_DATA_CODEWORDS + 2;
|
716
|
+
}
|
717
|
+
|
718
|
+
void fetchCodewords(pPdf417param p) {
|
719
|
+
pdf417class pp;
|
720
|
+
arrayList list;
|
721
|
+
pp.param = p;
|
722
|
+
p->error = 0;
|
723
|
+
if (p->lenText < 0)
|
724
|
+
p->lenText = strlen(p->text);
|
725
|
+
if (p->lenText > ABSOLUTE_MAX_TEXT_SIZE) {
|
726
|
+
p->error = PDF417_ERROR_TEXT_TOO_BIG;
|
727
|
+
return;
|
728
|
+
}
|
729
|
+
listInit(&list);
|
730
|
+
breakString(&pp, &list);
|
731
|
+
//dumpList(&pp, &list);
|
732
|
+
assemble(&pp, &list);
|
733
|
+
listFree(&list);
|
734
|
+
if (p->error)
|
735
|
+
return;
|
736
|
+
p->codewords[0] = p->lenCodewords = pp.cwPtr;
|
737
|
+
|
738
|
+
}
|
739
|
+
|
740
|
+
void paintCode(pPdf417param p) {
|
741
|
+
pdf417class pp;
|
742
|
+
arrayList list;
|
743
|
+
int maxErr, fixedColumn, lenErr, tot, skipRowColAdjust, pad;
|
744
|
+
pp.param = p;
|
745
|
+
p->error = 0;
|
746
|
+
if (p->options & PDF417_USE_RAW_CODEWORDS) {
|
747
|
+
if (p->lenCodewords > MAX_DATA_CODEWORDS || p->lenCodewords < 1 || p->lenCodewords != p->codewords[0]) {
|
748
|
+
p->error = PDF417_ERROR_INVALID_PARAMS;
|
749
|
+
return;
|
750
|
+
}
|
751
|
+
}
|
752
|
+
else {
|
753
|
+
if (p->lenText < 0)
|
754
|
+
p->lenText = strlen(p->text);
|
755
|
+
if (p->lenText > ABSOLUTE_MAX_TEXT_SIZE) {
|
756
|
+
p->error = PDF417_ERROR_TEXT_TOO_BIG;
|
757
|
+
return;
|
758
|
+
}
|
759
|
+
listInit(&list);
|
760
|
+
breakString(&pp, &list);
|
761
|
+
// dumpList(&pp, &list);
|
762
|
+
assemble(&pp, &list);
|
763
|
+
listFree(&list);
|
764
|
+
if (p->error)
|
765
|
+
return;
|
766
|
+
p->codewords[0] = p->lenCodewords = pp.cwPtr;
|
767
|
+
}
|
768
|
+
maxErr = maxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - p->lenCodewords);
|
769
|
+
if (!(p->options & PDF417_USE_ERROR_LEVEL)) {
|
770
|
+
if (p->lenCodewords < 41)
|
771
|
+
p->errorLevel = 2;
|
772
|
+
else if (p->lenCodewords < 161)
|
773
|
+
p->errorLevel = 3;
|
774
|
+
else if (p->lenCodewords < 321)
|
775
|
+
p->errorLevel = 4;
|
776
|
+
else
|
777
|
+
p->errorLevel = 5;
|
778
|
+
}
|
779
|
+
if (p->errorLevel < 0)
|
780
|
+
p->errorLevel = 0;
|
781
|
+
else if (p->errorLevel > maxErr)
|
782
|
+
p->errorLevel = maxErr;
|
783
|
+
if (p->codeColumns < 1)
|
784
|
+
p->codeColumns = 1;
|
785
|
+
else if (p->codeColumns > 30)
|
786
|
+
p->codeColumns = 30;
|
787
|
+
if (p->codeRows < 3)
|
788
|
+
p->codeRows = 3;
|
789
|
+
else if (p->codeRows > 90)
|
790
|
+
p->codeRows = 90;
|
791
|
+
lenErr = 2 << p->errorLevel;
|
792
|
+
fixedColumn = !(p->options & PDF417_FIXED_ROWS);
|
793
|
+
skipRowColAdjust = 0;
|
794
|
+
tot = p->lenCodewords + lenErr;
|
795
|
+
if (p->options & PDF417_FIXED_RECTANGLE) {
|
796
|
+
tot = p->codeColumns * p->codeRows;
|
797
|
+
if (tot > MAX_DATA_CODEWORDS + 2) {
|
798
|
+
tot = getMaxSquare(p);
|
799
|
+
}
|
800
|
+
if (tot < p->lenCodewords + lenErr)
|
801
|
+
tot = p->lenCodewords + lenErr;
|
802
|
+
else
|
803
|
+
skipRowColAdjust = 1;
|
804
|
+
}
|
805
|
+
else if (!(p->options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS))) {
|
806
|
+
double c, b;
|
807
|
+
fixedColumn = 1;
|
808
|
+
if (p->aspectRatio < 0.001)
|
809
|
+
p->aspectRatio = 0.001f;
|
810
|
+
else if (p->aspectRatio > 1000)
|
811
|
+
p->aspectRatio = 1000;
|
812
|
+
b = 73 * p->aspectRatio - 4;
|
813
|
+
c = (-b + sqrt(b * b + 4 * 17 * p->aspectRatio * (p->lenCodewords + lenErr) * p->yHeight)) / (2 * 17 * p->aspectRatio);
|
814
|
+
p->codeColumns = (int)(c + 0.5);
|
815
|
+
if (p->codeColumns < 1)
|
816
|
+
p->codeColumns = 1;
|
817
|
+
else if (p->codeColumns > 30)
|
818
|
+
p->codeColumns = 30;
|
819
|
+
}
|
820
|
+
if (!skipRowColAdjust) {
|
821
|
+
if (fixedColumn) {
|
822
|
+
p->codeRows = (tot - 1) / p->codeColumns + 1;
|
823
|
+
if (p->codeRows < 3)
|
824
|
+
p->codeRows = 3;
|
825
|
+
else if (p->codeRows > 90) {
|
826
|
+
p->codeRows = 90;
|
827
|
+
p->codeColumns = (tot - 1) / 90 + 1;
|
828
|
+
}
|
829
|
+
}
|
830
|
+
else {
|
831
|
+
p->codeColumns = (tot - 1) / p->codeRows + 1;
|
832
|
+
if (p->codeColumns > 30) {
|
833
|
+
p->codeColumns = 30;
|
834
|
+
p->codeRows = (tot - 1) / 30 + 1;
|
835
|
+
}
|
836
|
+
}
|
837
|
+
tot = p->codeRows * p->codeColumns;
|
838
|
+
}
|
839
|
+
if (tot > MAX_DATA_CODEWORDS + 2) {
|
840
|
+
tot = getMaxSquare(p);
|
841
|
+
}
|
842
|
+
p->errorLevel = maxPossibleErrorLevel(tot - p->lenCodewords);
|
843
|
+
lenErr = 2 << p->errorLevel;
|
844
|
+
pad = tot - lenErr - p->lenCodewords;
|
845
|
+
pp.cwPtr = p->lenCodewords;
|
846
|
+
while (pad--)
|
847
|
+
p->codewords[pp.cwPtr++] = TEXT_MODE;
|
848
|
+
p->codewords[0] = p->lenCodewords = pp.cwPtr;
|
849
|
+
calculateErrorCorrection(&pp, pp.param->lenCodewords);
|
850
|
+
pp.param->lenCodewords = tot;
|
851
|
+
outPaintCode(&pp);
|
852
|
+
}
|
853
|
+
|
854
|
+
#ifdef __cplusplus
|
855
|
+
}
|
856
|
+
#endif
|
857
|
+
|
858
|
+
|
859
|
+
|
860
|
+
|