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 +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
|
+
}
|