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.
@@ -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,5 @@
1
+
2
+ void rs_init_gf(int poly);
3
+ void rs_init_code(int nsym, int index);
4
+ void rs_encode(int len, unsigned char *data, unsigned char *res);
5
+
@@ -0,0 +1,359 @@
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
+ /* deallocate if exists already */
42
+ if(semacode !=NULL && semacode->data != NULL)
43
+ free(semacode->data);
44
+
45
+ bzero(semacode, sizeof(semacode_t));
46
+
47
+ // work around encoding bug by appending an extra character.
48
+ strcat(message, " ");
49
+ message_length++;
50
+
51
+ // choose the best grid that will hold our message
52
+ iec16022init(&semacode->width, &semacode->height, message);
53
+
54
+ // encode the actual data
55
+ semacode->data = (char *) iec16022ecc200(
56
+ &semacode->width,
57
+ &semacode->height,
58
+ NULL,
59
+ message_length,
60
+ (unsigned char *) message,
61
+ &semacode->raw_encoded_length,
62
+ &semacode->symbol_capacity,
63
+ &semacode->ecc_bytes);
64
+
65
+ return semacode;
66
+ }
67
+
68
+ /* our module and class, respectively */
69
+
70
+ static VALUE rb_mSemacode;
71
+ static VALUE rb_cEncoder;
72
+
73
+ static void
74
+ semacode_mark(semacode_t *semacode)
75
+ {
76
+ /* need this if we ever hold any other Ruby objects. so let's not go there. */
77
+ }
78
+
79
+ static void
80
+ semacode_free(semacode_t *semacode)
81
+ {
82
+ if(semacode != NULL) {
83
+ if(semacode->data != NULL)
84
+ free(semacode->data);
85
+ bzero(semacode, sizeof(semacode));
86
+ free(semacode);
87
+ }
88
+ }
89
+
90
+ static VALUE
91
+ semacode_allocate(VALUE klass)
92
+ {
93
+ semacode_t *semacode;
94
+ return Data_Make_Struct(klass, semacode_t, semacode_mark, semacode_free, semacode);
95
+ }
96
+
97
+ /*
98
+ Initialize the semacode. This function is called after a semaode is
99
+ created. Ruby objects are created using a new method, and then initialized
100
+ via the 'initialize' method once they have been allocated.
101
+
102
+ The initializer takes a single argument, which can be anything that
103
+ responds to the 'to_s' method - that is, anything string like.
104
+
105
+ The string in the argument is encoded and the semacode is returned
106
+ initialized and ready for use.
107
+
108
+ */
109
+ static VALUE
110
+ semacode_init(VALUE self, VALUE message)
111
+ {
112
+ semacode_t *semacode;
113
+
114
+ if (!rb_respond_to(message, rb_intern ("to_s")))
115
+ rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
116
+
117
+ Data_Get_Struct(self, semacode_t, semacode);
118
+ encode_string(semacode, StringValueLen(message), StringValuePtr(message));
119
+
120
+ return self;
121
+ }
122
+
123
+ /*
124
+ This function turns the raw output from an encoding into a more
125
+ friendly format organized by rows and columns.
126
+
127
+ It returns the semacode matrix as an array of arrays of boolean. The
128
+ first element in the array is the top row, the last is the bottom row.
129
+
130
+ Each row is also an array, containing boolean values. The length of each
131
+ row is the same as the semacode width, and the number of rows is the same
132
+ as the semacode height.
133
+
134
+ */
135
+ static VALUE
136
+ semacode_grid(semacode_t *semacode)
137
+ {
138
+ int w = semacode->width;
139
+ int h = semacode->height;
140
+
141
+ VALUE ret = rb_ary_new2(h);
142
+
143
+ int x, y;
144
+ for (y = h - 1; y >= 0; y--) {
145
+ VALUE ary = rb_ary_new2(w);
146
+ for (x = 0; x < w; x++) {
147
+ if(semacode->data[y * w + x])
148
+ rb_ary_push(ary, Qtrue);
149
+ else
150
+ rb_ary_push(ary, Qfalse);
151
+ }
152
+ rb_ary_push(ret, ary);
153
+ }
154
+
155
+ return ret;
156
+ }
157
+
158
+ /*
159
+ This function turns the raw output from an encoding into a string
160
+ representation.
161
+
162
+ It returns the semacode matrix as a comma-separated list of character
163
+ vectors (sequence of characters). The top row is the first vector and
164
+ the bottow row is the last vector.
165
+
166
+ Each vector is a sequence of characters, either '1' or '0', to represent
167
+ the bits of the semacode pattern. The length of a vector is the semacode
168
+ width, and the number of vectors is the same as the semacode height.
169
+
170
+ */
171
+ static VALUE
172
+ semacode_to_s(VALUE self)
173
+ {
174
+ semacode_t *semacode;
175
+ VALUE str;
176
+ int x, y;
177
+ int w, h;
178
+
179
+ Data_Get_Struct(self, semacode_t, semacode);
180
+
181
+ if(semacode == NULL || semacode->data == NULL)
182
+ return Qnil;
183
+
184
+ w = semacode->width;
185
+ h = semacode->height;
186
+
187
+ str = rb_str_new2("");
188
+
189
+ for (y = h - 1; y >= 0; y--) {
190
+ for (x = 0; x < w; x++) {
191
+ if(semacode->data[y * w + x])
192
+ rb_str_cat(str, "1", 1);
193
+ else
194
+ rb_str_cat(str, "0", 1);
195
+ }
196
+ rb_str_cat(str, ",", 1);
197
+ }
198
+
199
+ return str;
200
+ }
201
+ /*
202
+
203
+ After creating a semacode, it is possible to reuse the semacode object
204
+ if you want to encode another URL. You should call the 'encode' method
205
+ at any time to create a replacement semecode for the current object.
206
+
207
+ It returns the semacode matrix as an array of arrays of boolean. The
208
+ first element in the array is the top row, the last is the bottom row.
209
+
210
+ Each row is also an array, containing boolean values. The length of each
211
+ row is the same as the semacode width, and the number of rows is the same
212
+ as the semacode height.
213
+
214
+ */
215
+ static VALUE
216
+ semacode_encode(VALUE self, VALUE message)
217
+ {
218
+ semacode_t *semacode;
219
+
220
+ if (!rb_respond_to(message, rb_intern ("to_s")))
221
+ rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
222
+
223
+ Data_Get_Struct(self, semacode_t, semacode);
224
+
225
+ /* free previous string if that exists */
226
+ if(semacode->data != NULL) {
227
+ free(semacode->data);
228
+ semacode->data == NULL;
229
+ }
230
+
231
+ /* do a new encoding */
232
+ DATA_PTR(self) = encode_string(semacode, StringValueLen(message), StringValuePtr(message));
233
+
234
+ return semacode_grid(semacode);
235
+ }
236
+
237
+ /*
238
+ This function gives the encoding organized by rows and columns.
239
+
240
+ It returns the semacode matrix as an array of arrays of boolean. The
241
+ first element in the array is the top row, the last is the bottom row.
242
+
243
+ Each row is also an array, containing boolean values. The length of each
244
+ row is the same as the semacode width, and the number of rows is the same
245
+ as the semacode height.
246
+
247
+ */
248
+ static VALUE
249
+ semacode_data(VALUE self)
250
+ {
251
+ semacode_t *semacode;
252
+ Data_Get_Struct(self, semacode_t, semacode);
253
+
254
+ if(semacode->data == NULL)
255
+ return Qnil;
256
+ else
257
+ return semacode_grid(semacode);
258
+ }
259
+
260
+ /*
261
+ This returns the width of the semacode.
262
+ */
263
+ static VALUE
264
+ semacode_width(VALUE self)
265
+ {
266
+ semacode_t *semacode;
267
+ Data_Get_Struct(self, semacode_t, semacode);
268
+
269
+ return INT2FIX(semacode->width);
270
+ }
271
+
272
+ /*
273
+ This returns the height of the semacode.
274
+ */
275
+ static VALUE
276
+ semacode_height(VALUE self)
277
+ {
278
+ semacode_t *semacode;
279
+ Data_Get_Struct(self, semacode_t, semacode);
280
+
281
+ return INT2FIX(semacode->height);
282
+ }
283
+
284
+ /*
285
+ This returns the length of the semacode. It is
286
+ the same as the product of the height and the width.
287
+ */
288
+ static VALUE
289
+ semacode_length(VALUE self)
290
+ {
291
+ semacode_t *semacode;
292
+ Data_Get_Struct(self, semacode_t, semacode);
293
+
294
+ return INT2FIX(semacode->height * semacode->width);
295
+ }
296
+
297
+ /*
298
+ This returns the length of the raw underlying encoding
299
+ representing the data, before padding, error correction
300
+ or any other operations on the raw encoding.
301
+ */
302
+ static VALUE
303
+ semacode_raw_encoded_length(VALUE self)
304
+ {
305
+ semacode_t *semacode;
306
+ Data_Get_Struct(self, semacode_t, semacode);
307
+
308
+ return INT2FIX(semacode->raw_encoded_length);
309
+ }
310
+
311
+ /*
312
+ This returns the maximum number of characters that can
313
+ be stored in a symbol of the given width and height. You
314
+ can use this to decide if it is worth packing in extra
315
+ information while keeping the symbol size the same.
316
+ */
317
+ static VALUE
318
+ semacode_symbol_size(VALUE self)
319
+ {
320
+ semacode_t *semacode;
321
+ Data_Get_Struct(self, semacode_t, semacode);
322
+
323
+ return INT2FIX(semacode->symbol_capacity);
324
+ }
325
+
326
+ /*
327
+ This returns the number of bytes that are being devoted to
328
+ error correction.
329
+ */
330
+ static VALUE
331
+ semacode_ecc_bytes(VALUE self)
332
+ {
333
+ semacode_t *semacode;
334
+ Data_Get_Struct(self, semacode_t, semacode);
335
+
336
+ return INT2FIX(semacode->ecc_bytes);
337
+ }
338
+
339
+ void
340
+ Init_semacode()
341
+ {
342
+ rb_mSemacode = rb_define_module ("DataMatrix");
343
+ rb_cEncoder = rb_define_class_under(rb_mSemacode, "Encoder", rb_cObject);
344
+ rb_define_alloc_func(rb_cEncoder, semacode_allocate);
345
+
346
+ rb_define_method(rb_cEncoder, "initialize", semacode_init, 1);
347
+ rb_define_method(rb_cEncoder, "encode", semacode_encode, 1);
348
+ rb_define_method(rb_cEncoder, "to_a", semacode_data, 0);
349
+ rb_define_method(rb_cEncoder, "data", semacode_data, 0);
350
+ rb_define_method(rb_cEncoder, "to_s", semacode_to_s, 0);
351
+ rb_define_method(rb_cEncoder, "to_str", semacode_to_s, 0);
352
+ rb_define_method(rb_cEncoder, "width", semacode_width, 0);
353
+ rb_define_method(rb_cEncoder, "height", semacode_height, 0);
354
+ rb_define_method(rb_cEncoder, "length", semacode_length, 0);
355
+ rb_define_method(rb_cEncoder, "size", semacode_length, 0);
356
+ rb_define_method(rb_cEncoder, "raw_encoded_length", semacode_raw_encoded_length, 0);
357
+ rb_define_method(rb_cEncoder, "symbol_size", semacode_symbol_size, 0);
358
+ rb_define_method(rb_cEncoder, "ecc_bytes", semacode_ecc_bytes, 0);
359
+ }