data_matrix 0.1.1

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