semacode 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +132 -0
- data/ext/extconf.rb +3 -0
- data/ext/iec16022ecc200.c +939 -0
- data/ext/iec16022ecc200.h +27 -0
- data/ext/reedsol.c +170 -0
- data/ext/reedsol.h +5 -0
- data/ext/semacode.c +359 -0
- data/ext/semacode.h +28 -0
- data/tests/test.rb +91 -0
- metadata +62 -0
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.
|
data/ext/extconf.rb
ADDED
@@ -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
|
+
}
|