semacode-ruby19 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
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.3 2004/09/09 07:45:09 cvs
6
+ // Added change history to source files
7
+ // Added "info" type to IEC16022
8
+ // Added exact size checking shortcodes on encoding generation for iec16022
9
+ //
10
+
11
+ // Main encoding function
12
+ // Returns the grid (malloced) containing the matrix. L corner at 0,0.
13
+ // Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
14
+ // Takes barcodelen and barcode to be encoded
15
+ // Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
16
+ // If lenp not null, then the length of encoded data before any final unlatch or pad is stored
17
+ // If maxp not null, then the max storage of this size code is stored
18
+ // If eccp not null, then the number of ecc bytes used in this size is stored
19
+ // Returns 0 on error (writes to stderr with details).
20
+
21
+ #define MAXBARCODE 3116
22
+
23
+ unsigned char *
24
+ iec16022ecc200 (int *Wptr, int *Hptr, char **encodingptr, int barcodelen, unsigned char *barcode, int *lenp,int *maxp,int *eccp);
25
+
26
+
27
+
@@ -0,0 +1,170 @@
1
+ // reedsol.c
2
+ //
3
+ // This is a simple Reed-Solomon encoder
4
+ // (C) Cliff Hones 2004
5
+ //
6
+ // It is not written with high efficiency in mind, so is probably
7
+ // not suitable for real-time encoding. The aim was to keep it
8
+ // simple, general and clear.
9
+ //
10
+ // <Some notes on the theory and implementation need to be added here>
11
+
12
+ // Usage:
13
+ // First call rs_init_gf(poly) to set up the Galois Field parameters.
14
+ // Then call rs_init_code(size, index) to set the encoding size
15
+ // Then call rs_encode(datasize, data, out) to encode the data.
16
+ //
17
+ // These can be called repeatedly as required - but note that
18
+ // rs_init_code must be called following any rs_init_gf call.
19
+ //
20
+ // If the parameters are fixed, some of the statics below can be
21
+ // replaced with constants in the obvious way, and additionally
22
+ // malloc/free can be avoided by using static arrays of a suitable
23
+ // size.
24
+
25
+ #include <stdio.h> // only needed for debug (main)
26
+ #include <stdlib.h> // only needed for malloc/free
27
+
28
+ static int gfpoly;
29
+ static int symsize; // in bits
30
+ static int logmod; // 2**symsize - 1
31
+ static int rlen;
32
+
33
+ static int *log = NULL,
34
+ *alog = NULL,
35
+ *rspoly = NULL;
36
+
37
+ // rs_init_gf(poly) initialises the parameters for the Galois Field.
38
+ // The symbol size is determined from the highest bit set in poly
39
+ // This implementation will support sizes up to 30 bits (though that
40
+ // will result in very large log/antilog tables) - bit sizes of
41
+ // 8 or 4 are typical
42
+ //
43
+ // The poly is the bit pattern representing the GF characteristic
44
+ // polynomial. e.g. for ECC200 (8-bit symbols) the polynomial is
45
+ // a**8 + a**5 + a**3 + a**2 + 1, which translates to 0x12d.
46
+
47
+ void
48
+ rs_init_gf (int poly)
49
+ {
50
+ int m,
51
+ b,
52
+ p,
53
+ v;
54
+
55
+ // Return storage from previous setup
56
+ if (log)
57
+ {
58
+ free (log);
59
+ free (alog);
60
+ free (rspoly);
61
+ rspoly = NULL;
62
+ }
63
+ // Find the top bit, and hence the symbol size
64
+ for (b = 1, m = 0; b <= poly; b <<= 1)
65
+ m++;
66
+ b >>= 1;
67
+ m--;
68
+ gfpoly = poly;
69
+ symsize = m;
70
+
71
+ // Calculate the log/alog tables
72
+ logmod = (1 << m) - 1;
73
+ log = (int *) malloc (sizeof (int) * (logmod + 1));
74
+ alog = (int *) malloc (sizeof (int) * logmod);
75
+
76
+ for (p = 1, v = 0; v < logmod; v++)
77
+ {
78
+ alog[v] = p;
79
+ log[p] = v;
80
+ p <<= 1;
81
+ if (p & b)
82
+ p ^= poly;
83
+ }
84
+ }
85
+
86
+ // rs_init_code(nsym, index) initialises the Reed-Solomon encoder
87
+ // nsym is the number of symbols to be generated (to be appended
88
+ // to the input data). index is usually 1 - it is the index of
89
+ // the constant in the first term (i) of the RS generator polynomial:
90
+ // (x + 2**i)*(x + 2**(i+1))*... [nsym terms]
91
+ // For ECC200, index is 1.
92
+
93
+ void
94
+ rs_init_code (int nsym, int index)
95
+ {
96
+ int i,
97
+ k;
98
+
99
+ if (rspoly)
100
+ free (rspoly);
101
+ rspoly = (int *) malloc (sizeof (int) * (nsym + 1));
102
+
103
+ rlen = nsym;
104
+
105
+ rspoly[0] = 1;
106
+ for (i = 1; i <= nsym; i++)
107
+ {
108
+ rspoly[i] = 1;
109
+ for (k = i - 1; k > 0; k--)
110
+ {
111
+ if (rspoly[k])
112
+ rspoly[k] = alog[(log[rspoly[k]] + index) % logmod];
113
+ rspoly[k] ^= rspoly[k - 1];
114
+ }
115
+ rspoly[0] = alog[(log[rspoly[0]] + index) % logmod];
116
+ index++;
117
+ }
118
+ }
119
+
120
+ // Note that the following uses byte arrays, so is only suitable for
121
+ // symbol sizes up to 8 bits. Just change the data type of data and res
122
+ // to unsigned int * for larger symbols.
123
+
124
+ void
125
+ rs_encode (int len, unsigned char *data, unsigned char *res)
126
+ {
127
+ int i,
128
+ k,
129
+ m;
130
+ for (i = 0; i < rlen; i++)
131
+ res[i] = 0;
132
+ for (i = 0; i < len; i++)
133
+ {
134
+ m = res[rlen - 1] ^ data[i];
135
+ for (k = rlen - 1; k > 0; k--)
136
+ {
137
+ if (m && rspoly[k])
138
+ res[k] = res[k - 1] ^ alog[(log[m] + log[rspoly[k]]) % logmod];
139
+ else
140
+ res[k] = res[k - 1];
141
+ }
142
+ if (m && rspoly[0])
143
+ res[0] = alog[(log[m] + log[rspoly[0]]) % logmod];
144
+ else
145
+ res[0] = 0;
146
+ }
147
+ }
148
+
149
+ #ifndef LIB
150
+ // The following tests the routines with the ISO/IEC 16022 Annexe R data
151
+ int
152
+ main (void)
153
+ {
154
+ register int i;
155
+
156
+ unsigned char data[9] = { 142, 164, 186 };
157
+ unsigned char out[5];
158
+
159
+ rs_init_gf (0x12d);
160
+ rs_init_code (5, 1);
161
+
162
+ rs_encode (3, data, out);
163
+
164
+ printf ("Result of Annexe R encoding:\n");
165
+ for (i = 4; i >= 0; i--)
166
+ printf (" %d\n", out[i]);
167
+
168
+ return 0;
169
+ }
170
+ #endif
@@ -0,0 +1,7 @@
1
+ /* don't compile in the main function from reedsol.c */
2
+ #define LIB
3
+
4
+ void rs_init_gf(int poly);
5
+ void rs_init_code(int nsym, int index);
6
+ void rs_encode(int len, unsigned char *data, unsigned char *res);
7
+
@@ -0,0 +1,384 @@
1
+ /*
2
+
3
+ == Introduction
4
+
5
+ This Ruby extension implements a DataMatrix encoder for Ruby. It is
6
+ typically used to create semacodes, which are barcodes, that contain URLs.
7
+ This encoder does not create image files or visual representations of the
8
+ semacode. This is because it can be used for more than creating images, such
9
+ as rendering semacodes to HTML, SVG, PDF or even stored in a database or
10
+ file for later use.
11
+
12
+ Author:: Guido Sohne (mailto:guido@sohne.net)
13
+ Copyright:: Copyright (c) 2007 Guido Sohne
14
+ License:: GNU GPL version 2, available from http://www.gnu.org
15
+ */
16
+
17
+ #include "ruby.h"
18
+ #include "semacode.h"
19
+
20
+ /*
21
+
22
+ Internal function that encodes a string of given length, storing
23
+ the encoded result into an internal, private data structure. This
24
+ structure is consulted for any operations, such as to get the
25
+ semacode dimensions. It deallocates any previous data before
26
+ generating a new encoding.
27
+
28
+ Due to a bug in the underlying encoder, we do two things
29
+
30
+ * append a space character before encoding, to get around
31
+ an off by one error lurking in the C code
32
+
33
+ * manually select the best barcode dimensions, to avoid
34
+ an encoder bug where sometimes no suitable encoding would
35
+ be found
36
+
37
+ */
38
+ semacode_t*
39
+ encode_string(semacode_t *semacode, int message_length, char *message)
40
+ {
41
+ /* avoid obvious bad cases */
42
+ if(semacode == NULL || message == NULL || message_length < 1) {
43
+ return NULL;
44
+ }
45
+
46
+ /* deallocate if exists already */
47
+ if(semacode->data != NULL)
48
+ free(semacode->data);
49
+
50
+ /* deallocate if exists already */
51
+ if(semacode->encoding != NULL)
52
+ free(semacode->encoding);
53
+
54
+ bzero(semacode, sizeof(semacode_t));
55
+
56
+ // work around encoding bug by appending an extra character.
57
+ strcat(message, " ");
58
+ message_length++;
59
+
60
+ // choose the best grid that will hold our message
61
+ iec16022init(&semacode->width, &semacode->height, message);
62
+
63
+ // encode the actual data
64
+ semacode->data = (char *) iec16022ecc200(
65
+ &semacode->width,
66
+ &semacode->height,
67
+ &semacode->encoding,
68
+ message_length,
69
+ (unsigned char *) message,
70
+ &semacode->raw_encoded_length,
71
+ &semacode->symbol_capacity,
72
+ &semacode->ecc_bytes);
73
+
74
+ return semacode;
75
+ }
76
+
77
+ /* our module and class, respectively */
78
+
79
+ static VALUE rb_mSemacode;
80
+ static VALUE rb_cEncoder;
81
+
82
+ static void
83
+ semacode_mark(semacode_t *semacode)
84
+ {
85
+ /* need this if we ever hold any other Ruby objects. so let's not go there. */
86
+ }
87
+
88
+ static void
89
+ semacode_free(semacode_t *semacode)
90
+ {
91
+ if(semacode != NULL) {
92
+ if(semacode->data != NULL)
93
+ free(semacode->encoding);
94
+ free(semacode->data);
95
+ /* zero before freeing */
96
+ bzero(semacode, sizeof(semacode));
97
+ free(semacode);
98
+ }
99
+ }
100
+
101
+ static VALUE
102
+ semacode_allocate(VALUE klass)
103
+ {
104
+ semacode_t *semacode;
105
+ return Data_Make_Struct(klass, semacode_t, semacode_mark, semacode_free, semacode);
106
+ }
107
+
108
+ /*
109
+ Initialize the semacode. This function is called after a semacode is
110
+ created. Ruby objects are created using a new method, and then initialized
111
+ via the 'initialize' method once they have been allocated.
112
+
113
+ The initializer takes a single argument, which can be anything that
114
+ responds to the 'to_s' method - that is, anything string like.
115
+
116
+ The string in the argument is encoded and the semacode is returned
117
+ initialized and ready for use.
118
+
119
+ */
120
+ static VALUE
121
+ semacode_init(VALUE self, VALUE message)
122
+ {
123
+ semacode_t *semacode;
124
+
125
+ if (!rb_respond_to(message, rb_intern ("to_s")))
126
+ rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
127
+
128
+ Data_Get_Struct(self, semacode_t, semacode);
129
+ encode_string(semacode, StringValueLen(message), StringValuePtr(message));
130
+
131
+ return self;
132
+ }
133
+
134
+ /*
135
+ This function turns the raw output from an encoding into a more
136
+ friendly format organized by rows and columns.
137
+
138
+ It returns the semacode matrix as an array of arrays of boolean. The
139
+ first element in the array is the top row, the last is the bottom row.
140
+
141
+ Each row is also an array, containing boolean values. The length of each
142
+ row is the same as the semacode width, and the number of rows is the same
143
+ as the semacode height.
144
+
145
+ */
146
+ static VALUE
147
+ semacode_grid(semacode_t *semacode)
148
+ {
149
+ int w = semacode->width;
150
+ int h = semacode->height;
151
+
152
+ VALUE ret = rb_ary_new2(h);
153
+
154
+ int x, y;
155
+ for (y = h - 1; y >= 0; y--) {
156
+ VALUE ary = rb_ary_new2(w);
157
+ for (x = 0; x < w; x++) {
158
+ if(semacode->data[y * w + x])
159
+ rb_ary_push(ary, Qtrue);
160
+ else
161
+ rb_ary_push(ary, Qfalse);
162
+ }
163
+ rb_ary_push(ret, ary);
164
+ }
165
+
166
+ return ret;
167
+ }
168
+
169
+ /*
170
+ This function turns the raw output from an encoding into a string
171
+ representation.
172
+
173
+ It returns the semacode matrix as a comma-separated list of character
174
+ vectors (sequence of characters). The top row is the first vector and
175
+ the bottow row is the last vector.
176
+
177
+ Each vector is a sequence of characters, either '1' or '0', to represent
178
+ the bits of the semacode pattern. The length of a vector is the semacode
179
+ width, and the number of vectors is the same as the semacode height.
180
+
181
+ */
182
+ static VALUE
183
+ semacode_to_s(VALUE self)
184
+ {
185
+ semacode_t *semacode;
186
+ VALUE str;
187
+ int x, y;
188
+ int w, h;
189
+
190
+ Data_Get_Struct(self, semacode_t, semacode);
191
+
192
+ if(semacode == NULL || semacode->data == NULL)
193
+ return Qnil;
194
+
195
+ w = semacode->width;
196
+ h = semacode->height;
197
+
198
+ str = rb_str_new2("");
199
+
200
+ for (y = h - 1; y >= 0; y--) {
201
+ for (x = 0; x < w; x++) {
202
+ if(semacode->data[y * w + x])
203
+ rb_str_cat(str, "1", 1);
204
+ else
205
+ rb_str_cat(str, "0", 1);
206
+ }
207
+ rb_str_cat(str, ",", 1);
208
+ }
209
+
210
+ return str;
211
+ }
212
+ /*
213
+
214
+ After creating a semacode, it is possible to reuse the semacode object
215
+ if you want to encode another URL. You should call the 'encode' method
216
+ at any time to create a replacement semecode for the current object.
217
+
218
+ It returns the semacode matrix as an array of arrays of boolean. The
219
+ first element in the array is the top row, the last is the bottom row.
220
+
221
+ Each row is also an array, containing boolean values. The length of each
222
+ row is the same as the semacode width, and the number of rows is the same
223
+ as the semacode height.
224
+
225
+ */
226
+ static VALUE
227
+ semacode_encode(VALUE self, VALUE message)
228
+ {
229
+ semacode_t *semacode;
230
+
231
+ if (!rb_respond_to(message, rb_intern ("to_s")))
232
+ rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
233
+
234
+ Data_Get_Struct(self, semacode_t, semacode);
235
+
236
+ /* free previous string if that exists */
237
+ if(semacode->data != NULL) {
238
+ free(semacode->data);
239
+ semacode->data == NULL;
240
+ }
241
+
242
+ /* do a new encoding */
243
+ DATA_PTR(self) = encode_string(semacode, StringValueLen(message), StringValuePtr(message));
244
+
245
+ return semacode_grid(semacode);
246
+ }
247
+
248
+ /*
249
+ This function gives the encoding organized by rows and columns.
250
+
251
+ It returns the semacode matrix as an array of arrays of boolean. The
252
+ first element in the array is the top row, the last is the bottom row.
253
+
254
+ Each row is also an array, containing boolean values. The length of each
255
+ row is the same as the semacode width, and the number of rows is the same
256
+ as the semacode height.
257
+
258
+ */
259
+ static VALUE
260
+ semacode_data(VALUE self)
261
+ {
262
+ semacode_t *semacode;
263
+ Data_Get_Struct(self, semacode_t, semacode);
264
+
265
+ if(semacode->data == NULL)
266
+ return Qnil;
267
+ else
268
+ return semacode_grid(semacode);
269
+ }
270
+
271
+ /*
272
+ This returns the encoding string used to create the semacode.
273
+ */
274
+ static VALUE
275
+ semacode_encoded(VALUE self)
276
+ {
277
+ semacode_t *semacode;
278
+ Data_Get_Struct(self, semacode_t, semacode);
279
+
280
+ return rb_str_new2(semacode->encoding);
281
+ }
282
+
283
+ /*
284
+ This returns the width of the semacode.
285
+ */
286
+ static VALUE
287
+ semacode_width(VALUE self)
288
+ {
289
+ semacode_t *semacode;
290
+ Data_Get_Struct(self, semacode_t, semacode);
291
+
292
+ return INT2FIX(semacode->width);
293
+ }
294
+
295
+ /*
296
+ This returns the height of the semacode.
297
+ */
298
+ static VALUE
299
+ semacode_height(VALUE self)
300
+ {
301
+ semacode_t *semacode;
302
+ Data_Get_Struct(self, semacode_t, semacode);
303
+
304
+ return INT2FIX(semacode->height);
305
+ }
306
+
307
+ /*
308
+ This returns the length of the semacode. It is
309
+ the same as the product of the height and the width.
310
+ */
311
+ static VALUE
312
+ semacode_length(VALUE self)
313
+ {
314
+ semacode_t *semacode;
315
+ Data_Get_Struct(self, semacode_t, semacode);
316
+
317
+ return INT2FIX(semacode->height * semacode->width);
318
+ }
319
+
320
+ /*
321
+ This returns the length of the raw underlying encoding
322
+ representing the data, before padding, error correction
323
+ or any other operations on the raw encoding.
324
+ */
325
+ static VALUE
326
+ semacode_raw_encoded_length(VALUE self)
327
+ {
328
+ semacode_t *semacode;
329
+ Data_Get_Struct(self, semacode_t, semacode);
330
+
331
+ return INT2FIX(semacode->raw_encoded_length);
332
+ }
333
+
334
+ /*
335
+ This returns the maximum number of characters that can
336
+ be stored in a symbol of the given width and height. You
337
+ can use this to decide if it is worth packing in extra
338
+ information while keeping the symbol size the same.
339
+ */
340
+ static VALUE
341
+ semacode_symbol_size(VALUE self)
342
+ {
343
+ semacode_t *semacode;
344
+ Data_Get_Struct(self, semacode_t, semacode);
345
+
346
+ return INT2FIX(semacode->symbol_capacity);
347
+ }
348
+
349
+ /*
350
+ This returns the number of bytes that are being devoted to
351
+ error correction.
352
+ */
353
+ static VALUE
354
+ semacode_ecc_bytes(VALUE self)
355
+ {
356
+ semacode_t *semacode;
357
+ Data_Get_Struct(self, semacode_t, semacode);
358
+
359
+ return INT2FIX(semacode->ecc_bytes);
360
+ }
361
+
362
+ void
363
+ Init_semacode_native()
364
+ {
365
+ rb_mSemacode = rb_define_module ("DataMatrix");
366
+ rb_cEncoder = rb_define_class_under(rb_mSemacode, "Encoder", rb_cObject);
367
+
368
+ rb_define_alloc_func(rb_cEncoder, semacode_allocate);
369
+
370
+ rb_define_method(rb_cEncoder, "initialize", semacode_init, 1);
371
+ rb_define_method(rb_cEncoder, "encode", semacode_encode, 1);
372
+ rb_define_method(rb_cEncoder, "to_a", semacode_data, 0);
373
+ rb_define_method(rb_cEncoder, "data", semacode_data, 0);
374
+ rb_define_method(rb_cEncoder, "encoding", semacode_encoded, 0);
375
+ rb_define_method(rb_cEncoder, "to_s", semacode_to_s, 0);
376
+ rb_define_method(rb_cEncoder, "to_str", semacode_to_s, 0);
377
+ rb_define_method(rb_cEncoder, "width", semacode_width, 0);
378
+ rb_define_method(rb_cEncoder, "height", semacode_height, 0);
379
+ rb_define_method(rb_cEncoder, "length", semacode_length, 0);
380
+ rb_define_method(rb_cEncoder, "size", semacode_length, 0);
381
+ rb_define_method(rb_cEncoder, "raw_encoded_length", semacode_raw_encoded_length, 0);
382
+ rb_define_method(rb_cEncoder, "symbol_size", semacode_symbol_size, 0);
383
+ rb_define_method(rb_cEncoder, "ecc_bytes", semacode_ecc_bytes, 0);
384
+ }