semacode 0.7.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/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
+ }