data_matrix 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4c4f71b784d1454fdc371e8565479b0404f5f4bc
4
+ data.tar.gz: e385701eaf8326b9a4fce2e04eb3414341643925
5
+ SHA512:
6
+ metadata.gz: 38213745494b7b57f1dfb489c778c1ff2c18274e88cbd0919337c158ec13a91101522f4f7a7f20b5d22c134da399aebd8d1967e37996ebed0114f94c2790d8a7
7
+ data.tar.gz: aee294d8edf2b0db6eee86d41ee79c4855a1f8cd7edcddd4fdbe6f3c0e73c9b7830534635edaac3a3cebdfd20e2bbef3d1076013952a0b44b727efda5790a0c4
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ # rspec failure tracking
17
+ .rspec_status
18
+ .ruby-version
19
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,6 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+ AllCops:
4
+ TargetRubyVersion: 2.3
5
+ Exclude:
6
+ - 'bin/**/*'
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+
4
+ # Specify your gem's dependencies in data_matrix.gemspec
5
+ gemspec
@@ -0,0 +1,36 @@
1
+ # DataMatrix
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/data_matrix`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'data_matrix'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install data_matrix
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/vessi/data_matrix.
36
+
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ require 'rake/extensiontask'
8
+
9
+ task build: :compile
10
+
11
+ Rake::ExtensionTask.new('data_matrix') { |ext| ext.lib_dir = 'lib/data_matrix' }
12
+
13
+ task default: %i(clobber compile spec)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "data_matrix"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # coding: utf-8
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'data_matrix/version'
6
+
7
+ datamatrix_description = <<DESC
8
+ This Ruby extension implements a DataMatrix encoder for Ruby. It is typically
9
+ used to create semacodes, which are barcodes, that contain URLs. This encoder
10
+ does not create image files or visual representations of the semacode. This is
11
+ because it can be used for more than creating images, such as rendering
12
+ semacodes to HTML, SVG, PDF or even stored in a database or file for later
13
+ use.
14
+ DESC
15
+
16
+ Gem::Specification.new do |spec|
17
+ spec.name = 'data_matrix'
18
+ spec.version = DataMatrix::VERSION
19
+ spec.authors = ['Mikhail Bortnyk', 'Guido Sohne']
20
+ spec.email = %w(vessimir@gmail.com guido@sohne.net)
21
+
22
+ spec.summary = 'Create semacodes (2D barcodes) using Ruby.'
23
+ spec.description = datamatrix_description
24
+ spec.homepage = 'https://github.com/vessi/data_matrix'
25
+
26
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
27
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
28
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
29
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
30
+
31
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ spec.bindir = 'exe'
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
+ spec.require_paths = %w(lib)
35
+ spec.extensions = %w(ext/data_matrix/extconf.rb)
36
+
37
+ spec.add_development_dependency 'bundler', '~> 1.14'
38
+ spec.add_development_dependency 'rake', '~> 10.0'
39
+ spec.add_development_dependency 'rake-compiler'
40
+ spec.add_development_dependency 'rspec', '~> 3.0'
41
+ spec.add_development_dependency 'rubocop'
42
+ end
@@ -0,0 +1,206 @@
1
+ #include "data_matrix.h"
2
+
3
+ VALUE rb_mDataMatrix, rb_cEncoder;
4
+
5
+ semacode_t* encode_string(semacode_t* semacode, const char *message) {
6
+ char* fixed_message;
7
+
8
+ if (semacode == NULL || message == NULL || strlen(message) < 1) {
9
+ return NULL;
10
+ }
11
+
12
+ fixed_message = malloc(sizeof(char) * strlen(message) + 1);
13
+
14
+ if (semacode->data != NULL) {
15
+ free(semacode->data);
16
+ }
17
+ if (semacode->encoding != NULL) {
18
+ free(semacode->encoding);
19
+ }
20
+
21
+ bzero(semacode, sizeof(semacode_t));
22
+ fixed_message = strdup(message);
23
+ strcat(fixed_message, " ");
24
+
25
+ iec16022init(&semacode->width, &semacode->height, fixed_message);
26
+
27
+ semacode->data = (char *) iec16022ecc200(&semacode->width, &semacode->height, &semacode->encoding,
28
+ (int) strlen(fixed_message), (unsigned char *) fixed_message,
29
+ &semacode->raw_encoded_length, &semacode->symbol_capacity,
30
+ &semacode->ecc_bytes);
31
+
32
+ free(fixed_message);
33
+
34
+ return semacode;
35
+ }
36
+
37
+ static void data_matrix_mark(semacode_t* semacode) {
38
+ semacode->width = 0;
39
+ semacode->height = 0;
40
+ semacode->raw_encoded_length = 0;
41
+ semacode->symbol_capacity = 0;
42
+ semacode->ecc_bytes = 0;
43
+ semacode->encoding = NULL;
44
+ semacode->data = NULL;
45
+ }
46
+
47
+ static void data_matrix_free(semacode_t* semacode) {
48
+ if (semacode != NULL) {
49
+ if (semacode->data != NULL) {
50
+ free(semacode->encoding);
51
+ free(semacode->data);
52
+ }
53
+ bzero(semacode, sizeof(semacode));
54
+ free(semacode);
55
+ }
56
+ }
57
+
58
+ static VALUE data_matrix_grid(semacode_t *semacode) {
59
+ int w = semacode->width;
60
+ int h = semacode->height;
61
+
62
+ VALUE ret = rb_ary_new2(h);
63
+
64
+ int x, y;
65
+ for (y = h - 1; y >= 0; y--) {
66
+ VALUE ary = rb_ary_new2(w);
67
+ for (x = 0; x < w; x++) {
68
+ if(semacode->data[y * w + x])
69
+ rb_ary_push(ary, Qtrue);
70
+ else
71
+ rb_ary_push(ary, Qfalse);
72
+ }
73
+ rb_ary_push(ret, ary);
74
+ }
75
+
76
+ return ret;
77
+ }
78
+
79
+ static VALUE data_matrix_allocate(VALUE klass) {
80
+ semacode_t *semacode;
81
+ return Data_Make_Struct(klass, semacode_t, data_matrix_mark, data_matrix_free, semacode);
82
+ }
83
+
84
+ static VALUE data_matrix_init(VALUE self, VALUE message) {
85
+ semacode_t *semacode;
86
+ Data_Get_Struct(self, semacode_t, semacode);
87
+
88
+ encode_string(semacode, StringValuePtr(message));
89
+
90
+ return self;
91
+ }
92
+
93
+ static VALUE data_matrix_encode(VALUE self, VALUE encoding) {
94
+ semacode_t *semacode;
95
+
96
+ if (!rb_respond_to(encoding, rb_intern ("to_s")))
97
+ rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
98
+
99
+ Data_Get_Struct(self, semacode_t, semacode);
100
+
101
+ /* free previous string if that exists */
102
+ if(semacode->data != NULL) {
103
+ free(semacode->data);
104
+ semacode->data = NULL;
105
+ }
106
+
107
+ /* do a new encoding */
108
+ DATA_PTR(self) = encode_string(semacode, StringValuePtr(encoding));
109
+ return data_matrix_grid(semacode);
110
+ }
111
+
112
+ static VALUE data_matrix_data(VALUE self) {
113
+ semacode_t *semacode;
114
+ Data_Get_Struct(self, semacode_t, semacode);
115
+
116
+ if(semacode->data == NULL)
117
+ return Qnil;
118
+ else
119
+ return data_matrix_grid(semacode);
120
+ }
121
+
122
+ static VALUE data_matrix_encoded(VALUE self) {
123
+ semacode_t *semacode;
124
+ Data_Get_Struct(self, semacode_t, semacode);
125
+
126
+ return rb_str_new2(semacode->encoding);
127
+ }
128
+
129
+ static VALUE data_matrix_to_s(VALUE self) {
130
+ semacode_t *semacode;
131
+ VALUE str;
132
+ int x, y, w, h;
133
+
134
+ Data_Get_Struct(self, semacode_t, semacode);
135
+
136
+ if(semacode == NULL || semacode->data == NULL) return Qnil;
137
+
138
+ w = semacode->width;
139
+ h = semacode->height;
140
+
141
+ str = rb_str_new2("");
142
+
143
+ for (y = h - 1; y >= 0; y--) {
144
+ for (x = 0; x < w; x++) {
145
+ if(semacode->data[y * w + x])
146
+ rb_str_cat(str, "1", 1);
147
+ else
148
+ rb_str_cat(str, "0", 1);
149
+ }
150
+ rb_str_cat(str, ",", 1);
151
+ }
152
+ return str;
153
+ }
154
+
155
+ static VALUE data_matrix_width(VALUE self) {
156
+ semacode_t *semacode;
157
+ Data_Get_Struct(self, semacode_t, semacode);
158
+
159
+ return INT2FIX(semacode->width);
160
+ }
161
+
162
+ static VALUE data_matrix_height(VALUE self) {
163
+ semacode_t *semacode;
164
+ Data_Get_Struct(self, semacode_t, semacode);
165
+
166
+ return INT2FIX(semacode->height);
167
+ }
168
+
169
+ static VALUE data_matrix_raw_encoded_length(VALUE self) {
170
+ semacode_t *semacode;
171
+ Data_Get_Struct(self, semacode_t, semacode);
172
+
173
+ return INT2FIX(semacode->raw_encoded_length);
174
+ }
175
+
176
+ static VALUE data_matrix_symbol_size(VALUE self) {
177
+ semacode_t *semacode;
178
+ Data_Get_Struct(self, semacode_t, semacode);
179
+
180
+ return INT2FIX(semacode->symbol_capacity);
181
+ }
182
+
183
+ static VALUE data_matrix_ecc_bytes(VALUE self) {
184
+ semacode_t *semacode;
185
+ Data_Get_Struct(self, semacode_t, semacode);
186
+
187
+ return INT2FIX(semacode->ecc_bytes);
188
+ }
189
+
190
+ void Init_data_matrix(void) {
191
+ rb_mDataMatrix = rb_define_module("DataMatrix");
192
+ rb_cEncoder = rb_define_class_under(rb_mDataMatrix, "Encoder", rb_cObject);
193
+
194
+ rb_define_alloc_func(rb_cEncoder, data_matrix_allocate);
195
+
196
+ rb_define_method(rb_cEncoder, "encode_string", data_matrix_init, 1);
197
+ rb_define_method(rb_cEncoder, "encode", data_matrix_encode, 1);
198
+ rb_define_method(rb_cEncoder, "data", data_matrix_data, 0);
199
+ rb_define_method(rb_cEncoder, "encoding", data_matrix_encoded, 0);
200
+ rb_define_method(rb_cEncoder, "to_s", data_matrix_to_s, 0);
201
+ rb_define_method(rb_cEncoder, "width", data_matrix_width, 0);
202
+ rb_define_method(rb_cEncoder, "height", data_matrix_height, 0);
203
+ rb_define_method(rb_cEncoder, "raw_encoded_length", data_matrix_raw_encoded_length, 0);
204
+ rb_define_method(rb_cEncoder, "symbol_size", data_matrix_symbol_size, 0);
205
+ rb_define_method(rb_cEncoder, "ecc_bytes", data_matrix_ecc_bytes, 0);
206
+ }
@@ -0,0 +1,21 @@
1
+ #ifndef DATA_MATRIX_H
2
+ #define DATA_MATRIX_H 1
3
+
4
+ #include "ruby.h"
5
+ #include "iec16022ecc200.h"
6
+
7
+ typedef struct semacode_t {
8
+ int width;
9
+ int height;
10
+ int raw_encoded_length;
11
+ int symbol_capacity;
12
+ int ecc_bytes;
13
+ char *encoding;
14
+ char *data;
15
+ } semacode_t;
16
+
17
+ semacode_t* encode_string(semacode_t* semacode, const char *message);
18
+ static void data_matrix_mark(semacode_t* semacode);
19
+ static void data_matrix_free(semacode_t* semacode);
20
+
21
+ #endif /* DATA_MATRIX_H */
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ require 'mkmf'
3
+
4
+ create_makefile('data_matrix/data_matrix')
@@ -0,0 +1,847 @@
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 <stdlib.h>
27
+ #include <ctype.h>
28
+ #include <string.h>
29
+ #include <time.h>
30
+ #include "reedsol.h"
31
+ #include "iec16022ecc200.h"
32
+
33
+ static struct ecc200matrix_s {
34
+ int H, W, FH, FW, bytes, datablock, rsblock;
35
+ }
36
+
37
+ const ecc200matrix[] = {
38
+ {10, 10, 10, 10, 3, 3, 5}, //
39
+ {12, 12, 12, 12, 5, 5, 7}, //
40
+ {14, 14, 14, 14, 8, 8, 10}, //
41
+ {16, 16, 16, 16, 12, 12, 12}, //
42
+ {18, 18, 18, 18, 18, 18, 14}, //
43
+ {20, 20, 20, 20, 22, 22, 18}, //
44
+ {22, 22, 22, 22, 30, 30, 20}, //
45
+ {24, 24, 24, 24, 36, 36, 24}, //
46
+ {26, 26, 26, 26, 44, 44, 28}, //
47
+ {32, 32, 16, 16, 62, 62, 36}, //
48
+ {36, 36, 18, 18, 86, 86, 42}, //
49
+ {40, 40, 20, 20, 114, 114, 48}, //
50
+ {44, 44, 22, 22, 144, 144, 56}, //
51
+ {48, 48, 24, 24, 174, 174, 68}, //
52
+ {52, 52, 26, 26, 204, 102, 42}, //
53
+ {64, 64, 16, 16, 280, 140, 56}, //
54
+ {72, 72, 18, 18, 368, 92, 36}, //
55
+ {80, 80, 20, 20, 456, 114, 48}, //
56
+ {88, 88, 22, 22, 576, 144, 56}, //
57
+ {96, 96, 24, 24, 696, 174, 68}, //
58
+ {104, 104, 26, 26, 816, 136, 56}, //
59
+ {120, 120, 20, 20, 1050, 175, 68}, //
60
+ {132, 132, 22, 22, 1304, 163, 62}, //
61
+ {144, 144, 24, 24, 1558, 156, 62}, // 156*4+155*2
62
+ {0} // terminate
63
+ };
64
+
65
+ // Auto encoding format functions
66
+ static char encchr[] = "ACTXEB";
67
+
68
+ enum {
69
+ E_ASCII,
70
+ E_C40,
71
+ E_TEXT,
72
+ E_X12,
73
+ E_EDIFACT,
74
+ E_BINARY,
75
+ E_MAX
76
+ };
77
+
78
+ unsigned char switchcost[E_MAX][E_MAX] = {
79
+ {0, 1, 1, 1, 1, 2}, // From E_ASCII
80
+ {1, 0, 2, 2, 2, 3}, // From E_C40
81
+ {1, 2, 0, 2, 2, 3}, // From E_TEXT
82
+ {1, 2, 2, 0, 2, 3}, // From E_X12
83
+ {1, 2, 2, 2, 0, 3}, // From E_EDIFACT
84
+ {0, 1, 1, 1, 1, 0}, // From E_BINARY
85
+ };
86
+
87
+ // Annex M placement alorithm low level
88
+ static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b) {
89
+ if (r < 0) {
90
+ r += NR;
91
+ c += 4 - ((NR + 4) % 8);
92
+ }
93
+ if (c < 0) {
94
+ c += NC;
95
+ r += 4 - ((NC + 4) % 8);
96
+ }
97
+ array[r * NC + c] = (p << 3) + b;
98
+ }
99
+
100
+ static void ecc200placementblock(int *array, int NR, int NC, int r, int c, int p) {
101
+ ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7);
102
+ ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6);
103
+ ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5);
104
+ ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4);
105
+ ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3);
106
+ ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2);
107
+ ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1);
108
+ ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0);
109
+ }
110
+
111
+ static void ecc200placementcornerA(int *array, int NR, int NC, int p) {
112
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
113
+ ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6);
114
+ ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5);
115
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
116
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
117
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
118
+ ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
119
+ ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
120
+ }
121
+
122
+ static void ecc200placementcornerB(int *array, int NR, int NC, int p) {
123
+ ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
124
+ ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
125
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
126
+ ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4);
127
+ ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3);
128
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2);
129
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1);
130
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
131
+ }
132
+
133
+ static void ecc200placementcornerC(int *array, int NR, int NC, int p) {
134
+ ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
135
+ ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
136
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
137
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
138
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
139
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
140
+ ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
141
+ ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
142
+ }
143
+
144
+ static void ecc200placementcornerD(int *array, int NR, int NC, int p) {
145
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
146
+ ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6);
147
+ ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5);
148
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
149
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
150
+ ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2);
151
+ ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1);
152
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
153
+ }
154
+
155
+ // Annex M placement alorithm main function
156
+ static void ecc200placement(int *array, int NR, int NC) {
157
+ int r, c, p;
158
+ // invalidate
159
+ for (r = 0; r < NR; r++)
160
+ for (c = 0; c < NC; c++)
161
+ array[r * NC + c] = 0;
162
+ // start
163
+ p = 1;
164
+ r = 4;
165
+ c = 0;
166
+ do {
167
+ // check corner
168
+ if (r == NR && !c)
169
+ ecc200placementcornerA(array, NR, NC, p++);
170
+ if (r == NR - 2 && !c && NC % 4)
171
+ ecc200placementcornerB(array, NR, NC, p++);
172
+ if (r == NR - 2 && !c && (NC % 8) == 4)
173
+ ecc200placementcornerC(array, NR, NC, p++);
174
+ if (r == NR + 4 && c == 2 && !(NC % 8))
175
+ ecc200placementcornerD(array, NR, NC, p++);
176
+ // up/right
177
+ do {
178
+ if (r < NR && c >= 0 && !array[r * NC + c])
179
+ ecc200placementblock(array, NR, NC, r, c, p++);
180
+ r -= 2;
181
+ c += 2;
182
+ } while (r >= 0 && c < NC);
183
+ r++;
184
+ c += 3;
185
+ // down/left
186
+ do {
187
+ if (r >= 0 && c < NC && !array[r * NC + c])
188
+ ecc200placementblock (array, NR, NC, r, c, p++);
189
+ r += 2;
190
+ c -= 2;
191
+ } while (r < NR && c >= 0);
192
+ r += 3;
193
+ c++;
194
+ } while (r < NR || c < NC);
195
+ // unfilled corner
196
+ if (!array[NR * NC - 1])
197
+ array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
198
+ }
199
+
200
+ // calculate and append ecc code, and if necessary interleave
201
+ static void ecc200(unsigned char *binary, int bytes, int datablock, int rsblock) {
202
+ int blocks = (bytes + 2) / datablock, b;
203
+ rs_init_gf(0x12d);
204
+ rs_init_code(rsblock, 1);
205
+ for (b = 0; b < blocks; b++) {
206
+ unsigned char buf[256], ecc[256];
207
+ int n, p = 0;
208
+ for (n = b; n < bytes; n += blocks)
209
+ buf[p++] = binary[n];
210
+ rs_encode(p, buf, ecc);
211
+ p = rsblock - 1; // comes back reversed
212
+ for (n = b; n < rsblock * blocks; n += blocks)
213
+ binary[bytes + n] = ecc[p--];
214
+ }
215
+ }
216
+
217
+ // perform encoding for ecc200, source s len sl, to target t len tl, using optional encoding control string e
218
+ // return 1 if OK, 0 if failed. Does all necessary padding to tl
219
+ char ecc200encode(unsigned char *t, unsigned int tl, const unsigned char *s, const unsigned int sl, char *encoding, int *lenp) {
220
+ char enc = 'a'; // start in ASCII encoding mode
221
+ unsigned int tp = 0, sp = 0;
222
+ if (strlen(encoding) < sl) {
223
+ free(encoding);
224
+ //TODO: Insert return with return code here
225
+ return 0;
226
+ }
227
+ // do the encoding
228
+ while (sp < sl && tp < tl) {
229
+ char newenc = enc; // suggest new encoding
230
+ if (tl - tp <= 1 && (enc == 'c' || enc == 't') || tl - tp <= 2 && enc == 'x')
231
+ enc = 'a'; // auto revert to ASCII
232
+ newenc = tolower(encoding[sp]);
233
+ switch (newenc) {
234
+ // encode character
235
+ case 'c': // C40
236
+ case 't': // Text
237
+ case 'x': // X12
238
+ {
239
+ char out[6];
240
+ unsigned char p = 0;
241
+ const char *e, *s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_", *s3 = 0;
242
+ if (newenc == 'c') {
243
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
244
+ s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
245
+ }
246
+ if (newenc == 't')
247
+ {
248
+ e = " 0123456789abcdefghijklmnopqrstuvwxyz";
249
+ s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
250
+ }
251
+ if (newenc == 'x')
252
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
253
+ do
254
+ {
255
+ unsigned char c = s[sp++];
256
+ char *w;
257
+ if (c & 0x80)
258
+ {
259
+ if (newenc == 'x')
260
+ {
261
+ free(encoding);
262
+ //TODO: Insert rb_raise(rb_eArgError, "cannot encode character in X12", c);
263
+ return 0;
264
+ }
265
+ c &= 0x7f;
266
+ out[p++] = 1;
267
+ out[p++] = 30;
268
+ }
269
+ w = strchr (e, c);
270
+ if (w)
271
+ out[p++] = ((w - e) + 3) % 40;
272
+ else
273
+ {
274
+ if (newenc == 'x')
275
+ {
276
+ free(encoding);
277
+ //TODO: rb_raise(rb_eArgError, "cannot encode character in X12", c);
278
+ return 0;
279
+ }
280
+ if (c < 32)
281
+ { // shift 1
282
+ out[p++] = 0;
283
+ out[p++] = c;
284
+ } else
285
+ {
286
+ w = strchr (s2, c);
287
+ if (w)
288
+ { // shift 2
289
+ out[p++] = 1;
290
+ out[p++] = (w - s2);
291
+ } else
292
+ {
293
+ w = strchr (s3, c);
294
+ if (w)
295
+ {
296
+ out[p++] = 2;
297
+ out[p++] = (w - s3);
298
+ } else
299
+ {
300
+ free(encoding);
301
+ //TODO: rb_raise(rb_eRuntimeError, "this should not be happening!", c);
302
+ return 0;
303
+ }
304
+ }
305
+ }
306
+ }
307
+ if (p == 2 && tp + 2 == tl && sp == sl)
308
+ out[p++] = 0; // shift 1 pad at end
309
+ while (p >= 3)
310
+ {
311
+ int v = out[0] * 1600 + out[1] * 40 + out[2] + 1;
312
+ if (enc != newenc)
313
+ {
314
+ if (enc == 'c' || enc == 't' || enc == 'x')
315
+ t[tp++] = 254; // escape C40/text/X12
316
+ else if (enc == 'x')
317
+ t[tp++] = 0x7C; // escape EDIFACT
318
+ if (newenc == 'c')
319
+ t[tp++] = 230;
320
+ if (newenc == 't')
321
+ t[tp++] = 239;
322
+ if (newenc == 'x')
323
+ t[tp++] = 238;
324
+ enc = newenc;
325
+ }
326
+ t[tp++] = (v >> 8);
327
+ t[tp++] = (v & 0xFF);
328
+ p -= 3;
329
+ out[0] = out[3];
330
+ out[1] = out[4];
331
+ out[2] = out[5];
332
+ }
333
+ }
334
+ while (p && sp < sl);
335
+ }
336
+ break;
337
+ case 'e': // EDIFACT
338
+ {
339
+ char out[4];
340
+ unsigned char p = 0;
341
+ if (enc != newenc) {
342
+ // can only be from C40/Text/X12
343
+ t[tp++] = 254;
344
+ enc = 'a';
345
+ }
346
+ while (sp < sl && tolower (encoding[sp]) == 'e' && p < 4)
347
+ out[p++] = s[sp++];
348
+ if (p < 4) {
349
+ out[p++] = 0x1F;
350
+ enc = 'a';
351
+ } // termination
352
+ t[tp] = ((s[0] & 0x3F) << 2);
353
+ t[tp++] |= ((s[1] & 0x30) >> 4);
354
+ t[tp] = ((s[1] & 0x0F) << 4);
355
+ if (p == 2)
356
+ tp++;
357
+ else {
358
+ t[tp++] |= ((s[2] & 0x3C) >> 2);
359
+ t[tp] = ((s[2] & 0x03) << 6);
360
+ t[tp++] |= (s[3] & 0x3F);
361
+ }
362
+ }
363
+ break;
364
+ case 'a': // ASCII
365
+ if (enc != newenc) {
366
+ if (enc == 'c' || enc == 't' || enc == 'x')
367
+ t[tp++] = 254; // escape C40/text/X12
368
+ else
369
+ t[tp++] = 0x7C; // escape EDIFACT
370
+ }
371
+ enc = 'a';
372
+ if (sl - sp >= 2 && isdigit(s[sp]) && isdigit(s[sp + 1])) {
373
+ t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
374
+ sp += 2;
375
+ } else
376
+ if (s[sp] > 127) {
377
+ t[tp++] = 235;
378
+ t[tp++] = s[sp++] - 127;
379
+ } else
380
+ t[tp++] = s[sp++] + 1;
381
+ break;
382
+ case 'b': // Binary
383
+ {
384
+ int l = 0; // how much to encode
385
+ if (encoding) {
386
+ unsigned int p;
387
+ for (p = sp; p < sl && tolower(encoding[p]) == 'b'; p++)
388
+ l++;
389
+ }
390
+ t[tp++] = 231; // base256
391
+ if (l < 250)
392
+ t[tp++] = l;
393
+ else {
394
+ t[tp++] = 249 + (l / 250);
395
+ t[tp++] = (l % 250);
396
+ }
397
+ while (l-- && tp < tl) {
398
+ t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1; // see annex H
399
+ tp++;
400
+ }
401
+ enc = 'a'; // reverse to ASCII at end
402
+ }
403
+ break;
404
+ default:
405
+ free(encoding);
406
+ //TODO: rb_raise(rb_eArgError, "unknown encoding attempted");
407
+ return 0; // failed
408
+ }
409
+ }
410
+ if (lenp)
411
+ *lenp = tp;
412
+ if (tp < tl && enc != 'a') {
413
+ if (enc == 'c' || enc == 'x' || enc == 't')
414
+ t[tp++] = 254; // escape X12/C40/Text
415
+ else
416
+ t[tp++] = 0x7C; // escape EDIFACT
417
+ }
418
+ if (tp < tl)
419
+ t[tp++] = 129; // pad
420
+ while (tp < tl) {
421
+ // more padding
422
+ int v = 129 + (((tp + 1) * 149) % 253) + 1; // see Annex H
423
+ if (v > 254)
424
+ v -= 254;
425
+ t[tp++] = v;
426
+ }
427
+ if (tp > tl || sp < sl)
428
+ return 0; // did not fit
429
+ return 1; // OK
430
+ }
431
+
432
+ // Creates a encoding list (malloc)
433
+ // returns encoding string
434
+ // if lenp not null, target len stored
435
+ // if error, null returned
436
+ // if exact specified, then assumes shortcuts applicable for exact fit in target
437
+ // 1. No unlatch to return to ASCII for last encoded byte after C40 or Text or X12
438
+ // 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after EDIFACT
439
+ // 3. Final C40 or text encoding exactly in last 2 bytes can have a shift 0 to pad to make a tripple
440
+ // Only use the encoding from an exact request if the len matches the target, otherwise free the result and try again with exact=0
441
+ static char* encmake(const unsigned int l, const unsigned char *s, int *lenp, char exact) {
442
+ char *encoding = 0;
443
+ unsigned int p = l;
444
+ unsigned char e;
445
+ struct {
446
+ short s; // number of bytes of source that can be encoded in a row at this point using this encoding mode
447
+ short t; // number of bytes of target generated encoding from this point to end if already in this encoding mode
448
+ } enc[IEC16022ECC200_MAXBARCODE][E_MAX];
449
+ memset(&enc, 0, sizeof (enc));
450
+ if (!l)
451
+ return ""; // no length
452
+ if (l > IEC16022ECC200_MAXBARCODE)
453
+ return 0; // not valid
454
+ while (p--) {
455
+ unsigned char b = 0;
456
+ char sub;
457
+ int sl, tl, bl, t;
458
+ // consider each encoding from this point
459
+ // ASCII
460
+ sl = tl = 1;
461
+ if (isdigit(s[p]) && p + 1 < l && isdigit(s[p + 1]))
462
+ sl = 2; // double digit
463
+ else
464
+ if (s[p] & 0x80)
465
+ tl = 2; // high shifted
466
+ bl = 0;
467
+ if (p + sl < l)
468
+ for (e = 0; e < E_MAX; e++)
469
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
470
+ bl = t;
471
+ b = e;
472
+ }
473
+ enc[p][E_ASCII].t = tl + bl;
474
+ enc[p][E_ASCII].s = sl;
475
+ if (bl && b == E_ASCII)
476
+ enc[p][b].s += enc[p + sl][b].s;
477
+ // C40
478
+ sub = tl = sl = 0;
479
+ do {
480
+ unsigned char c = s[p + sl++];
481
+ if (c & 0x80) {
482
+ // shift + upper
483
+ sub += 2;
484
+ c &= 0x7F;
485
+ }
486
+ if (c != ' ' && !isdigit (c) && !isupper (c))
487
+ sub++; // shift
488
+ sub++;
489
+ while (sub >= 3) {
490
+ sub -= 3;
491
+ tl += 2;
492
+ }
493
+ } while (sub && p + sl < l);
494
+ if (exact && sub == 2 && p + sl == l) {
495
+ // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
496
+ sub = 0;
497
+ tl += 2;
498
+ }
499
+ if (!sub) {
500
+ // can encode C40
501
+ bl = 0;
502
+ if (p + sl < l)
503
+ for (e = 0; e < E_MAX; e++)
504
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_C40][e]) < bl || !bl)) {
505
+ bl = t;
506
+ b = e;
507
+ }
508
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
509
+ // special case, switch to ASCII for last bytes
510
+ bl = 1;
511
+ b = E_ASCII;
512
+ }
513
+ enc[p][E_C40].t = tl + bl;
514
+ enc[p][E_C40].s = sl;
515
+ if (bl && b == E_C40)
516
+ enc[p][b].s += enc[p + sl][b].s;
517
+ }
518
+ // Text
519
+ sub = tl = sl = 0;
520
+ do {
521
+ unsigned char c = s[p + sl++];
522
+ if (c & 0x80) {
523
+ // shift + upper
524
+ sub += 2;
525
+ c &= 0x7F;
526
+ }
527
+ if (c != ' ' && !isdigit (c) && !islower (c))
528
+ sub++; // shift
529
+ sub++;
530
+ while (sub >= 3) {
531
+ sub -= 3;
532
+ tl += 2;
533
+ }
534
+ } while (sub && p + sl < l);
535
+ if (exact && sub == 2 && p + sl == l) {
536
+ // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
537
+ sub = 0;
538
+ tl += 2;
539
+ }
540
+ if (!sub && sl) {
541
+ // can encode Text
542
+ bl = 0;
543
+ if (p + sl < l)
544
+ for (e = 0; e < E_MAX; e++)
545
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_TEXT][e]) < bl || !bl)) {
546
+ bl = t;
547
+ b = e;
548
+ }
549
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
550
+ // special case, switch to ASCII for last bytes
551
+ bl = 1;
552
+ b = E_ASCII;
553
+ }
554
+ enc[p][E_TEXT].t = tl + bl;
555
+ enc[p][E_TEXT].s = sl;
556
+ if (bl && b == E_TEXT)
557
+ enc[p][b].s += enc[p + sl][b].s;
558
+ }
559
+ // X12
560
+ sub = tl = sl = 0;
561
+ do {
562
+ unsigned char c = s[p + sl++];
563
+ if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit(c) && !isupper(c)) {
564
+ sl = 0;
565
+ break;
566
+ }
567
+ sub++;
568
+ while (sub >= 3) {
569
+ sub -= 3;
570
+ tl += 2;
571
+ }
572
+ } while (sub && p + sl < l);
573
+ if (!sub && sl) {
574
+ // can encode X12
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_X12][e]) < bl || !bl)) {
579
+ bl = t;
580
+ b = e;
581
+ }
582
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
583
+ // special case, switch to ASCII for last bytes
584
+ bl = 1;
585
+ b = E_ASCII;
586
+ }
587
+ enc[p][E_X12].t = tl + bl;
588
+ enc[p][E_X12].s = sl;
589
+ if (bl && b == E_X12)
590
+ enc[p][b].s += enc[p + sl][b].s;
591
+ }
592
+ // EDIFACT
593
+ sl = bl = 0;
594
+ if (s[p + 0] >= 32 && s[p + 0] <= 94) {
595
+ // can encode 1
596
+ char bs = 0;
597
+ if (p + 1 == l && (!bl || bl < 2)) {
598
+ bl = 2;
599
+ bs = 1;
600
+ } else
601
+ for (e = 0; e < E_MAX; e++)
602
+ if (e != E_EDIFACT && enc[p + 1][e].t && ((t = 2 + enc[p + 1][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
603
+ // E_ASCII as allowed for unlatch
604
+ bs = 1;
605
+ bl = t;
606
+ b = e;
607
+ }
608
+ if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94) {
609
+ // can encode 2
610
+ if (p + 2 == l && (!bl || bl < 2)) {
611
+ bl = 3;
612
+ bs = 2;
613
+ } else
614
+ for (e = 0; e < E_MAX; e++)
615
+ if (e != E_EDIFACT && enc[p + 2][e].t && ((t = 3 + enc[p + 2][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
616
+ // E_ASCII as allowed for unlatch
617
+ bs = 2;
618
+ bl = t;
619
+ b = e;
620
+ }
621
+ if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94) {
622
+ // can encode 3
623
+ if (p + 3 == l && (!bl || bl < 3)) {
624
+ bl = 3;
625
+ bs = 3;
626
+ } else
627
+ for (e = 0; e < E_MAX; e++)
628
+ if (e != E_EDIFACT && enc[p + 3][e].t && ((t = 3 + enc[p + 3][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
629
+ // E_ASCII as allowed for unlatch
630
+ bs = 3;
631
+ bl = t;
632
+ b = e;
633
+ }
634
+ if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94) {
635
+ // can encode 4
636
+ if (p + 4 == l && (!bl || bl < 3)) {
637
+ bl = 3;
638
+ bs = 4;
639
+ } else {
640
+ for (e = 0; e < E_MAX; e++)
641
+ if (enc[p + 4][e].t && ((t = 3 + enc[p + 4][e].t + switchcost[E_EDIFACT][e]) < bl || !bl)) {
642
+ bs = 4;
643
+ bl = t;
644
+ b = e;
645
+ }
646
+ if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl) {
647
+ // special case, switch to ASCII for last 1 ot two bytes
648
+ bs = 4;
649
+ bl = t;
650
+ b = E_ASCII;
651
+ }
652
+ }
653
+ }
654
+ }
655
+ }
656
+ enc[p][E_EDIFACT].t = bl;
657
+ enc[p][E_EDIFACT].s = bs;
658
+ if (bl && b == E_EDIFACT)
659
+ enc[p][b].s += enc[p + bs][b].s;
660
+ }
661
+ // Binary
662
+ bl = 0;
663
+ for (e = 0; e < E_MAX; e++)
664
+ if (enc[p + 1][e].t && ((t = enc[p + 1][e].t + switchcost[E_BINARY][e] + ((e == E_BINARY && enc[p + 1][e].t == 249) ? 1 : 0)) < bl || !bl)) {
665
+ bl = t;
666
+ b = e;
667
+ }
668
+ enc[p][E_BINARY].t = 1 + bl;
669
+ enc[p][E_BINARY].s = 1;
670
+ if (bl && b == E_BINARY)
671
+ enc[p][b].s += enc[p + 1][b].s;
672
+ }
673
+ encoding = malloc(sizeof(char)*(l + 1));
674
+ p = 0;
675
+ {
676
+ unsigned char cur = E_ASCII; // starts ASCII
677
+ while (p < l) {
678
+ int t, m = 0;
679
+ unsigned char b = 0;
680
+ for (e = 0; e < E_MAX; e++)
681
+ if (enc[p][e].t && ((t = enc[p][e].t + switchcost[cur][e]) < m || t == m && e == cur || !m)) {
682
+ b = e;
683
+ m = t;
684
+ }
685
+ cur = b;
686
+ m = enc[p][b].s;
687
+ if (!p && lenp)
688
+ *lenp = enc[p][b].t;
689
+ while (p < l && m--)
690
+ encoding[p++] = encchr[b];
691
+ }
692
+ }
693
+ encoding[p] = 0;
694
+ return encoding;
695
+ }
696
+
697
+ void iec16022init(int *Wptr, int *Hptr, const char *barcode) {
698
+ if(Wptr == NULL || Hptr == NULL || barcode == NULL)
699
+ return;
700
+
701
+ int barcodelen = (int)strlen(barcode) + 1;
702
+ struct ecc200matrix_s *matrix;
703
+ for (matrix = ecc200matrix; matrix->bytes < barcodelen; matrix++);
704
+ *Wptr = matrix->W;
705
+ *Hptr = matrix->H;
706
+ }
707
+
708
+ // Main encoding function
709
+ // Returns the grid (malloced) containing the matrix. L corner at 0,0.
710
+ // Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
711
+ // Takes barcodelen and barcode to be encoded
712
+ // Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
713
+ // If lenp not null, then the length of encoded data before any final unlatch or pad is stored
714
+ // If maxp not null, then the max storage of this size code is stored
715
+ // If eccp not null, then the number of ecc bytes used in this size is stored
716
+ // Returns 0 on error (writes to stderr with details).
717
+ unsigned char* iec16022ecc200(int *Wptr, int *Hptr, char **encodingptr, const int barcodelen, const unsigned char *barcode, int *lenp, int *maxp, int *eccp) {
718
+ // GS
719
+ // max semacode size is 3116 (from iec16022ecc200.h)
720
+ // we over compensate and check that the input is within this length
721
+ // to avoid any buffer overflow conditions.
722
+ unsigned char binary[4096]; // encoded raw data and ecc to place in barcode
723
+ int W = 0, H = 0;
724
+ char *encoding = 0;
725
+ unsigned char *grid = 0;
726
+ struct ecc200matrix_s *matrix;
727
+
728
+ // GS
729
+ // using the length from the 144x144 semacode in the matrix
730
+ // I don't trust the 3116 maximum length value ... and
731
+ // besides how many characters do you really need in a
732
+ // semacode?
733
+ if(barcodelen > 1556) {
734
+ //TODO: rb_raise(rb_eRangeError, "barcode is too long (> 1556 chars)");
735
+ return NULL;
736
+ }
737
+
738
+ memset(binary, 0, sizeof(binary));
739
+ if (encodingptr)
740
+ encoding = *encodingptr;
741
+ if (Wptr)
742
+ W = *Wptr;
743
+ if (Hptr)
744
+ H = *Hptr;
745
+
746
+ // encoding
747
+ if (W) {
748
+ // known size
749
+ for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++);
750
+ if (!matrix->W) {
751
+ //TODO: rb_raise(rb_eRangeError, "invalid size for barcode");
752
+ return 0;
753
+ }
754
+ if (!encoding) {
755
+ int len;
756
+ char *e = encmake(barcodelen, barcode, &len, 1);
757
+ if (e && len != matrix->bytes) {
758
+ // try not an exact fit
759
+ free (e);
760
+ e = encmake (barcodelen, barcode, &len, 0);
761
+ if (len > matrix->bytes) {
762
+ free(e);
763
+ //TODO: rb_raise(rb_eRangeError, "cannot make barcode fit");
764
+ return 0;
765
+ }
766
+ }
767
+ encoding = e;
768
+ }
769
+ } else {
770
+ // find size
771
+ if (encoding) {
772
+ // find one that fits chosen encoding
773
+ for (matrix = ecc200matrix; matrix->W; matrix++)
774
+ if (ecc200encode(binary, matrix->bytes, barcode, barcodelen, encoding, 0))
775
+ break;
776
+ } else {
777
+ int len;
778
+ char *e;
779
+ e = encmake(barcodelen, barcode, &len, 1);
780
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes != len; matrix++);
781
+ if (e && !matrix->W) {
782
+ // try for non exact fit
783
+ free (e);
784
+ e = encmake(barcodelen, barcode, &len, 0);
785
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++);
786
+ }
787
+ encoding = e;
788
+ }
789
+ if (!matrix->W) {
790
+ free(encoding);
791
+ //TODO: rb_raise(rb_eRangeError, "overlong barcode");
792
+ return 0;
793
+ }
794
+ W = matrix->W;
795
+ H = matrix->H;
796
+ }
797
+ if (!ecc200encode(binary, matrix->bytes, barcode, barcodelen, encoding, lenp)) {
798
+ free(encoding);
799
+ //TODO: rb_raise(rb_eRangeError, "barcode too long for expected encoding");
800
+ return 0;
801
+ }
802
+ // ecc code
803
+ ecc200(binary, matrix->bytes, matrix->datablock, matrix->rsblock);
804
+ {
805
+ // placement
806
+ int x, y, NC, NR, *places;
807
+ NC = W - 2 * (W / matrix->FW);
808
+ NR = H - 2 * (H / matrix->FH);
809
+ places = malloc(sizeof(int) * NC * NR);
810
+ ecc200placement(places, NR, NC);
811
+ grid = malloc(sizeof(char) * W * H);
812
+ memset (grid, 0, W * H);
813
+ for (y = 0; y < H; y += matrix->FH) {
814
+ for (x = 0; x < W; x++)
815
+ grid[y * W + x] = 1;
816
+ for (x = 0; x < W; x += 2)
817
+ grid[(y + matrix->FH - 1) * W + x] = 1;
818
+ }
819
+ for (x = 0; x < W; x += matrix->FW) {
820
+ for (y = 0; y < H; y++)
821
+ grid[y * W + x] = 1;
822
+ for (y = 0; y < H; y += 2)
823
+ grid[y * W + x + matrix->FW - 1] = 1;
824
+ }
825
+ for (y = 0; y < NR; y++) {
826
+ for (x = 0; x < NC; x++) {
827
+ int v = places[(NR - y - 1) * NC + x];
828
+ if (v == 1 || v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))
829
+ grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
830
+ }
831
+ }
832
+ free (places);
833
+ }
834
+ if (Wptr)
835
+ *Wptr = W;
836
+ if (Hptr)
837
+ *Hptr = H;
838
+ if (encodingptr)
839
+ *encodingptr = encoding;
840
+ else
841
+ free(encoding); // get rid of this if we aren't returning it
842
+ if (maxp)
843
+ *maxp = matrix->bytes;
844
+ if (eccp)
845
+ *eccp = (matrix->bytes + 2) / matrix->datablock * matrix->rsblock;
846
+ return grid;
847
+ }