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.
@@ -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
+