barby-pdf417 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,829 @@
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
+ #ifndef __APPLE__
47
+ #include <malloc.h>
48
+ #endif
49
+
50
+ #include <string.h>
51
+ #include <stdio.h>
52
+ #include <math.h>
53
+ #include <stdlib.h>
54
+
55
+ #ifdef __cplusplus
56
+ extern "C" {
57
+ #endif
58
+
59
+ #define __INCLUDE_PDF417LIBIMP_H__
60
+ #include "pdf417libimp.h"
61
+ #undef __INCLUDE_PDF417LIBIMP_H__
62
+ #include "pdf417lib.h"
63
+
64
+ #ifndef NULL
65
+ #ifdef __cplusplus
66
+ #define NULL 0
67
+ #else
68
+ #define NULL ((void *)0)
69
+ #endif
70
+ #endif
71
+
72
+ char* MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^";
73
+ char* PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'";
74
+
75
+ typedef struct _listElement {
76
+ char type;
77
+ int start;
78
+ int end;
79
+ } listElement, *pListElement;
80
+
81
+ typedef struct _arrayList {
82
+ pListElement array;
83
+ int size;
84
+ int capacity;
85
+ } arrayList, *pArrayList;
86
+
87
+ typedef struct _pdf417class {
88
+ int bitPtr;
89
+ int cwPtr;
90
+ pdf417param *param;
91
+ } pdf417class, *pPdf417class;
92
+
93
+
94
+ static void listInit(pArrayList list) {
95
+ list->capacity = 20;
96
+ list->size = 0;
97
+ list->array = (pListElement)malloc(list->capacity * sizeof(listElement));
98
+ }
99
+
100
+ static void listFree(pArrayList list) {
101
+ free(list->array);
102
+ list->array = NULL;
103
+ }
104
+
105
+ static void listAdd(pArrayList list, char type, int start, int end) {
106
+ if (list->size == list->capacity) {
107
+ pListElement temp;
108
+ list->capacity *= 2;
109
+ temp = (pListElement)malloc(list->capacity * sizeof(listElement));
110
+ memcpy(temp, list->array, list->size * sizeof(listElement));
111
+ free(list->array);
112
+ list->array = temp;
113
+ }
114
+ list->array[list->size].type = type;
115
+ list->array[list->size].start = start;
116
+ list->array[list->size].end = end;
117
+ ++list->size;
118
+ }
119
+
120
+ static pListElement listGet(pArrayList list, int idx) {
121
+ if (idx >= list->size || idx < 0)
122
+ return NULL;
123
+ return list->array + idx;
124
+ }
125
+
126
+ static void listRemove(pArrayList list, int idx) {
127
+ if (idx >= list->size || idx < 0)
128
+ return;
129
+ --list->size;
130
+ memmove(list->array + idx, list->array + (idx + 1), (list->size - idx) * sizeof(listElement));
131
+ }
132
+
133
+ static int checkElementType(pListElement p, char type) {
134
+ if (!p)
135
+ return 0;
136
+ return (p->type == type);
137
+ }
138
+
139
+ static int getElementLength(pListElement p) {
140
+ if (!p)
141
+ return 0;
142
+ return p->end - p->start;
143
+ }
144
+
145
+ void pdf417init(pPdf417param param) {
146
+ param->options = 0;
147
+ param->outBits = NULL;
148
+ param->lenBits = 0;
149
+ param->error = 0;
150
+ param->lenText = -1;
151
+ param->text = "";
152
+ param->yHeight = 3;
153
+ param->aspectRatio = 0.5;
154
+ }
155
+
156
+ void pdf417free(pPdf417param param) {
157
+ if (param->outBits != NULL) {
158
+ free(param->outBits);
159
+ param->outBits = NULL;
160
+ }
161
+ }
162
+
163
+ static void outCodeword17(pPdf417class p, int codeword) {
164
+ int bytePtr = p->bitPtr / 8;
165
+ int bit = p->bitPtr - bytePtr * 8;
166
+ p->param->outBits[bytePtr++] |= codeword >> (9 + bit);
167
+ p->param->outBits[bytePtr++] |= codeword >> (1 + bit);
168
+ codeword <<= 8;
169
+ p->param->outBits[bytePtr] |= codeword >> (1 + bit);
170
+ p->bitPtr += 17;
171
+ }
172
+
173
+ static void outCodeword18(pPdf417class p, int codeword) {
174
+ int bytePtr = p->bitPtr / 8;
175
+ int bit = p->bitPtr - bytePtr * 8;
176
+ p->param->outBits[bytePtr++] |= codeword >> (10 + bit);
177
+ p->param->outBits[bytePtr++] |= codeword >> (2 + bit);
178
+ codeword <<= 8;
179
+ p->param->outBits[bytePtr] |= codeword >> (2 + bit);
180
+ if (bit == 7)
181
+ p->param->outBits[++bytePtr] |= 0x80;
182
+ p->bitPtr += 18;
183
+ }
184
+
185
+ static void outCodeword(pPdf417class p, int codeword) {
186
+ outCodeword17(p, codeword);
187
+ }
188
+
189
+ static void outStopPattern(pPdf417class p) {
190
+ outCodeword18(p, STOP_PATTERN);
191
+ }
192
+
193
+ static void outStartPattern(pPdf417class p) {
194
+ outCodeword17(p, START_PATTERN);
195
+ }
196
+
197
+ static void outPaintCode(pPdf417class p) {
198
+ int codePtr = 0;
199
+ int row;
200
+ int rowMod;
201
+ int *cluster;
202
+ int edge;
203
+ int column;
204
+ p->param->bitColumns = START_CODE_SIZE * (p->param->codeColumns + 3) + STOP_SIZE;
205
+ p->param->lenBits = ((p->param->bitColumns - 1) / 8 + 1) * p->param->codeRows;
206
+ p->param->outBits = (char*)malloc(p->param->lenBits);
207
+ memset(p->param->outBits, 0, p->param->lenBits);
208
+ for (row = 0; row < p->param->codeRows; ++row) {
209
+ p->bitPtr = ((p->param->bitColumns - 1) / 8 + 1) * 8 * row;
210
+ rowMod = row % 3;
211
+ cluster = CLUSTERS[rowMod];
212
+ outStartPattern(p);
213
+ edge = 0;
214
+ switch (rowMod) {
215
+ case 0:
216
+ edge = 30 * (row / 3) + ((p->param->codeRows - 1) / 3);
217
+ break;
218
+ case 1:
219
+ edge = 30 * (row / 3) + p->param->errorLevel * 3 + ((p->param->codeRows - 1) % 3);
220
+ break;
221
+ default:
222
+ edge = 30 * (row / 3) + p->param->codeColumns - 1;
223
+ break;
224
+ }
225
+ outCodeword(p, cluster[edge]);
226
+
227
+ for (column = 0; column < p->param->codeColumns; ++column) {
228
+ outCodeword(p, cluster[p->param->codewords[codePtr++]]);
229
+ }
230
+
231
+ switch (rowMod) {
232
+ case 0:
233
+ edge = 30 * (row / 3) + p->param->codeColumns - 1;
234
+ break;
235
+ case 1:
236
+ edge = 30 * (row / 3) + ((p->param->codeRows - 1) / 3);
237
+ break;
238
+ default:
239
+ edge = 30 * (row / 3) + p->param->errorLevel * 3 + ((p->param->codeRows - 1) % 3);
240
+ break;
241
+ }
242
+ outCodeword(p, cluster[edge]);
243
+ outStopPattern(p);
244
+ }
245
+ if (p->param->options & PDF417_INVERT_BITMAP) {
246
+ char* pm = p->param->outBits;
247
+ char* end = pm + p->param->lenBits;
248
+ while (pm < end)
249
+ *(pm++) ^= 0xff;
250
+ }
251
+ }
252
+
253
+ static void calculateErrorCorrection(pPdf417class p, int dest) {
254
+ int t1 = 0;
255
+ int t2 = 0;
256
+ int t3 = 0;
257
+ int *A;
258
+ int Alength;
259
+ int *E;
260
+ int lastE;
261
+ int k, e, j;
262
+ if (p->param->errorLevel < 0 || p->param->errorLevel > 8)
263
+ p->param->errorLevel = 0;
264
+ A = ERROR_LEVEL[p->param->errorLevel];
265
+ Alength = 2 << p->param->errorLevel;
266
+ E = p->param->codewords + dest;
267
+ memset(E, 0, Alength * sizeof(int));
268
+ lastE = Alength - 1;
269
+ for (k = 0; k < p->param->lenCodewords; ++k) {
270
+ t1 = p->param->codewords[k] + E[0];
271
+ for (e = 0; e <= lastE; ++e) {
272
+ t2 = (t1 * A[lastE - e]) % MOD;
273
+ t3 = MOD - t2;
274
+ E[e] = ((e == lastE ? 0 : E[e + 1]) + t3) % MOD;
275
+ }
276
+ }
277
+ for (j = 0; j < Alength; ++j)
278
+ E[j] = (MOD - E[j]) % MOD;
279
+ }
280
+
281
+ static int getTextTypeAndValue(char* text, int size, int idx) {
282
+ int c;
283
+ char *ms, *ps;
284
+ if (idx >= size)
285
+ return 0;
286
+ c = text[idx];
287
+ if (c >= 'A' && c <= 'Z')
288
+ return (ALPHA + c - 'A');
289
+ if (c >= 'a' && c <= 'z')
290
+ return (LOWER + c - 'a');
291
+ if (c == ' ')
292
+ return (ALPHA + LOWER + MIXED + SPACE);
293
+ ms = strchr(MIXED_SET, c);
294
+ ps = strchr(PUNCTUATION_SET, c);
295
+ if (!ms && !ps)
296
+ return (ISBYTE + (c & 0xff));
297
+ if (ms - MIXED_SET == ps - PUNCTUATION_SET)
298
+ return (MIXED + PUNCTUATION + (ms - MIXED_SET));
299
+ if (ms != NULL)
300
+ return (MIXED + (ms - MIXED_SET));
301
+ return (PUNCTUATION + (ps - PUNCTUATION_SET));
302
+ }
303
+
304
+ static void textCompaction(pPdf417class p, int start, int length) {
305
+ int dest[ABSOLUTE_MAX_TEXT_SIZE * 2];
306
+ char* text = p->param->text;
307
+ int mode = ALPHA;
308
+ int ptr = 0;
309
+ int fullBytes = 0;
310
+ int v = 0;
311
+ int k;
312
+ int size;
313
+ memset(dest, 0, sizeof(dest));
314
+ length += start;
315
+ for (k = start; k < length; ++k) {
316
+ v = getTextTypeAndValue(text, length, k);
317
+ if ((v & mode) != 0) {
318
+ dest[ptr++] = v & 0xff;
319
+ continue;
320
+ }
321
+ if ((v & ISBYTE) != 0) {
322
+ if ((ptr & 1) != 0) {
323
+ dest[ptr++] = (mode & PUNCTUATION) != 0 ? PAL : PS;
324
+ mode = (mode & PUNCTUATION) != 0 ? ALPHA : mode;
325
+ }
326
+ dest[ptr++] = BYTESHIFT;
327
+ dest[ptr++] = v & 0xff;
328
+ fullBytes += 2;
329
+ continue;
330
+ }
331
+ switch (mode) {
332
+ case ALPHA:
333
+ if ((v & LOWER) != 0) {
334
+ dest[ptr++] = LL;
335
+ dest[ptr++] = v & 0xff;
336
+ mode = LOWER;
337
+ }
338
+ else if ((v & MIXED) != 0) {
339
+ dest[ptr++] = ML;
340
+ dest[ptr++] = v & 0xff;
341
+ mode = MIXED;
342
+ }
343
+ else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
344
+ dest[ptr++] = ML;
345
+ dest[ptr++] = PL;
346
+ dest[ptr++] = v & 0xff;
347
+ mode = PUNCTUATION;
348
+ }
349
+ else {
350
+ dest[ptr++] = PS;
351
+ dest[ptr++] = v & 0xff;
352
+ }
353
+ break;
354
+ case LOWER:
355
+ if ((v & ALPHA) != 0) {
356
+ if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & ALPHA) != 0) {
357
+ dest[ptr++] = ML;
358
+ dest[ptr++] = AL;
359
+ mode = ALPHA;
360
+ }
361
+ else {
362
+ dest[ptr++] = AS;
363
+ }
364
+ dest[ptr++] = v & 0xff;
365
+ }
366
+ else if ((v & MIXED) != 0) {
367
+ dest[ptr++] = ML;
368
+ dest[ptr++] = v & 0xff;
369
+ mode = MIXED;
370
+ }
371
+ else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
372
+ dest[ptr++] = ML;
373
+ dest[ptr++] = PL;
374
+ dest[ptr++] = v & 0xff;
375
+ mode = PUNCTUATION;
376
+ }
377
+ else {
378
+ dest[ptr++] = PS;
379
+ dest[ptr++] = v & 0xff;
380
+ }
381
+ break;
382
+ case MIXED:
383
+ if ((v & LOWER) != 0) {
384
+ dest[ptr++] = LL;
385
+ dest[ptr++] = v & 0xff;
386
+ mode = LOWER;
387
+ }
388
+ else if ((v & ALPHA) != 0) {
389
+ dest[ptr++] = AL;
390
+ dest[ptr++] = v & 0xff;
391
+ mode = ALPHA;
392
+ }
393
+ else if ((getTextTypeAndValue(text, length, k + 1) & getTextTypeAndValue(text, length, k + 2) & PUNCTUATION) != 0) {
394
+ dest[ptr++] = PL;
395
+ dest[ptr++] = v & 0xff;
396
+ mode = PUNCTUATION;
397
+ }
398
+ else {
399
+ dest[ptr++] = PS;
400
+ dest[ptr++] = v & 0xff;
401
+ }
402
+ break;
403
+ case PUNCTUATION:
404
+ dest[ptr++] = PAL;
405
+ mode = ALPHA;
406
+ --k;
407
+ break;
408
+ }
409
+ }
410
+ if ((ptr & 1) != 0)
411
+ dest[ptr++] = PS;
412
+ size = (ptr + fullBytes) / 2;
413
+ if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
414
+ p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
415
+ return;
416
+ }
417
+ length = ptr;
418
+ ptr = 0;
419
+ while (ptr < length) {
420
+ v = dest[ptr++];
421
+ if (v >= 30) {
422
+ p->param->codewords[p->cwPtr++] = v;
423
+ p->param->codewords[p->cwPtr++] = dest[ptr++];
424
+ }
425
+ else
426
+ p->param->codewords[p->cwPtr++] = v * 30 + dest[ptr++];
427
+ }
428
+ }
429
+
430
+ static void basicNumberCompaction(pPdf417class p, int start, int length) {
431
+ char* text = p->param->text;
432
+ int* ret = p->param->codewords + p->cwPtr;
433
+ int retLast = length / 3;
434
+ int ni, k;
435
+ p->cwPtr += retLast + 1;
436
+ memset(ret, 0, (retLast + 1) * sizeof(int));
437
+ ret[retLast] = 1;
438
+ length += start;
439
+ for (ni = start; ni < length; ++ni) {
440
+ // multiply by 10
441
+ for (k = retLast; k >= 0; --k)
442
+ ret[k] *= 10;
443
+ // add the digit
444
+ ret[retLast] += text[ni] - '0';
445
+ // propagate carry
446
+ for (k = retLast; k > 0; --k) {
447
+ ret[k - 1] += ret[k] / 900;
448
+ ret[k] %= 900;
449
+ }
450
+ }
451
+ }
452
+
453
+ static void numberCompaction(pPdf417class p, int start, int length) {
454
+ int full = (length / 44) * 15;
455
+ int size = length % 44;
456
+ int k;
457
+ if (size == 0)
458
+ size = full;
459
+ else
460
+ size = full + size / 3 + 1;
461
+ if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
462
+ p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
463
+ return;
464
+ }
465
+ length += start;
466
+ for (k = start; k < length; k += 44) {
467
+ size = length - k < 44 ? length - k : 44;
468
+ basicNumberCompaction(p, k, size);
469
+ }
470
+ }
471
+
472
+ static void byteCompaction6(pPdf417class p, int start) {
473
+ int length = 6;
474
+ char* text = p->param->text;
475
+ int* ret = p->param->codewords + p->cwPtr;
476
+ int retLast = 4;
477
+ int ni, k;
478
+ p->cwPtr += retLast + 1;
479
+ memset(ret, 0, (retLast + 1) * sizeof(int));
480
+ length += start;
481
+ for (ni = start; ni < length; ++ni) {
482
+ // multiply by 256
483
+ for (k = retLast; k >= 0; --k)
484
+ ret[k] *= 256;
485
+ // add the digit
486
+ ret[retLast] += (int)text[ni] & 0xff;
487
+ // propagate carry
488
+ for (k = retLast; k > 0; --k) {
489
+ ret[k - 1] += ret[k] / 900;
490
+ ret[k] %= 900;
491
+ }
492
+ }
493
+ }
494
+
495
+ static void byteCompaction(pPdf417class p, int start, int length) {
496
+ int k, j;
497
+ int size = (length / 6) * 5 + (length % 6);
498
+ if (size + p->cwPtr > MAX_DATA_CODEWORDS) {
499
+ p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
500
+ return;
501
+ }
502
+ length += start;
503
+ for (k = start; k < length; k += 6) {
504
+ size = length - k < 44 ? length - k : 6;
505
+ if (size < 6) {
506
+ for (j = 0; j < size; ++j)
507
+ p->param->codewords[p->cwPtr++] = (int)p->param->text[k + j] & 0xff;
508
+ }
509
+ else {
510
+ byteCompaction6(p, k);
511
+ }
512
+ }
513
+ }
514
+
515
+ static void breakString(pPdf417class p, pArrayList list) {
516
+ char* text = p->param->text;
517
+ int textLength = p->param->lenText;
518
+ int lastP = 0;
519
+ int startN = 0;
520
+ int nd = 0;
521
+ char c = 0;
522
+ int k, ptrS, lastTxt, j, txt;
523
+ pListElement v;
524
+ pListElement vp;
525
+ pListElement vn;
526
+ list->size = 0;
527
+ for (k = 0; k < textLength; ++k) {
528
+ c = text[k];
529
+ if (c >= '0' && c <= '9') {
530
+ if (nd == 0)
531
+ startN = k;
532
+ ++nd;
533
+ continue;
534
+ }
535
+ if (nd >= 13) {
536
+ if (lastP != startN) {
537
+ c = text[lastP];
538
+ ptrS = lastP;
539
+ lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
540
+ for (j = lastP; j < startN; ++j) {
541
+ c = text[j];
542
+ txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
543
+ if (txt != lastTxt) {
544
+ listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
545
+ lastP = j;
546
+ lastTxt = txt;
547
+ }
548
+ }
549
+ listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
550
+ }
551
+ listAdd(list, 'N', startN, k);
552
+ lastP = k;
553
+ }
554
+ nd = 0;
555
+ }
556
+ if (nd < 13)
557
+ startN = textLength;
558
+ if (lastP != startN) {
559
+ c = text[lastP];
560
+ ptrS = lastP;
561
+ lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
562
+ for (j = lastP; j < startN; ++j) {
563
+ c = text[j];
564
+ txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t';
565
+ if (txt != lastTxt) {
566
+ listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
567
+ lastP = j;
568
+ lastTxt = txt;
569
+ }
570
+ }
571
+ listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
572
+ }
573
+ if (nd >= 13)
574
+ listAdd(list, 'N', startN, textLength);
575
+ //optimize
576
+ //merge short binary
577
+ for (k = 0; k < list->size; ++k) {
578
+ v = listGet(list, k);
579
+ vp = listGet(list, k - 1);
580
+ vn = listGet(list, k + 1);;
581
+ if (checkElementType(v, 'B') && getElementLength(v) == 1) {
582
+ if (checkElementType(vp, 'T') && checkElementType(vn, 'T')
583
+ && getElementLength(vp) + getElementLength(vn) >= 3) {
584
+ vp->end = vn->end;
585
+ listRemove(list, k);
586
+ listRemove(list, k);
587
+ k = -1;
588
+ continue;
589
+ }
590
+ }
591
+ }
592
+ //merge text sections
593
+ for (k = 0; k < list->size; ++k) {
594
+ v = listGet(list, k);
595
+ vp = listGet(list, k - 1);
596
+ vn = listGet(list, k + 1);;
597
+ if (checkElementType(v, 'T') && getElementLength(v) >= 5) {
598
+ int redo = 0;
599
+ if ((checkElementType(vp, 'B') && getElementLength(vp) == 1) || checkElementType(vp, 'T')) {
600
+ redo = 1;
601
+ v->start = vp->start;
602
+ listRemove(list, k - 1);
603
+ --k;
604
+ }
605
+ if ((checkElementType(vn, 'B') && getElementLength(vn) == 1) || checkElementType(vn, 'T')) {
606
+ redo = 1;
607
+ v->end = vn->end;
608
+ listRemove(list, k + 1);
609
+ }
610
+ if (redo) {
611
+ k = -1;
612
+ continue;
613
+ }
614
+ }
615
+ }
616
+ //merge binary sections
617
+ for (k = 0; k < list->size; ++k) {
618
+ v = listGet(list, k);
619
+ vp = listGet(list, k - 1);
620
+ vn = listGet(list, k + 1);;
621
+ if (checkElementType(v, 'B')) {
622
+ int redo = 0;
623
+ if ((checkElementType(vp, 'T') && getElementLength(vp) < 5) || checkElementType(vp, 'B')) {
624
+ redo = 1;
625
+ v->start = vp->start;
626
+ listRemove(list, k - 1);
627
+ --k;
628
+ }
629
+ if ((checkElementType(vn, 'T') && getElementLength(vn) < 5) || checkElementType(vn, 'B')) {
630
+ redo = 1;
631
+ v->end = vn->end;
632
+ listRemove(list, k + 1);
633
+ }
634
+ if (redo) {
635
+ k = -1;
636
+ continue;
637
+ }
638
+ }
639
+ }
640
+ // check if all numbers
641
+ if (list->size == 1 && (v = listGet(list, 0))->type == 'T' && getElementLength(v) >= 8) {
642
+ for (k = v->start; k < v->end; ++k) {
643
+ c = text[k];
644
+ if (c < '0' || c > '9')
645
+ break;
646
+ }
647
+ if (k == v->end)
648
+ v->type = 'N';
649
+ }
650
+ }
651
+
652
+ static void assemble(pPdf417class p, pArrayList list) {
653
+ int k;
654
+ if (list->size == 0)
655
+ return;
656
+ p->cwPtr = 1;
657
+ for (k = 0; k < list->size; ++k) {
658
+ pListElement v = listGet(list, k);
659
+ switch (v->type) {
660
+ case 'T':
661
+ if (k != 0)
662
+ p->param->codewords[p->cwPtr++] = TEXT_MODE;
663
+ textCompaction(p, v->start, v->end - v->start);
664
+ break;
665
+ case 'N':
666
+ p->param->codewords[p->cwPtr++] = NUMERIC_MODE;
667
+ numberCompaction(p, v->start, v->end - v->start);
668
+ break;
669
+ case 'B':
670
+ p->param->codewords[p->cwPtr++] = (v->end - v->start) % 6 ? BYTE_MODE : BYTE_MODE_6;
671
+ byteCompaction(p, v->start, v->end - v->start);
672
+ break;
673
+ }
674
+ if (p->param->error)
675
+ return;
676
+ }
677
+ }
678
+
679
+ static int maxPossibleErrorLevel(int remain) {
680
+ int level = 8;
681
+ int size = 512;
682
+ while (level > 0) {
683
+ if (remain >= size)
684
+ return level;
685
+ --level;
686
+ size >>= 1;
687
+ }
688
+ return 0;
689
+ }
690
+
691
+ static void dumpList(pPdf417class p, pArrayList list) {
692
+ int k;
693
+ if (list->size == 0)
694
+ return;
695
+ for (k = 0; k < list->size; ++k) {
696
+ pListElement v = listGet(list, k);
697
+ //printf("%c%.*s\n", v->type, v->end - v->start, p->param->text + v->start);
698
+ }
699
+ }
700
+
701
+ static int getMaxSquare(pPdf417param p) {
702
+ if (p->codeColumns > 21) {
703
+ p->codeColumns = 29;
704
+ p->codeRows = 32;
705
+ }
706
+ else {
707
+ p->codeColumns = 16;
708
+ p->codeRows = 58;
709
+ }
710
+ return MAX_DATA_CODEWORDS + 2;
711
+ }
712
+
713
+ void paintCode(pPdf417param p) {
714
+ pdf417class pp;
715
+ arrayList list;
716
+ int maxErr, fixedColumn, lenErr, tot, skipRowColAdjust, pad;
717
+ pp.param = p;
718
+ p->error = 0;
719
+ if (p->options & PDF417_USE_RAW_CODEWORDS) {
720
+ if (p->lenCodewords > MAX_DATA_CODEWORDS || p->lenCodewords < 1 || p->lenCodewords != p->codewords[0]) {
721
+ p->error = PDF417_ERROR_INVALID_PARAMS;
722
+ return;
723
+ }
724
+ }
725
+ else {
726
+ if (p->lenText < 0)
727
+ p->lenText = strlen(p->text);
728
+ if (p->lenText > ABSOLUTE_MAX_TEXT_SIZE) {
729
+ p->error = PDF417_ERROR_TEXT_TOO_BIG;
730
+ return;
731
+ }
732
+ listInit(&list);
733
+ breakString(&pp, &list);
734
+ dumpList(&pp, &list);
735
+ assemble(&pp, &list);
736
+ listFree(&list);
737
+ if (p->error)
738
+ return;
739
+ p->codewords[0] = p->lenCodewords = pp.cwPtr;
740
+ }
741
+ maxErr = maxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - p->lenCodewords);
742
+ if (!(p->options & PDF417_USE_ERROR_LEVEL)) {
743
+ if (p->lenCodewords < 41)
744
+ p->errorLevel = 2;
745
+ else if (p->lenCodewords < 161)
746
+ p->errorLevel = 3;
747
+ else if (p->lenCodewords < 321)
748
+ p->errorLevel = 4;
749
+ else
750
+ p->errorLevel = 5;
751
+ }
752
+ if (p->errorLevel < 0)
753
+ p->errorLevel = 0;
754
+ else if (p->errorLevel > maxErr)
755
+ p->errorLevel = maxErr;
756
+ if (p->codeColumns < 1)
757
+ p->codeColumns = 1;
758
+ else if (p->codeColumns > 30)
759
+ p->codeColumns = 30;
760
+ if (p->codeRows < 3)
761
+ p->codeRows = 3;
762
+ else if (p->codeRows > 90)
763
+ p->codeRows = 90;
764
+ lenErr = 2 << p->errorLevel;
765
+ fixedColumn = !(p->options & PDF417_FIXED_ROWS);
766
+ skipRowColAdjust = 0;
767
+ tot = p->lenCodewords + lenErr;
768
+ if (p->options & PDF417_FIXED_RECTANGLE) {
769
+ tot = p->codeColumns * p->codeRows;
770
+ if (tot > MAX_DATA_CODEWORDS + 2) {
771
+ tot = getMaxSquare(p);
772
+ }
773
+ if (tot < p->lenCodewords + lenErr)
774
+ tot = p->lenCodewords + lenErr;
775
+ else
776
+ skipRowColAdjust = 1;
777
+ }
778
+ else if (!(p->options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS))) {
779
+ double c, b;
780
+ fixedColumn = 1;
781
+ if (p->aspectRatio < 0.001)
782
+ p->aspectRatio = 0.001f;
783
+ else if (p->aspectRatio > 1000)
784
+ p->aspectRatio = 1000;
785
+ b = 73 * p->aspectRatio - 4;
786
+ c = (-b + sqrt(b * b + 4 * 17 * p->aspectRatio * (p->lenCodewords + lenErr) * p->yHeight)) / (2 * 17 * p->aspectRatio);
787
+ p->codeColumns = (int)(c + 0.5);
788
+ if (p->codeColumns < 1)
789
+ p->codeColumns = 1;
790
+ else if (p->codeColumns > 30)
791
+ p->codeColumns = 30;
792
+ }
793
+ if (!skipRowColAdjust) {
794
+ if (fixedColumn) {
795
+ p->codeRows = (tot - 1) / p->codeColumns + 1;
796
+ if (p->codeRows < 3)
797
+ p->codeRows = 3;
798
+ else if (p->codeRows > 90) {
799
+ p->codeRows = 90;
800
+ p->codeColumns = (tot - 1) / 90 + 1;
801
+ }
802
+ }
803
+ else {
804
+ p->codeColumns = (tot - 1) / p->codeRows + 1;
805
+ if (p->codeColumns > 30) {
806
+ p->codeColumns = 30;
807
+ p->codeRows = (tot - 1) / 30 + 1;
808
+ }
809
+ }
810
+ tot = p->codeRows * p->codeColumns;
811
+ }
812
+ if (tot > MAX_DATA_CODEWORDS + 2) {
813
+ tot = getMaxSquare(p);
814
+ }
815
+ p->errorLevel = maxPossibleErrorLevel(tot - p->lenCodewords);
816
+ lenErr = 2 << p->errorLevel;
817
+ pad = tot - lenErr - p->lenCodewords;
818
+ pp.cwPtr = p->lenCodewords;
819
+ while (pad--)
820
+ p->codewords[pp.cwPtr++] = TEXT_MODE;
821
+ p->codewords[0] = p->lenCodewords = pp.cwPtr;
822
+ calculateErrorCorrection(&pp, pp.param->lenCodewords);
823
+ pp.param->lenCodewords = tot;
824
+ outPaintCode(&pp);
825
+ }
826
+
827
+ #ifdef __cplusplus
828
+ }
829
+ #endif