semacode 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,132 @@
1
+ = Ruby Semacode Encoder
2
+
3
+ == Introduction
4
+
5
+ This Ruby extension implements a DataMatrix encoder for Ruby. It is typically
6
+ used to create semacodes, which are barcodes, that contain URLs. This encoder
7
+ does not create image files or visual representations of the semacode. This is
8
+ because it can be used for more than creating images, such as rendering
9
+ semacodes to HTML, SVG, PDF or even stored in a database or file for later
10
+ use.
11
+
12
+ See test.rb for an example of how to create a visual symbol for a semacode, it
13
+ presents a semacode in HTML and plain text formats, and this can give you an
14
+ idea of how to start.
15
+
16
+ Once you have a visual representation of the semacode, you can use a reader,
17
+ such as those from http://semacode.org on your camera phone, to capture the
18
+ URL embedded in the semacode and proceed directly to that web site.
19
+
20
+ === License
21
+
22
+ This software is released under the terms of the GNU Public License version 2,
23
+ available from <http://www.gnu.org>
24
+
25
+ === Contact Information
26
+
27
+ You can contact me via <guido@sohne.net> if you have patches, bug fixes or
28
+ improvements.
29
+
30
+ * Based on the iec16022ecc200.c encoder by Adrian Kennard, Andrews & Arnold
31
+ Ltd
32
+ * Copyright (C) 2007, Guido Sohne
33
+
34
+
35
+ == Quick Start
36
+
37
+ 1. Configure the extension to your local system and ruby
38
+
39
+ <tt>ruby extconf.rb</tt>
40
+
41
+ 2. Build the extension
42
+
43
+ <tt>make</tt>
44
+
45
+ 3. Test that it works
46
+
47
+ <tt>ruby test.rb</tt>
48
+
49
+ 4. Install the extension (you may need to become root)
50
+
51
+ <tt>make install</tt>
52
+
53
+ You should take a look at tests/test.rb to understand how to use this. It
54
+ includes some code to generate a semacode using HTML and CSS, so that could
55
+ end up being useful.
56
+
57
+
58
+ == USAGE
59
+
60
+ Here's some basic ways in which you can make use of this extension. It tries
61
+ to show by example, how the semacodes can be created and what can be done with
62
+ or to a semacode object.
63
+
64
+ * include this library
65
+
66
+ <tt>require 'rubygems'</tt>
67
+ <tt>require 'semacode'</tt>
68
+
69
+ * create a semacode
70
+
71
+ <tt>semacode = Barcode::Semacode.new "http://sohne.net/projects/semafox/"</tt>
72
+
73
+ * return the semacode as an array of arrays of boolean
74
+
75
+ The first element of the array is the top row, the last element is the
76
+ bottom row. the array length is the semacode height, and each element is
77
+ an array as wide as the semacode width
78
+
79
+ <tt>grid = semacode.data</tt> or
80
+ <tt>grid = semacode.to_a</tt> or
81
+
82
+ * return the semacode as a string
83
+
84
+ The string is a comma separated list of character vectors. Each vector is a row
85
+ in the semacode symbol, the top row is first, and the bottom row is last. Inside
86
+ each row, the vector reads from left to right.
87
+
88
+ <tt>semacode.to_s</tt> or
89
+ <tt>semacode.to_str</tt>
90
+
91
+ * encode another string
92
+
93
+ <tt>semacode.encode "http://sohne.net"</tt>
94
+
95
+ * get the width
96
+
97
+ <tt>semacode.width</tt>
98
+
99
+ * get the height
100
+
101
+ <tt>semacode.height</tt>
102
+
103
+ * how long is the semacode? (width * height)
104
+
105
+ <tt>semacode.length</tt> or
106
+ <tt>semacode.size</tt>
107
+
108
+ * get the raw encoded length (before padding and before ecc)
109
+
110
+ <tt>semacode.raw_encoded_length</tt>
111
+
112
+ * get the symbol size
113
+
114
+ The max number of characters this semacode type
115
+ (specific width x height) can hold is called the
116
+ symbol size
117
+
118
+ <tt>semacode.symbol_size</tt>
119
+
120
+ * count the ECC bytes
121
+
122
+ How many bytes were used for error correction?
123
+
124
+ <tt>semacode.ecc_bytes</tt>
125
+
126
+
127
+ == NOTES
128
+
129
+ The C code can throw runtime exceptions. Be sure to include
130
+ a catch block if you want to use this in production. Mostly
131
+ the exceptions are not recoverable, except for when the data
132
+ is too long, in which case you can shorten it and try again.
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ dir_config("semacode")
3
+ create_makefile('semacode')
@@ -0,0 +1,939 @@
1
+ // IEC16022 bar code generation library
2
+ // Adrian Kennard, Andrews & Arnold Ltd
3
+ // with help from Cliff Hones on the RS coding
4
+ //
5
+ // Revision 1.8 2004/09/12 10:35:25 cvs
6
+ // Minor fixes to auto encoding, and more precise placement of text on stamp output.
7
+ //
8
+ // Revision 1.7 2004/09/11 11:16:20 cvs
9
+ // Fixed binary format encoding, and added output file to indicia
10
+ //
11
+ // Revision 1.6 2004/09/10 16:10:30 cvs
12
+ // Correction of declaration ordering
13
+ //
14
+ // Revision 1.5 2004/09/09 12:35:48 cvs
15
+ // Interleaved (large) codes now working as well.
16
+ // Fixed bugs in the auto encoding (was selecting EDIFACT wrongly)
17
+ //
18
+ // Revision 1.4 2004/09/09 07:45:09 cvs
19
+ // Added change history to source files
20
+ // Added "info" type to IEC16022
21
+ // Added exact size checking shortcodes on encoding generation for iec16022
22
+ //
23
+
24
+
25
+ #include <stdio.h>
26
+ #include <ctype.h>
27
+ #include <string.h>
28
+ #include <time.h>
29
+ #include <malloc.h>
30
+ #include "ruby.h"
31
+ #include "reedsol.h"
32
+ #include "iec16022ecc200.h"
33
+
34
+ static struct ecc200matrix_s
35
+ {
36
+ int H,
37
+ W;
38
+ int FH,
39
+ FW;
40
+ int bytes;
41
+ int datablock,
42
+ rsblock;
43
+ }
44
+ ecc200matrix[] =
45
+ {
46
+ 10, 10, 10, 10, 3, 3, 5, //
47
+ 12, 12, 12, 12, 5, 5, 7, //
48
+ 14, 14, 14, 14, 8, 8, 10, //
49
+ 16, 16, 16, 16, 12, 12, 12, //
50
+ 12, 26, 12, 26, 16, 16, 14, //
51
+ 18, 18, 18, 18, 18, 18, 14, //
52
+ 20, 20, 20, 20, 22, 22, 18, //
53
+ 22, 22, 22, 22, 30, 30, 20, //
54
+ 24, 24, 24, 24, 36, 36, 24, //
55
+ 26, 26, 26, 26, 44, 44, 28, //
56
+ 32, 32, 16, 16, 62, 62, 36, //
57
+ 36, 36, 18, 18, 86, 86, 42, //
58
+ 40, 40, 20, 20, 114, 114, 48, //
59
+ 44, 44, 22, 22, 144, 144, 56, //
60
+ 48, 48, 24, 24, 174, 174, 68, //
61
+ 52, 52, 26, 26, 204, 102, 42, //
62
+ 64, 64, 16, 16, 280, 140, 56, //
63
+ 72, 72, 18, 18, 368, 92, 36, //
64
+ 80, 80, 20, 20, 456, 114, 48, //
65
+ 88, 88, 22, 22, 576, 144, 56, //
66
+ 96, 96, 24, 24, 696, 174, 68, //
67
+ 104, 104, 26, 26, 816, 136, 56, //
68
+ 120, 120, 20, 20, 1050, 175, 68, //
69
+ 132, 132, 22, 22, 1304, 163, 62, //
70
+ 144, 144, 24, 24, 1558, 156, 62, // 156*4+155*2
71
+ 0 // terminate
72
+ };
73
+
74
+ // simple checked response malloc
75
+ static void *
76
+ safemalloc (int n)
77
+ {
78
+ void *p = (void *) malloc((size_t) n);
79
+ if (!p)
80
+ {
81
+ rb_raise(rb_eRuntimeError, "malloc failed", n);
82
+ exit (1);
83
+ }
84
+ return p;
85
+ }
86
+
87
+ // Annex M placement alorithm low level
88
+ static void
89
+ ecc200placementbit (int *array, int NR, int NC, int r, int c, int p, char b)
90
+ {
91
+ if (r < 0)
92
+ {
93
+ r += NR;
94
+ c += 4 - ((NR + 4) % 8);
95
+ }
96
+ if (c < 0)
97
+ {
98
+ c += NC;
99
+ r += 4 - ((NC + 4) % 8);
100
+ }
101
+ array[r * NC + c] = (p << 3) + b;
102
+ }
103
+
104
+ static void
105
+ ecc200placementblock (int *array, int NR, int NC, int r, int c, int p)
106
+ {
107
+ ecc200placementbit (array, NR, NC, r - 2, c - 2, p, 7);
108
+ ecc200placementbit (array, NR, NC, r - 2, c - 1, p, 6);
109
+ ecc200placementbit (array, NR, NC, r - 1, c - 2, p, 5);
110
+ ecc200placementbit (array, NR, NC, r - 1, c - 1, p, 4);
111
+ ecc200placementbit (array, NR, NC, r - 1, c - 0, p, 3);
112
+ ecc200placementbit (array, NR, NC, r - 0, c - 2, p, 2);
113
+ ecc200placementbit (array, NR, NC, r - 0, c - 1, p, 1);
114
+ ecc200placementbit (array, NR, NC, r - 0, c - 0, p, 0);
115
+ }
116
+
117
+ static void
118
+ ecc200placementcornerA (int *array, int NR, int NC, int p)
119
+ {
120
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
121
+ ecc200placementbit (array, NR, NC, NR - 1, 1, p, 6);
122
+ ecc200placementbit (array, NR, NC, NR - 1, 2, p, 5);
123
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
124
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
125
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
126
+ ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
127
+ ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
128
+ }
129
+
130
+ static void
131
+ ecc200placementcornerB (int *array, int NR, int NC, int p)
132
+ {
133
+ ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
134
+ ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
135
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
136
+ ecc200placementbit (array, NR, NC, 0, NC - 4, p, 4);
137
+ ecc200placementbit (array, NR, NC, 0, NC - 3, p, 3);
138
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 2);
139
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 1);
140
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
141
+ }
142
+
143
+ static void
144
+ ecc200placementcornerC (int *array, int NR, int NC, int p)
145
+ {
146
+ ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
147
+ ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
148
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
149
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
150
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
151
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
152
+ ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
153
+ ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
154
+ }
155
+
156
+ static void
157
+ ecc200placementcornerD (int *array, int NR, int NC, int p)
158
+ {
159
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
160
+ ecc200placementbit (array, NR, NC, NR - 1, NC - 1, p, 6);
161
+ ecc200placementbit (array, NR, NC, 0, NC - 3, p, 5);
162
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
163
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
164
+ ecc200placementbit (array, NR, NC, 1, NC - 3, p, 2);
165
+ ecc200placementbit (array, NR, NC, 1, NC - 2, p, 1);
166
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
167
+ }
168
+
169
+ // Annex M placement alorithm main function
170
+ static void
171
+ ecc200placement (int *array, int NR, int NC)
172
+ {
173
+ int r,
174
+ c,
175
+ p;
176
+ // invalidate
177
+ for (r = 0; r < NR; r++)
178
+ for (c = 0; c < NC; c++)
179
+ array[r * NC + c] = 0;
180
+ // start
181
+ p = 1;
182
+ r = 4;
183
+ c = 0;
184
+ do
185
+ {
186
+ // check corner
187
+ if (r == NR && !c)
188
+ ecc200placementcornerA (array, NR, NC, p++);
189
+ if (r == NR - 2 && !c && NC % 4)
190
+ ecc200placementcornerB (array, NR, NC, p++);
191
+ if (r == NR - 2 && !c && (NC % 8) == 4)
192
+ ecc200placementcornerC (array, NR, NC, p++);
193
+ if (r == NR + 4 && c == 2 && !(NC % 8))
194
+ ecc200placementcornerD (array, NR, NC, p++);
195
+ // up/right
196
+ do
197
+ {
198
+ if (r < NR && c >= 0 && !array[r * NC + c])
199
+ ecc200placementblock (array, NR, NC, r, c, p++);
200
+ r -= 2;
201
+ c += 2;
202
+ }
203
+ while (r >= 0 && c < NC);
204
+ r++;
205
+ c += 3;
206
+ // down/left
207
+ do
208
+ {
209
+ if (r >= 0 && c < NC && !array[r * NC + c])
210
+ ecc200placementblock (array, NR, NC, r, c, p++);
211
+ r += 2;
212
+ c -= 2;
213
+ }
214
+ while (r < NR && c >= 0);
215
+ r += 3;
216
+ c++;
217
+ }
218
+ while (r < NR || c < NC);
219
+ // unfilled corner
220
+ if (!array[NR * NC - 1])
221
+ array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
222
+ }
223
+
224
+ // calculate and append ecc code, and if necessary interleave
225
+ static void
226
+ ecc200 (unsigned char *binary, int bytes, int datablock, int rsblock)
227
+ {
228
+ int blocks = (bytes + 2) / datablock,
229
+ b;
230
+ rs_init_gf (0x12d);
231
+ rs_init_code (rsblock, 1);
232
+ for (b = 0; b < blocks; b++)
233
+ {
234
+ unsigned char buf[256],
235
+ ecc[256];
236
+ int n,
237
+ p = 0;
238
+ for (n = b; n < bytes; n += blocks)
239
+ buf[p++] = binary[n];
240
+ rs_encode (p, buf, ecc);
241
+ p = rsblock - 1; // comes back reversed
242
+ for (n = b; n < rsblock * blocks; n += blocks)
243
+ binary[bytes + n] = ecc[p--];
244
+ }
245
+ }
246
+
247
+ // perform encoding for ecc200, source s len sl, to target t len tl, using optional encoding control string e
248
+ // return 1 if OK, 0 if failed. Does all necessary padding to tl
249
+ char
250
+ ecc200encode (unsigned char *t, int tl, unsigned char *s, int sl, char *encoding, int *lenp)
251
+ {
252
+ char enc = 'a'; // start in ASCII encoding mode
253
+ int tp = 0,
254
+ sp = 0;
255
+ if (strlen (encoding) < sl)
256
+ {
257
+ rb_raise(rb_eRuntimeError, "encoding string too short");
258
+ return 0;
259
+ }
260
+ // do the encoding
261
+ while (sp < sl && tp < tl)
262
+ {
263
+ char newenc = enc; // suggest new encoding
264
+ if (tl - tp <= 1 && (enc == 'c' || enc == 't') || tl - tp <= 2 && enc == 'x')
265
+ enc = 'a'; // auto revert to ASCII
266
+ newenc = tolower (encoding[sp]);
267
+ switch (newenc)
268
+ { // encode character
269
+ case 'c': // C40
270
+ case 't': // Text
271
+ case 'x': // X12
272
+ {
273
+ char out[6],
274
+ p = 0;
275
+ const char *e,
276
+ *s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_",
277
+ *s3 = 0;
278
+ if (newenc == 'c')
279
+ {
280
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
281
+ s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
282
+ }
283
+ if (newenc == 't')
284
+ {
285
+ e = " 0123456789abcdefghijklmnopqrstuvwxyz";
286
+ s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
287
+ }
288
+ if (newenc == 'x')
289
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
290
+ do
291
+ {
292
+ unsigned char c = s[sp++];
293
+ char *w;
294
+ if (c & 0x80)
295
+ {
296
+ if (newenc == 'x')
297
+ {
298
+ rb_raise(rb_eRuntimeError, "cannot encode character in X12", c);
299
+ return 0;
300
+ }
301
+ c &= 0x7f;
302
+ out[p++] = 1;
303
+ out[p++] = 30;
304
+ }
305
+ w = strchr (e, c);
306
+ if (w)
307
+ out[p++] = ((w - e) + 3) % 40;
308
+ else
309
+ {
310
+ if (newenc == 'x')
311
+ {
312
+ rb_raise(rb_eRuntimeError, "cannot encode character in X12", c);
313
+ return 0;
314
+ }
315
+ if (c < 32)
316
+ { // shift 1
317
+ out[p++] = 0;
318
+ out[p++] = c;
319
+ } else
320
+ {
321
+ w = strchr (s2, c);
322
+ if (w)
323
+ { // shift 2
324
+ out[p++] = 1;
325
+ out[p++] = (w - s2);
326
+ } else
327
+ {
328
+ w = strchr (s3, c);
329
+ if (w)
330
+ {
331
+ out[p++] = 2;
332
+ out[p++] = (w - s3);
333
+ } else
334
+ {
335
+ rb_raise(rb_eRuntimeError, "this should not be happening!", c);
336
+ return 0;
337
+ }
338
+ }
339
+ }
340
+ }
341
+ if (p == 2 && tp + 2 == tl && sp == sl)
342
+ out[p++] = 0; // shift 1 pad at end
343
+ while (p >= 3)
344
+ {
345
+ int v = out[0] * 1600 + out[1] * 40 + out[2] + 1;
346
+ if (enc != newenc)
347
+ {
348
+ if (enc == 'c' || enc == 't' || enc == 'x')
349
+ t[tp++] = 254; // escape C40/text/X12
350
+ else if (enc == 'x')
351
+ t[tp++] = 0x7C; // escape EDIFACT
352
+ if (newenc == 'c')
353
+ t[tp++] = 230;
354
+ if (newenc == 't')
355
+ t[tp++] = 239;
356
+ if (newenc == 'x')
357
+ t[tp++] = 238;
358
+ enc = newenc;
359
+ }
360
+ t[tp++] = (v >> 8);
361
+ t[tp++] = (v & 0xFF);
362
+ p -= 3;
363
+ out[0] = out[3];
364
+ out[1] = out[4];
365
+ out[2] = out[5];
366
+ }
367
+ }
368
+ while (p && sp < sl);
369
+ }
370
+ break;
371
+ case 'e': // EDIFACT
372
+ {
373
+ unsigned char out[4],
374
+ p = 0;
375
+ if (enc != newenc)
376
+ { // can only be from C40/Text/X12
377
+ t[tp++] = 254;
378
+ enc = 'a';
379
+ }
380
+ while (sp < sl && tolower (encoding[sp]) == 'e' && p < 4)
381
+ out[p++] = s[sp++];
382
+ if (p < 4)
383
+ {
384
+ out[p++] = 0x1F;
385
+ enc = 'a';
386
+ } // termination
387
+ t[tp] = ((s[0] & 0x3F) << 2);
388
+ t[tp++] |= ((s[1] & 0x30) >> 4);
389
+ t[tp] = ((s[1] & 0x0F) << 4);
390
+ if (p == 2)
391
+ tp++;
392
+ else
393
+ {
394
+ t[tp++] |= ((s[2] & 0x3C) >> 2);
395
+ t[tp] = ((s[2] & 0x03) << 6);
396
+ t[tp++] |= (s[3] & 0x3F);
397
+ }
398
+ }
399
+ break;
400
+ case 'a': // ASCII
401
+ if (enc != newenc)
402
+ {
403
+ if (enc == 'c' || enc == 't' || enc == 'x')
404
+ t[tp++] = 254; // escape C40/text/X12
405
+ else
406
+ t[tp++] = 0x7C; // escape EDIFACT
407
+ }
408
+ enc = 'a';
409
+ if (sl - sp >= 2 && isdigit (s[sp]) && isdigit (s[sp + 1]))
410
+ {
411
+ t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
412
+ sp += 2;
413
+ } else if (s[sp] > 127)
414
+ {
415
+ t[tp++] = 235;
416
+ t[tp++] = s[sp++] - 127;
417
+ } else
418
+ t[tp++] = s[sp++] + 1;
419
+ break;
420
+ case 'b': // Binary
421
+ {
422
+ int l = 0; // how much to encode
423
+ if (encoding)
424
+ {
425
+ int p;
426
+ for (p = sp; p < sl && tolower (encoding[p]) == 'b'; p++)
427
+ l++;
428
+ }
429
+ t[tp++] = 231; // base256
430
+ if (l < 250)
431
+ t[tp++] = l;
432
+ else
433
+ {
434
+ t[tp++] = 249 + (l / 250);
435
+ t[tp++] = (l % 250);
436
+ }
437
+ while (l-- && tp < tl)
438
+ {
439
+ t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1; // see annex H
440
+ tp++;
441
+ }
442
+ enc = 'a'; // reverse to ASCII at end
443
+ }
444
+ break;
445
+ default:
446
+ rb_raise(rb_eRuntimeError, "unknown encoding attempted");
447
+ return 0; // failed
448
+ }
449
+ }
450
+ if (lenp)
451
+ *lenp = tp;
452
+ if (tp < tl && enc != 'a')
453
+ {
454
+ if (enc == 'c' || enc == 'x' || enc == 't')
455
+ t[tp++] = 254; // escape X12/C40/Text
456
+ else
457
+ t[tp++] = 0x7C; // escape EDIFACT
458
+ }
459
+ if (tp < tl)
460
+ t[tp++] = 129; // pad
461
+ while (tp < tl)
462
+ { // more padding
463
+ int v = 129 + (((tp + 1) * 149) % 253) + 1; // see Annex H
464
+ if (v > 254)
465
+ v -= 254;
466
+ t[tp++] = v;
467
+ }
468
+ if (tp > tl || sp < sl)
469
+ return 0; // did not fit
470
+ //for (tp = 0; tp < tl; tp++) rb_raise(rb_eRuntimeError, "%02X ", t[tp]); rb_raise(rb_eRuntimeError, "\n");
471
+ return 1; // OK
472
+ }
473
+
474
+ // Auto encoding format functions
475
+ static char encchr[] = "ACTXEB";
476
+
477
+ enum
478
+ {
479
+ E_ASCII,
480
+ E_C40,
481
+ E_TEXT,
482
+ E_X12,
483
+ E_EDIFACT,
484
+ E_BINARY,
485
+ E_MAX
486
+ };
487
+
488
+ unsigned char switchcost[E_MAX][E_MAX] = {
489
+ 0, 1, 1, 1, 1, 2, // From E_ASCII
490
+ 1, 0, 2, 2, 2, 3, // From E_C40
491
+ 1, 2, 0, 2, 2, 3, // From E_TEXT
492
+ 1, 2, 2, 0, 2, 3, // From E_X12
493
+ 1, 2, 2, 2, 0, 3, // From E_EDIFACT
494
+ 0, 1, 1, 1, 1, 0, // From E_BINARY
495
+ };
496
+
497
+ // Creates a encoding list (malloc)
498
+ // returns encoding string
499
+ // if lenp not null, target len stored
500
+ // if error, null returned
501
+ // if exact specified, then assumes shortcuts applicable for exact fit in target
502
+ // 1. No unlatch to return to ASCII for last encoded byte after C40 or Text or X12
503
+ // 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after EDIFACT
504
+ // 3. Final C40 or text encoding exactly in last 2 bytes can have a shift 0 to pad to make a tripple
505
+ // Only use the encoding from an exact request if the len matches the target, otherwise free the result and try again with exact=0
506
+ static char *
507
+ encmake (int l, unsigned char *s, int *lenp, char exact)
508
+ {
509
+ char *encoding = 0;
510
+ int p = l;
511
+ char e;
512
+ struct
513
+ {
514
+ short s; // number of bytes of source that can be encoded in a row at this point using this encoding mode
515
+ short t; // number of bytes of target generated encoding from this point to end if already in this encoding mode
516
+ } enc[MAXBARCODE][E_MAX];
517
+ memset (&enc, 0, sizeof (enc));
518
+ if (!l)
519
+ return ""; // no length
520
+ if (l > MAXBARCODE)
521
+ return 0; // not valid
522
+ while (p--)
523
+ {
524
+ char b = 0,
525
+ sub;
526
+ int sl,
527
+ tl,
528
+ bl,
529
+ t;
530
+ // consider each encoding from this point
531
+ // ASCII
532
+ sl = tl = 1;
533
+ if (isdigit (s[p]) && p + 1 < l && isdigit (s[p + 1]))
534
+ sl = 2; // double digit
535
+ else if (s[p] & 0x80)
536
+ tl = 2; // high shifted
537
+ bl = 0;
538
+ if (p + sl < l)
539
+ for (e = 0; e < E_MAX; e++)
540
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_ASCII][e]) < bl || !bl))
541
+ {
542
+ bl = t;
543
+ b = e;
544
+ }
545
+ enc[p][E_ASCII].t = tl + bl;
546
+ enc[p][E_ASCII].s = sl;
547
+ if (bl && b == E_ASCII)
548
+ enc[p][b].s += enc[p + sl][b].s;
549
+ // C40
550
+ sub = tl = sl = 0;
551
+ do
552
+ {
553
+ unsigned char c = s[p + sl++];
554
+ if (c & 0x80)
555
+ { // shift + upper
556
+ sub += 2;
557
+ c &= 0x7F;
558
+ }
559
+ if (c != ' ' && !isdigit (c) && !isupper (c))
560
+ sub++; // shift
561
+ sub++;
562
+ while (sub >= 3)
563
+ {
564
+ sub -= 3;
565
+ tl += 2;
566
+ }
567
+ } while (sub && p + sl < l);
568
+ if (exact && sub == 2 && p + sl == l)
569
+ { // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
570
+ sub = 0;
571
+ tl += 2;
572
+ }
573
+ if (!sub)
574
+ { // can encode C40
575
+ bl = 0;
576
+ if (p + sl < l)
577
+ for (e = 0; e < E_MAX; e++)
578
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_C40][e]) < bl || !bl))
579
+ {
580
+ bl = t;
581
+ b = e;
582
+ }
583
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
584
+ { // special case, switch to ASCII for last bytes
585
+ bl = 1;
586
+ b = E_ASCII;
587
+ }
588
+ enc[p][E_C40].t = tl + bl;
589
+ enc[p][E_C40].s = sl;
590
+ if (bl && b == E_C40)
591
+ enc[p][b].s += enc[p + sl][b].s;
592
+ }
593
+ // Text
594
+ sub = tl = sl = 0;
595
+ do
596
+ {
597
+ unsigned char c = s[p + sl++];
598
+ if (c & 0x80)
599
+ { // shift + upper
600
+ sub += 2;
601
+ c &= 0x7F;
602
+ }
603
+ if (c != ' ' && !isdigit (c) && !islower (c))
604
+ sub++; // shift
605
+ sub++;
606
+ while (sub >= 3)
607
+ {
608
+ sub -= 3;
609
+ tl += 2;
610
+ }
611
+ } while (sub && p + sl < l);
612
+ if (exact && sub == 2 && p + sl == l)
613
+ { // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
614
+ sub = 0;
615
+ tl += 2;
616
+ }
617
+ if (!sub && sl)
618
+ { // can encode Text
619
+ bl = 0;
620
+ if (p + sl < l)
621
+ for (e = 0; e < E_MAX; e++)
622
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_TEXT][e]) < bl || !bl))
623
+ {
624
+ bl = t;
625
+ b = e;
626
+ }
627
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
628
+ { // special case, switch to ASCII for last bytes
629
+ bl = 1;
630
+ b = E_ASCII;
631
+ }
632
+ enc[p][E_TEXT].t = tl + bl;
633
+ enc[p][E_TEXT].s = sl;
634
+ if (bl && b == E_TEXT)
635
+ enc[p][b].s += enc[p + sl][b].s;
636
+ }
637
+ // X12
638
+ sub = tl = sl = 0;
639
+ do
640
+ {
641
+ unsigned char c = s[p + sl++];
642
+ if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit (c) && !isupper (c))
643
+ {
644
+ sl = 0;
645
+ break;
646
+ }
647
+ sub++;
648
+ while (sub >= 3)
649
+ {
650
+ sub -= 3;
651
+ tl += 2;
652
+ }
653
+ } while (sub && p + sl < l);
654
+ if (!sub && sl)
655
+ { // can encode X12
656
+ bl = 0;
657
+ if (p + sl < l)
658
+ for (e = 0; e < E_MAX; e++)
659
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_X12][e]) < bl || !bl))
660
+ {
661
+ bl = t;
662
+ b = e;
663
+ }
664
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
665
+ { // special case, switch to ASCII for last bytes
666
+ bl = 1;
667
+ b = E_ASCII;
668
+ }
669
+ enc[p][E_X12].t = tl + bl;
670
+ enc[p][E_X12].s = sl;
671
+ if (bl && b == E_X12)
672
+ enc[p][b].s += enc[p + sl][b].s;
673
+ }
674
+ // EDIFACT
675
+ sl = bl = 0;
676
+ if (s[p + 0] >= 32 && s[p + 0] <= 94)
677
+ { // can encode 1
678
+ char bs = 0;
679
+ if (p + 1 == l && (!bl || bl < 2))
680
+ {
681
+ bl = 2;
682
+ bs = 1;
683
+ } else
684
+ for (e = 0; e < E_MAX; e++)
685
+ if (e != E_EDIFACT && enc[p + 1][e].t && ((t = 2 + enc[p + 1][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
686
+ {
687
+ bs = 1;
688
+ bl = t;
689
+ b = e;
690
+ }
691
+ if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94)
692
+ { // can encode 2
693
+ if (p + 2 == l && (!bl || bl < 2))
694
+ {
695
+ bl = 3;
696
+ bs = 2;
697
+ } else
698
+ for (e = 0; e < E_MAX; e++)
699
+ if (e != E_EDIFACT && enc[p + 2][e].t && ((t = 3 + enc[p + 2][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
700
+ {
701
+ bs = 2;
702
+ bl = t;
703
+ b = e;
704
+ }
705
+ if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94)
706
+ { // can encode 3
707
+ if (p + 3 == l && (!bl || bl < 3))
708
+ {
709
+ bl = 3;
710
+ bs = 3;
711
+ } else
712
+ for (e = 0; e < E_MAX; e++)
713
+ if (e != E_EDIFACT && enc[p + 3][e].t && ((t = 3 + enc[p + 3][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
714
+ {
715
+ bs = 3;
716
+ bl = t;
717
+ b = e;
718
+ }
719
+ if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94)
720
+ { // can encode 4
721
+ if (p + 4 == l && (!bl || bl < 3))
722
+ {
723
+ bl = 3;
724
+ bs = 4;
725
+ } else
726
+ {
727
+ for (e = 0; e < E_MAX; e++)
728
+ if (enc[p + 4][e].t && ((t = 3 + enc[p + 4][e].t + switchcost[E_EDIFACT][e]) < bl || !bl))
729
+ {
730
+ bs = 4;
731
+ bl = t;
732
+ b = e;
733
+ }
734
+ if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl)
735
+ { // special case, switch to ASCII for last 1 ot two bytes
736
+ bs = 4;
737
+ bl = t;
738
+ b = E_ASCII;
739
+ }
740
+ }
741
+ }
742
+ }
743
+ }
744
+ enc[p][E_EDIFACT].t = bl;
745
+ enc[p][E_EDIFACT].s = bs;
746
+ if (bl && b == E_EDIFACT)
747
+ enc[p][b].s += enc[p + bs][b].s;
748
+ }
749
+ // Binary
750
+ bl = 0;
751
+ for (e = 0; e < E_MAX; e++)
752
+ if (enc[p + 1][e].t
753
+ && ((t = enc[p + 1][e].t + switchcost[E_BINARY][e] + ((e == E_BINARY && enc[p + 1][e].t == 249) ? 1 : 0)) < bl || !bl))
754
+ {
755
+ bl = t;
756
+ b = e;
757
+ }
758
+ enc[p][E_BINARY].t = 1 + bl;
759
+ enc[p][E_BINARY].s = 1;
760
+ if (bl && b == E_BINARY)
761
+ enc[p][b].s += enc[p + 1][b].s;
762
+ //rb_raise(rb_eRuntimeError, "%d:", p); for (e = 0; e < E_MAX; e++) rb_raise(rb_eRuntimeError, " %c*%d/%d", encchr[e], enc[p][e].s, enc[p][e].t); rb_raise(rb_eRuntimeError, "\n");
763
+ }
764
+ encoding = safemalloc (l + 1);
765
+ p = 0;
766
+ {
767
+ char cur = E_ASCII; // starts ASCII
768
+ while (p < l)
769
+ {
770
+ int t,
771
+ m = 0;
772
+ char b = 0;
773
+ for (e = 0; e < E_MAX; e++)
774
+ if (enc[p][e].t && ((t = enc[p][e].t + switchcost[cur][e]) < m || t == m && e == cur || !m))
775
+ {
776
+ b = e;
777
+ m = t;
778
+ }
779
+ cur = b;
780
+ m = enc[p][b].s;
781
+ if (!p && lenp)
782
+ *lenp = enc[p][b].t;
783
+ while (p < l && m--)
784
+ encoding[p++] = encchr[b];
785
+ }
786
+ }
787
+ encoding[p] = 0;
788
+ return encoding;
789
+ }
790
+
791
+ void iec16022init(int *Wptr, int *Hptr, const char *barcode)
792
+ {
793
+ if(Wptr == NULL || Hptr == NULL || barcode == NULL) return;
794
+
795
+ int barcodelen = strlen(barcode) + 1;
796
+ struct ecc200matrix_s *matrix;
797
+ for (matrix = ecc200matrix; matrix->bytes < barcodelen; matrix++);
798
+ *Wptr = matrix->W;
799
+ *Hptr = matrix->H;
800
+ }
801
+
802
+ // Main encoding function
803
+ // Returns the grid (malloced) containing the matrix. L corner at 0,0.
804
+ // Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
805
+ // Takes barcodelen and barcode to be encoded
806
+ // Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
807
+ // If lenp not null, then the length of encoded data before any final unlatch or pad is stored
808
+ // If maxp not null, then the max storage of this size code is stored
809
+ // If eccp not null, then the number of ecc bytes used in this size is stored
810
+ // Returns 0 on error (writes to stderr with details).
811
+ unsigned char *
812
+ iec16022ecc200 (int *Wptr, int *Hptr, char **encodingptr, int barcodelen, unsigned char *barcode, int *lenp, int *maxp, int *eccp)
813
+ {
814
+ unsigned char binary[3000]; // encoded raw data and ecc to place in barcode
815
+ int W = 0,
816
+ H = 0;
817
+ char *encoding = 0;
818
+ unsigned char *grid = 0;
819
+ struct ecc200matrix_s *matrix;
820
+ memset (binary, 0, sizeof (binary));
821
+ if (encodingptr)
822
+ encoding = *encodingptr;
823
+ if (Wptr)
824
+ W = *Wptr;
825
+ if (Hptr)
826
+ H = *Hptr;
827
+
828
+ // encoding
829
+ if (W)
830
+ { // known size
831
+ for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++);
832
+ if (!matrix->W)
833
+ {
834
+ rb_raise(rb_eRuntimeError, "invalid size for barcode");
835
+ return 0;
836
+ }
837
+ if (!encoding)
838
+ {
839
+ int len;
840
+ char *e = encmake (barcodelen, barcode, &len, 1);
841
+ if (e && len != matrix->bytes)
842
+ { // try not an exact fit
843
+ free (e);
844
+ e = encmake (barcodelen, barcode, &len, 0);
845
+ if (len > matrix->bytes)
846
+ {
847
+ rb_raise(rb_eRuntimeError, "cannot make barcode fit");
848
+ return 0;
849
+ }
850
+ }
851
+ encoding = e;
852
+ }
853
+ } else
854
+ { // find size
855
+ if (encoding)
856
+ { // find one that fits chosen encoding
857
+ for (matrix = ecc200matrix; matrix->W; matrix++)
858
+ if (ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, 0))
859
+ break;
860
+ } else
861
+ {
862
+ int len;
863
+ char *e;
864
+ e = encmake (barcodelen, barcode, &len, 1);
865
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes != len; matrix++);
866
+ if (e && !matrix->W)
867
+ { // try for non exact fit
868
+ free (e);
869
+ e = encmake (barcodelen, barcode, &len, 0);
870
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++);
871
+ }
872
+ encoding = e;
873
+ }
874
+ if (!matrix->W)
875
+ {
876
+ rb_raise(rb_eRuntimeError, "barcode too long");
877
+ return 0;
878
+ }
879
+ W = matrix->W;
880
+ H = matrix->H;
881
+ }
882
+ if (!ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, lenp))
883
+ {
884
+ rb_raise(rb_eRuntimeError, "barcode too long for expected encoding");
885
+ return 0;
886
+ }
887
+ // ecc code
888
+ ecc200 (binary, matrix->bytes, matrix->datablock, matrix->rsblock);
889
+ { // placement
890
+ int x,
891
+ y,
892
+ NC,
893
+ NR,
894
+ *places;
895
+ NC = W - 2 * (W / matrix->FW);
896
+ NR = H - 2 * (H / matrix->FH);
897
+ places = safemalloc (NC * NR * sizeof (int));
898
+ ecc200placement (places, NR, NC);
899
+ grid = safemalloc (W * H);
900
+ memset (grid, 0, W * H);
901
+ for (y = 0; y < H; y += matrix->FH)
902
+ {
903
+ for (x = 0; x < W; x++)
904
+ grid[y * W + x] = 1;
905
+ for (x = 0; x < W; x += 2)
906
+ grid[(y + matrix->FH - 1) * W + x] = 1;
907
+ }
908
+ for (x = 0; x < W; x += matrix->FW)
909
+ {
910
+ for (y = 0; y < H; y++)
911
+ grid[y * W + x] = 1;
912
+ for (y = 0; y < H; y += 2)
913
+ grid[y * W + x + matrix->FW - 1] = 1;
914
+ }
915
+ for (y = 0; y < NR; y++)
916
+ {
917
+ for (x = 0; x < NC; x++)
918
+ {
919
+ int v = places[(NR - y - 1) * NC + x];
920
+ //rb_raise(rb_eRuntimeError, "%4d", v);
921
+ if (v == 1 || v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))
922
+ grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
923
+ }
924
+ //rb_raise(rb_eRuntimeError, "\n");
925
+ }
926
+ free (places);
927
+ }
928
+ if (Wptr)
929
+ *Wptr = W;
930
+ if (Hptr)
931
+ *Hptr = H;
932
+ if (encodingptr)
933
+ *encodingptr = encoding;
934
+ if (maxp)
935
+ *maxp = matrix->bytes;
936
+ if (eccp)
937
+ *eccp = (matrix->bytes + 2) / matrix->datablock * matrix->rsblock;
938
+ return grid;
939
+ }