File Coverage

blib/lib/Barcode/DataMatrix/Engine.pm
Criterion Covered Total %
statement 380 516 73.6
branch 129 252 51.1
condition 67 152 44.0
subroutine 37 39 94.8
pod 31 31 100.0
total 644 990 65.0


line stmt bran cond sub pod time code
1             package Barcode::DataMatrix::Engine;
2              
3             =head1 Barcode::DataMatrix::Engine
4              
5             The engine which generates the data matrix bitmap.
6              
7             =cut
8              
9 2     2   11 use strict;
  2         5  
  2         56  
10 2     2   9 use warnings;
  2         5  
  2         57  
11 2     2   10 no warnings qw(uninitialized);
  2         4  
  2         61  
12 2     2   986 use Barcode::DataMatrix::Reed;
  2         5  
  2         54  
13 2     2   1096 use Barcode::DataMatrix::Constants ();
  2         6  
  2         42  
14 2     2   1141 use Barcode::DataMatrix::CharDataFiller ();
  2         4  
  2         41  
15 2     2   2004 use Data::Dumper;$Data::Dumper::Useqq = 1;
  2         14753  
  2         143  
16              
17             =head2 DEBUG
18              
19             Turn on/off general debugging information.
20              
21             =cut
22              
23 2     2   12 use constant DEBUG => 0;
  2         4  
  2         14310  
24              
25             our %DEBUG = (
26             ENC => 0,
27             EAUTO => 0,
28             CALC => 0,
29             TRACE => 0,
30             B256 => 0
31             );
32             our (@FORMATS,@C1);
33              
34             *FORMATS = \@Barcode::DataMatrix::Constants::FORMATS;
35             *C1 = \@Barcode::DataMatrix::Constants::C1;
36              
37             =head2 E_ASCII
38              
39             Represent the ASCII encoding type.
40              
41             =cut
42              
43 126     126 1 378 sub E_ASCII { 0 }
44              
45             =head2 E_C40
46              
47             Represent the C40 encoding type. (upper case alphanumeric)
48              
49             =cut
50              
51 380     380 1 1155 sub E_C40 { 1 }
52              
53             =head2 E_TEXT
54              
55             Represent the TEXT encoding type. (lower case alphanumeric)
56              
57             =cut
58              
59 156     156 1 617 sub E_TEXT { 2 }
60              
61             =head2 E_BASE256
62              
63             Represent the BASE256 encoding type.
64              
65             =cut
66              
67 78     78 1 186 sub E_BASE256 { 3 }
68              
69             =head2 E_NONE
70              
71             Represent the when there is no encoding type.
72              
73             =cut
74              
75 8     8 1 32 sub E_NONE { 4 }
76              
77             =head2 E_AUTO
78              
79             Represent the when the encoding type is automatically set.
80              
81             =cut
82              
83 28     28 1 95 sub E_AUTO { 5 }
84              
85             our $N = 255;
86              
87             =head2 Types
88              
89             Return a list of encoding types.
90              
91             =cut
92              
93             sub Types {
94 12     12 1 36 return qw( ASCII C40 TEXT BASE256 NONE AUTO );
95             }
96              
97             =head2 stringToType (type_name)
98              
99             Return the integer representing the type from the type name.
100              
101             =cut
102              
103             sub stringToType {
104 54     54 1 100 my $m = 'E_'.shift;
105 54         73 return eval { __PACKAGE__->$m(); };
  54         138  
106             }
107              
108             =head2 typeToString (type_integer)
109              
110             Return the type name from the integer representing the type.
111              
112             =cut
113              
114             sub typeToString {
115 12     12 1 20 my $i = shift;
116 12         25 for (Types) {
117 42 100 66     69 return $_ if stringToType($_) == $i and defined $i;
118             }
119 0         0 return 'UNK';
120             }
121              
122             our @encName = map { typeToString $_ } 0..5;
123              
124             =head2 stringToFormat (format_string)
125              
126             Convert a "width x height" format string into an internal format specification.
127              
128             =cut
129              
130             sub stringToFormat {
131 12     12 1 18 my $sz = shift;
132 12 50       78 return unless $sz;
133 0         0 my ($w,$h) = map { +int } split /\s*x\s*/,$sz,2;
  0         0  
134 0         0 my $r;
135 0         0 for my $i (0..$#FORMATS) {
136 0 0 0     0 $r = $i,last if $FORMATS[$i][0] == $w and $FORMATS[$i][1] == $h;
137             }
138 0 0       0 die "Format not supported ($sz)\n" unless defined $r;
139 0         0 return $r;
140             }
141              
142             =head2 setType (type_name)
143              
144             Set the encoding type from the given type name.
145              
146             =cut
147              
148             sub setType {
149 12     12 1 25 my $self = shift;
150 12         21 my $type = shift;
151 12         34 my $t = stringToType($type);
152 12 50       39 warn "setType $type => $t\n" if $DEBUG{ENC};
153 12 50       33 $t = E_ASCII unless defined $t;
154 12         29 $self->{encoding} = $self->{currentEncoding} = $t;
155 12 50       31 warn "Have type $t (".typeToString($t).")\n" if $DEBUG{ENC};
156 12         24 return;
157             }
158              
159             =head2 new
160              
161             Construct a C object.
162              
163             =cut
164              
165             sub new {
166 12     12 1 30 my $self = bless{},shift;
167 12         39 $self->init();
168 12 50       46 warn "[CA] new(@_)\n" if $DEBUG{TRACE};
169 12         35 $self->{orig} = $self->{code} = shift; # text
170 12         43 $self->setType(shift); # type of encoding
171 12   50     34 $self->{preferredFormat} = stringToFormat(shift) || -1; # type of format
172 12         40 $self->{as} = [ ]; # additional streams
173 12 50       36 $self->ProcessTilde if (shift); # process tilde
174 12 50       35 return unless ( my $l = length($self->{code}) ); # no data to encode
175 12         369 $self->{ac} = [ split //,$self->{code} ]; # create an char array
176 12         83 $self->{ai} = [ map { +ord } @{ $self->{ac} } ]; # create an int array
  1116         1477  
  12         38  
177 12         59 $self->CreateBitmap();
178 12         79 return $self;
179             }
180              
181             =head2 init
182              
183             Initialize some of the basic C data.
184              
185             =cut
186              
187             sub init {
188 12     12 1 18 my $self = shift;
189 12         36 my %p = (
190             processTilde => 0,#0
191             encoding => E_ASCII,
192             preferredFormat => -1,
193             currentEncoding => E_ASCII,
194             C49rest => 0,
195             );
196 12         50 for (keys %p){
197 60         129 $self->{$_} = $p{$_};
198             }
199             }
200              
201             =head2 ProcessTilde
202              
203             Handle special or control characters, which are prefixed by a tilde C<~>
204             when encoding.
205              
206             =cut
207              
208             sub ProcessTilde {
209 0     0 1 0 my $self = shift;
210 0         0 my $s = $self->{code};
211 0         0 my $as = $self->{as};
212 0         0 for ($s) {
213 0         0 s{~d(\d{3})}{ chr($1) }ge;
  0         0  
214 0         0 s{~d.{3}}{}g;
215 0         0 for my $i (0,1,4,5) {
216 0         0 s{^(.{$i})~1}{ $as->[$-[0]+$i]=''; $1."\350"}ge;
  0         0  
  0         0  
217             }
218 0         0 s{~1}{\035}g;
219 0         0 s{~2(.{3})}{ $as->[$-[0]] = $1; "\351".$2 }e;
  0         0  
  0         0  
220 0         0 s{^~3}{ $as->[0] = ''; "\352" }e;
  0         0  
  0         0  
221 0         0 s{^~5}{ $as->[0] = ''; "\354" }e;
  0         0  
  0         0  
222 0         0 s{^~6}{ $as->[0] = ''; "\355" }e;
  0         0  
  0         0  
223 0         0 s{~7(.{6})}{do{
  0         0  
224 0         0 my $d = int $1;
225             #warn "There is $d got from $1\n";
226 0 0       0 if ($d < 127) {
    0          
227 0         0 $d = chr($d+1);
228             }
229             elsif($d < 16383) {
230 0         0 $d =
231             chr( ( $d - 127 ) / 254 + 128 ).
232             chr( ( $d - 127 ) % 254 + 1 );
233             }
234             else{
235 0         0 $d =
236             chr( int( ( $d - 16383 ) / 64516 + 192 ) ).
237             chr( int( ( $d - 16383 ) / 254 ) % 254 + 1 ).
238             chr( int( ( $d - 16383 ) % 254 + 1 ) );
239             }
240 0         0 $as->[$-[0]] = $d;
241 0 0       0 warn "PT affect as[$-[0]] = ".join('+', map ord, split //, $d) if $DEBUG{TRACE};
242 0         0 "\361"
243             }}ge;
244 0 0       0 s{~(.)}{$1 eq '~' ? '~' : $1}ge;
  0         0  
245 0 0       0 warn "[C9] ProcessTilde($self->{code}) => ".Dumper($_) if $DEBUG{TRACE};
246 0         0 return $self->{code} = $_;
247             }
248             }
249              
250             =head2 CalcReed (ai, err)
251              
252             Return the message as a Reed-Solomon encoded array.
253              
254             =cut
255              
256             sub CalcReed { # (int ai[], int i, int j) : void
257 16     16 1 29 my ($ai,$err) = @_;
258 16         55 my $rv = Barcode::DataMatrix::Reed::encode($ai,$err);
259 16         237 @$ai = @$rv;
260 16         76 return $ai;
261             }
262              
263             =head2 A253 (i, j)
264              
265             Return padding codewords via the 253-state algorithm.
266              
267             For more information see
268             L.
269              
270             The relevant text for this algorithm is reproduced here.
271              
272             If the symbol is not full, pad Cs are required. After the last data
273             C, the 254 C indicates the end of the datas or the return to ASCII
274             method. First padding C is 129 and next padding Cs are computed with
275             the 253-state algorithm.
276              
277             =head3 The 253-state algorithm
278              
279             Let C

be the number of data Cs from the beginning of the data, C a

280             pseudo random number and C the required pad C.
281              
282             R = ((149 * P) MOD 253) + 1
283             CW = (129 + R) MOD 254
284              
285             =cut
286              
287             sub A253 # C8 (int i, int j) : int
288             {
289 149     149 1 187 my ($i,$j) = @_;
290 149         202 my $l = $i + (149 * $j) % 253 + 1;
291 149 100       354 return $l <= 254 ? $l : $l - 254;
292             }
293              
294             =head2 CreateBitmap
295              
296             Generate and return the bitmap representing the message.
297              
298             =cut
299              
300             sub CreateBitmap #CB (int ai[], String as[]) : int[][]
301             {
302 12     12 1 21 my $self = shift;
303 12         29 my ($ai,$as) = @$self{qw(ai as)};
304 12 50       35 warn "[CB] CreateBitmap(ai[" .join(',',@$ai).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
305 12         23 my $ai1 = [];
306 12         22 my $i = 0;
307 12 100       35 $self->{currentEncoding} = $self->{encoding} if $self->{encoding} != E_AUTO;
308 12         31 for ($self->{encoding}){
309 12 50       33 warn "[CB] Select method for $self->{encoding}, ".typeToString($self->{encoding})."\n" if $DEBUG{ENC};
310 12 100       27 $_ == E_AUTO && do { $i = $self->DetectEncoding($ai1); last;};
  2         7  
  2         5  
311 10 100       23 $_ == E_ASCII && do { $i = $self->EncodeASCII(scalar(@$ai), $ai, $ai1, $as); last;};
  2         8  
  2         3  
312 8 100       17 $_ == E_C40 && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 0, 1, 0); last;};
  2         12  
  2         4  
313 6 100       13 $_ == E_TEXT && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 1, 1, 0); last;};
  2         9  
  2         7  
314 4 100       10 $_ == E_BASE256 && do { $i = $self->EncodeBASE256(scalar(@$ai), [0], $ai, [0], $ai1, 0, $as); last;};
  2         11  
  2         5  
315 2 50       5 $_ == E_NONE && do { $ai1 = [ @$ai ]; $i = @$ai; last };
  2         12  
  2         4  
  2         4  
316             }
317 12 50       32 warn "[CB] selected (ai1[" .join(',',@$ai1).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
318 12         13 DEBUG and print "Use Encoding: " .typeToString($self->{currentEncoding}). "(".typeToString($self->{encoding}).")\n";
319 12 50       26 warn "[CB]: enc res: ".typeToString($self->{encoding}).", " .typeToString($self->{currentEncoding}). "\n" if $DEBUG{ENC};
320 12         17 my $k = 0;
321 12 50       34 if($self->{preferredFormat} != -1) {
322 0         0 $k = $self->{preferredFormat};
323 0 0       0 $k = 0 if $i > $FORMATS[$k][7];
324             }
325 12   66     66 for(; $i > $FORMATS[$k][7] && $k < 30; $k++)
326             {
327 94 100 100     174 next if $self->{currentEncoding} != E_C40 && $self->{currentEncoding} != E_TEXT;
328 46 0 33     116 if($self->{C49rest} == 1 && $ai1->[$i - 2] == 254 && $FORMATS[$k][7] == $i - 1) {
      33        
329 0         0 $ai1->[$i - 2] = $ai1->[$i - 1];
330 0         0 $ai1->[$i - 1] = 0;
331 0         0 $i--;
332 0         0 last;
333             }
334 46 100 33     441 next if($self->{C49rest} != 0 || $ai1->[$i - 1] != 254 || $FORMATS[$k][7] != $i - 1);
      66        
335 2         3 $ai1->[$i - 1] = 0;
336 2         9 $i--;
337 2         5 last;
338             }
339              
340 12 50       27 return if $k == 30;
341 12         15 my $l = $k;
342             @$self{qw(
343             rows
344             cols
345             datarows
346             datacols
347             regions
348             maprows
349             mapcols
350             totaldata
351             totalerr
352             reeddata
353             reederr
354             reedblocks
355 12         23 )} = @{$FORMATS[$l]}[0..11];
  12         104  
356 12         20 DEBUG and print "Format: $self->{rows}x$self->{cols}; Data: $self->{totaldata}; i=$i; blocks = $self->{reedblocks}\n";
357             $ai1->[$i - 1] = 129 if (
358             ($self->{currentEncoding} == E_C40 || $self->{currentEncoding} == E_TEXT )
359             and
360 12 50 100     77 $self->{C49rest} == 0 && $i == $self->{totaldata} && $ai1->[$i - 1] == 254
      66        
      66        
      66        
361             );
362 12         15 my $flag = 1;
363 12 50       39 warn "Calc begin from $i..$self->{totaldata} ai1=[@{$ai1}]\n" if $DEBUG{CALC};
  0         0  
364 12         34 for(my $i1 = $i; $i1 < $self->{totaldata}; $i1++) {
365 158 100       364 $ai1->[$i1] = $flag ? 129 : A253(129, $i1 + 1);
366 158         403 $flag = 0;
367             }
368 12         37 return $self->{bitmap} = $self->GenData($self->ecc($l,$ai1));
369             }
370              
371             =head2 ecc (format, ai)
372              
373             Return the ECC200 (DataMatrix) array, formatted for the appropriate matrix
374             size.
375              
376             =cut
377              
378             sub ecc {
379 12     12 1 17 my $self = shift;
380 12         16 my $format = shift;
381 12         16 my $ai = shift;
382 12         21 my ($data,$err,$blocks) = @{$FORMATS[$format]}[9..11];
  12         44  
383 12         15 $blocks--;$data--;
  12         15  
384 12 50       31 warn "ECC: ai=[@{$ai}], blocks=$blocks\n" if $DEBUG{CALC};
  0         0  
385 12         27 my @blocks = map {[]} 0..$blocks;
  16         37  
386 12         22 my $block = 0;
387 12         56 for (@$ai) {
388 1228         1289 push @{$blocks[$block++]}, $_;
  1228         1939  
389 1228 100       2608 $block = 0 if $block > $blocks;
390             }
391 12 50       35 warn "Calc blocks=".Dumper \@blocks if $DEBUG{CALC};
392 12         31 for (0..$#blocks) {
393 16         17 $#{ $blocks[$_] } = $data; # correct padding
  16         54  
394 16 50 33     50 if($self->{rows} == 144 and $_ > 7) {
395 0         0 $#{$blocks[$_]} -= 1;
  0         0  
396             }
397              
398 16         41 CalcReed($blocks[$_], $err);
399             }
400             warn "Calc reed=\n".
401 12 50       37 join "\n", map { '['.join(',',@$_).']' } @blocks if $DEBUG{CALC};
  0         0  
402 12         15 my @rv;
403 12         32 for my $n (0..$data+$err) {
404 1130         1690 for my $b (0..$#blocks) {
405 1758 50       1806 if ( $n < @{$blocks[$b]} ) { # 144 fix
  1758         3882  
406 1758         3268 push @rv, $blocks[$b][$n];
407             }
408             }
409             }
410 12         101 return \@rv;
411             }
412              
413             =head2 isIDigit (character_code)
414              
415             Return true if the character code represents a digit.
416              
417             =cut
418              
419             sub isIDigit { # C1
420 494     494 1 604 my $i = shift;
421 494 50 33     2592 return ( $i >= 48 && $i <= 57 ) ? 1 : 0;
422             }
423              
424             =head2 isILower (character_code)
425              
426             Return true if the character code represents a lower case letter.
427              
428             =cut
429              
430             sub isILower {
431 308     308 1 343 my $i = shift;
432 308 50 33     1001 return ( $i >= ord('a') && $i <= ord('z') ) ? 1 : 0;
433             }
434              
435             =head2 isIUpper (character_code)
436              
437             Return true if the character code represents an upper case letter.
438              
439             =cut
440              
441             sub isIUpper {
442 308     308 1 367 my $i = shift;
443 308 50 33     1498 return ( $i >= ord('A') && $i <= ord('Z') ) ? 1 : 0;
444             }
445              
446             =head2 DetectEncoding
447              
448             Detect the encoding type.
449              
450             =cut
451              
452             sub DetectEncoding() #C4 (int i, int ai[], int ai1[], String as[]) : int
453             {
454 2     2 1 4 my $self = shift;
455 2 50       7 warn "[C4] DetectEncoding(@_)\n" if $DEBUG{TRACE};
456 2         4 my $ai = $self->{ai};
457 2         5 my $i = scalar (@$ai);
458 2         4 my $as = $self->{as};
459 2         3 my $ai1 = shift;
460 2         4 my $ai2 = [ ];
461 2         4 my $ai3 = [ ];
462 2         3 my $flag = 0;
463 2         3 my $j1 = 0;
464 2         5 my $k1 = E_ASCII;
465 2         72 my $ai4 = [ 0 ];
466 2         5 my $l2 = E_ASCII;
467 2         3 my $as1 = [ ];
468 2         4 my $iterator = 0;
469 2         5 $self->{currentEncoding} = E_ASCII;
470 2 50       6 warn("DetectENC: starting from ".$encName[$self->{currentEncoding}]."\n") if $DEBUG{EAUTO};
471 2         7 while($iterator < $i) { # while iterator less than length of data
472 2 50       6 warn("DetectENC: at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
473 2   66     7 while($self->{currentEncoding} == E_ASCII and $iterator < $i) {
474 2 50       7 warn("DetectENC: while at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
475 2         4 my $flag1 = 0;
476 2 50 33     10 if(
      33        
477             $iterator + 1 < $i
478             and isIDigit($ai->[$iterator])
479             and isIDigit($ai->[$iterator + 1])
480             ){
481 0 0       0 warn("DetectENC: 2dig $ai->[$iterator]+$ai->[$iterator+1] at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
482 0 0       0 $ai1->[$j1++] = 254 if($l2 != E_ASCII);
483 0         0 $ai2->[0] = $ai->[$iterator];
484 0         0 $ai2->[1] = $ai->[$iterator + 1];
485 0         0 my $j = $self->EncodeASCII(2, $ai2, $ai3, $as1);
486 0         0 splice(@$ai1,$j1,$j, @$ai3[0 .. $j-1 ]);
487 0         0 $j1 += $j;
488 0         0 $iterator++;
489 0         0 $iterator++;
490 0         0 $flag1 = 1;
491 0         0 $l2 = E_ASCII;
492             }
493 2 50       5 if(!$flag1) {
494 2 50       6 warn("DetectENC: !dig !flag1 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
495 2         9 my $l1 = $self->SelectEncoding( $iterator );
496 2 50       5 if( $l1 != E_ASCII) {
497 2 50       6 warn("DetectENC: $encName[$self->{currentEncoding}] => $encName[$l1]\n") if $DEBUG{EAUTO};
498 2         3 $l2 = $self->{currentEncoding};
499 2         5 $self->{currentEncoding} = $l1;
500             }
501             }
502 2 50 33     9 if(!$flag1 and $self->{currentEncoding} == E_ASCII){
503 0 0       0 $ai1->[$j1++] = 254 if($l2 != E_ASCII);
504 0         0 $ai2->[0] = $ai->[$iterator];
505 0         0 $as1->[0] = $as->[$iterator];
506 0         0 my $k = $self->EncodeASCII(1, $ai2, $ai3, $as1);
507 0         0 $as1->[0] = undef;
508 0         0 splice(@$ai1,$j1,$k, @$ai3[0 .. $k-1 ]);
509 0         0 $j1 += $k;
510 0         0 $iterator++;
511 0         0 $l2 = E_ASCII;
512             }
513             }
514 2 50       7 warn("DetectENC: after while at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
515 2         2 my $i2;
516 2   66     6 for(; $self->{currentEncoding} == E_C40 and $iterator < $i; $self->{currentEncoding} = $i2) {
517 62         78 $ai4->[0] = $iterator;
518 62         118 my $l = $self->EncodeC40TEXT($i, $ai4, $ai, $ai3, 0, $l2 != E_C40, 1);
519 62         87 $iterator = $ai4->[0];
520 62         143 splice(@$ai1,$j1,$l, @$ai3[0 .. $l-1 ]);
521 62         81 $j1 += $l;
522 62         118 $i2 = $self->SelectEncoding($iterator);
523 62         150 $l2 = $self->{currentEncoding};
524             }
525 2 50       6 warn("DetectENC: after C40 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
526              
527 2         2 my $j2;
528 2   33     13 for(; $self->{currentEncoding} == E_TEXT and $iterator < $i; $self->{currentEncoding} = $j2) {
529 0         0 $ai4->[0] = $iterator;
530 0         0 my $i1 = $self->EncodeC40TEXT($i, $ai4, $ai, $ai3, 1, $l2 != E_TEXT, 1);
531 0         0 $iterator = $ai4->[0];
532 0         0 splice(@$ai1,$j1,$i1, @$ai3[0 .. $i1-1 ]);
533 0         0 $j1 += $i1;
534 0         0 $j2 = $self->SelectEncoding($iterator);
535 0         0 $l2 = $self->{currentEncoding};
536             }
537 2 50       6 warn("DetectENC: after TEXT at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
538              
539 2 50       6 if($self->{currentEncoding} == E_BASE256) {
540 0         0 $ai4->[0] = $iterator;
541 0         0 $j1 = $self->EncodeBASE256($i, $ai4, $ai, [$j1], $ai1, 1);
542 0         0 $iterator = $ai4->[0];
543 0         0 my $k2 = $self->SelectEncoding($iterator);
544 0         0 $l2 = $self->{currentEncoding};
545 0         0 $self->{currentEncoding} = $k2;
546             }
547 2 50       9 warn("DetectENC: after B256 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
548             }
549 2         6 return $j1;
550             }
551              
552             =head2 EncodeASCII (i, ai, ai1, as)
553              
554             Encode the message as ASCII.
555              
556             =cut
557              
558             sub EncodeASCII { #CE (int i; int ai[], int ai1[], String as[]) : int
559 2     2 1 4 my $self = shift;
560 2 50       6 warn "[CE] EncodeASCII(@_)\n" if $DEBUG{TRACE};
561 2         4 my ($i,$ai,$ai1,$as) = @_;
562 2 50       8 warn "[CE] ai:{".join(" ",grep{+defined}@$ai)."}; ai1:{".join(" ",grep{+defined}@$ai1)."}; as:{".join(" ",grep{+defined}@$as)."}\n" if $DEBUG{ENC};
  0         0  
  0         0  
  0         0  
563 2         3 my $j = 0;
564 2         3 my $flag = 0;
565 2         7 for(my $k = 0; $k < $i; $k++) {
566 186         207 my $flag1 = 0;
567 186 50 66     550 if(
      33        
568             $k < $i - 1
569             and isIDigit($ai->[$k])
570             and isIDigit($ai->[$k+1])
571             ) {
572 0         0 my $l = ($ai->[$k] - 48) * 10 + ($ai->[$k + 1] - 48);
573 0         0 $ai1->[$j++] = 130 + $l;
574 0         0 $k++;
575 0         0 $flag1 = 1;
576             }
577 186 50 33     764 if(!$flag1 and defined $as->[$k]) {
578 0 0 0     0 if(
      0        
      0        
579             $ai->[$k] == 234
580             or $ai->[$k] == 237
581             or $ai->[$k] == 236
582             or $ai->[$k] == 232
583             ) {
584 0         0 $ai1->[$j++] = $ai->[$k];
585 0         0 $flag1 = 1;
586             }
587 0 0 0     0 if($ai->[$k] == 233 || $ai->[$k] == 241) {
588 0         0 $ai1->[$j++] = $ai->[$k];
589 0         0 for(my $i1 = 0; $i1 < length $as->[$k]; $i1++){
590 0         0 $ai1->[$j++] = ord substr($as->[$k],$i1,1);
591             }
592 0         0 $flag1 = 1;
593             }
594             }
595 186 50       343 if(!$flag1){
596 186 50       348 if($ai->[$k] < 128) {
597 186         536 $ai1->[$j++] = $ai->[$k] + 1;
598             } else {
599 0         0 $ai1->[$j++] = 235;
600 0         0 $ai1->[$j++] = ($ai->[$k] - 128) + 1;
601             }
602             }
603             }
604 2 50       8 warn "[CE] end $j ai1:{".join(" ",@$ai1)."};\n" if $DEBUG{ENC};
605 2         5 return $j;
606             }
607              
608             =head2 SelectEncoding (j, ai, i)
609              
610             Select a new encoding type for the message.
611              
612             =cut
613              
614             sub SelectEncoding #C3 (int ai[], int i, int j, String as[]) : int # DefineEncoding??
615             #iterator, ai, encoding
616             {
617             #(iterator[,ai[,encoding]])
618             #(ai,i: encoding,j: iterator,as)
619 64     64 1 82 my $self = shift;
620 64 50       136 warn "[C3] SelectEncoding(@_)\n" if $DEBUG{TRACE};
621              
622 64         75 my $j = shift;
623              
624 64         73 my $ai = shift;
625 64 50       138 $ai = $self->{ai} unless defined $ai;
626              
627 64   33     159 my $i = shift || $self->{currentEncoding};
628 64 50       111 $i = $self->{currentEncoding} unless defined $i;
629              
630 64         91 my $as = $self->{as};
631 64         75 my $d = 0.0;
632 64         67 my $d2 = 1.0;
633 64         80 my $d3 = 1.0;
634 64         68 my $d4 = 1.25;
635 64         73 my $k = $j;
636 64 100       109 if($i != E_ASCII)
637             {
638 62         74 $d = 1.0;
639 62         68 $d2 = 2.0;
640 62         64 $d3 = 2.0;
641 62         74 $d4 = 2.25;
642             }
643 64 100       116 $d2 = 0.0 if $i == E_C40;
644 64 50       114 $d3 = 0.0 if $i == E_TEXT;
645 64 50       114 $d4 = 0.0 if $i == E_BASE256;
646 64         164 for(; $j < @$ai; $j++)
647             {
648 308 0 33     616 warn "SelectEncoding: have as[$j]: $as->[$j]\n" if defined $as->[$j] and $DEBUG{EAUTO};
649 308         348 my $c = $ai->[$j];
650 308 50       562 return E_ASCII if defined $as->[$j];
651              
652 308 50       527 if ( isIDigit($c) ) { $d += 0.5 }
  0 50       0  
653 0         0 elsif ( $c > 127 ) { $d = int( $d + 0.5 ) + 2; }
654 308         459 else { $d = int( $d + 0.5 ) + 1; }
655              
656 308 50       347 if ( @{ $C1[$c] } == 1 ) { $d2 += 0.66000000000000003; }
  308 0       674  
  308         360  
657 0         0 elsif ( $c > 127 ) { $d2 += 2.6600000000000001; }
658 0         0 else { $d2 += 1.3300000000000001; }
659 308         362 my $c1 = $c;
660 308 50       514 if( isIUpper($c) ) { $c1 = ord lc chr $c; }
  308         416  
661 308 50       563 if( isILower($c) ) { $c1 = ord uc chr $c; }
  0         0  
662              
663 308 50       373 if ( @{ $C1[$c1] } == 1) { $d3 += 0.66000000000000003; }
  308 50       829  
  0         0  
664 0         0 elsif ( $c1 > 127 ) { $d3 += 2.6600000000000001; }
665 308         365 else { $d3 += 1.3300000000000001; }
666              
667 308         408 $d4++;
668              
669 308 100       969 if($j - $k >= 4) {
670 62 0 33     171 return E_ASCII if $d + 1.0 <= $d2 and $d + 1.0 <= $d3 and $d + 1.0 <= $d4;
      33        
671 62 50       129 return E_BASE256 if $d4 + 1.0 <= $d;
672 62 50 33     251 return E_BASE256 if $d4 + 1.0 < $d3 and $d4 + 1.0 < $d2;
673 62 0 33     153 return E_TEXT if $d3 + 1.0 < $d and $d3 + 1.0 < $d2 and $d3 + 1.0 < $d4;
      33        
674 62 50 66     419 return E_C40 if $d2 + 1.0 < $d and $d2 + 1.0 < $d3 and $d2 + 1.0 < $d4;
      66        
675             }
676             }
677              
678 4         7 $d = int( $d + 0.5 );
679 4         6 $d2 = int( $d2 + 0.5 );
680 4         6 $d3 = int( $d3 + 0.5 );
681 4         6 $d4 = int( $d4 + 0.5 );
682 4 0 33     11 return E_ASCII if $d <= $d2 and $d <= $d3 and $d <= $d4;
      33        
683 4 0 33     11 return E_TEXT if $d3 < $d and $d3 < $d2 and $d3 < $d4;
      33        
684 4 0 33     12 return E_BASE256 if $d4 < $d and $d4 < $d3 and $d4 < $d2;
      33        
685 4         8 return E_C40;
686             }
687              
688             =head2 EncodeC40TEXT (i, ai, ai1, ai2, flag, flag1, flag2)
689              
690             Encode the message as C40/TEXT.
691              
692             =cut
693              
694             sub EncodeC40TEXT { # C6 #(int i, int ai[], int ai1[], int ai2[], boolean flag, boolean flag1, boolean flag2) : int
695 66     66 1 91 my $self = shift;
696 66         103 my ($i,$ai,$ai1,$ai2,$flag,$flag1,$flag2) = @_;
697 66         90 my $j = my $k = 0;
698 66         108 my $ai3 = [ 0, 0, 0 ];
699 66         84 my $flag3 = 0;
700 66         89 my $as = [ ];
701 66 100       126 if($flag1) {
702 6 100       19 $ai2->[$j++] = $flag ? 239 : 230;
703             }
704 66         173 for(my $j1 = $ai->[0]; $j1 < $i; $j1++) {
705 558         714 my $l = $ai1->[$j1];
706 558 100       981 if($flag) {
707 186         246 my $s = chr($l);
708 186 50 33     396 $s = uc($s) if($l >= 97 && $l <= 122);
709 186 50 33     737 $s = lc($s) if($l >= 65 && $l <= 90);
710 186         246 $l = ord(substr($s,0,1));
711             }
712 558         742 my $ai4 = $C1[$l];
713 558         927 for my $l1 (0 .. $#$ai4) {
714 744         1049 $ai3->[$k++] = $ai4->[$l1];
715 744 100       1595 if($k == 3) {
716 248         422 my $i2 = $ai3->[0] * 1600 + $ai3->[1] * 40 + $ai3->[2] + 1;
717 248         433 $ai2->[$j++] = int $i2 / 256;
718 248         368 $ai2->[$j++] = $i2 % 256;
719 248         390 $k = 0;
720             }
721             }
722              
723 558 100 100     2340 if($flag2 && $k == 0) {
724 62         89 $self->{C49rest} = $k;
725 62         81 $ai->[0] = $j1 + 1;
726 62 100       129 $ai2->[$j++] = 254 if($ai->[0] == $i);
727 62         159 return $j;
728             }
729             }
730              
731 4         8 $ai->[0] = $i;
732 4 50       8 if($k > 0) {
733 0 0       0 if($k == 1) {
734 0         0 $ai2->[$j++] = 254;
735 0         0 $ai2->[$j++] = $ai1->[$i - 1] + 1;
736 0         0 return $j;
737             }
738 0 0       0 if($k == 2) {
739 0         0 $ai3->[2] = 0;
740 0         0 my $k1 = $ai3->[0] * 1600 + $ai3->[1] * 40 + $ai3->[2] + 1;
741 0         0 $ai2->[$j++] = int $k1 / 256;
742 0         0 $ai2->[$j++] = $k1 % 256;
743 0         0 $ai2->[$j++] = 254;
744 0         0 $self->{C49rest} = $k;
745 0         0 return $j;
746             }
747             } else {
748 4         10 $ai2->[$j++] = 254;
749             }
750 4         6 $self->{C49rest} = $k;
751 4         12 return $j;
752             }
753              
754             =head2 state255 (V, P)
755              
756             The 255-state algorithm. Used when encoding strings with the BASE256 type.
757              
758             This information originally from
759             L.
760              
761             Let C

the number of data Cs from the beginning of datas (C = code

762             word). Let C be a pseudo random number, C the base 256 C value
763             and C the required C.
764              
765             R = ((149 * P) MOD 255) + 1
766             CW = (V + R) MOD 256
767              
768             =cut
769              
770             sub state255 # (int V, int P) : int
771             {
772 188     188 1 235 my ($V,$P) = @_;
773 188         532 return ( $V + (149 * $P) % 255 + 1 ) % 256;
774             }
775              
776             =head2 hexary (src)
777              
778             Return a string representation of the input hexadecimal number.
779              
780             =cut
781              
782             sub hexary {
783 0     0 1 0 join(" ",map{ sprintf '%02x',$_} @{ shift() } )
  0         0  
  0         0  
784             }
785              
786             =head2 EncodeBASE256 (i, hint, src, stat, res, flag)
787              
788             Encode the message as BASE256.
789              
790             =cut
791              
792             sub EncodeBASE256 {
793 2     2 1 3 my $self = shift;
794 2         5 my ($i,$hint,$src,$stat,$res,$flag) = @_;
795 2         3 my $j = 0;
796 2         4 my $xv = [];
797 2         4 my $k =
798             my $l = $stat->[0];
799 2         4 my $flag1 = 0;
800 2         2 my $j1 = 0;
801 2 50       19 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
802 2 50       6 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
803 2         7 for( $j1 = $hint->[0]; $j1 < $i; $j1++){
804 186         258 $xv->[$j++] = $src->[$j1];
805 186 50 33     582 last if $flag and $self->SelectEncoding($j1 + 1,$src,E_BASE256) != E_BASE256;
806             }
807 2 50       7 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
808 2 50       6 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
809 2         3 $hint->[0] = $j1;
810 2         4 $res->[$l++] = 231;
811 2 50       6 if($j < 250) {
812 2         7 $res->[$l++] = state255($j, $l + 1);
813             } else {
814 0         0 $res->[$l++] = state255(249 + ($i - $i % 250) / 250, $l + 1);
815 0         0 $res->[$l++] = state255($i % 250, $l + 1);
816             }
817 2         10 $res->[$l++] = state255($xv->[$_], $l + 1) for 0..$j-1;
818 2         4 $stat->[0] = $l;
819 2         9 return $l;
820             }
821              
822             =head2 GenData (ai)
823              
824             Generate and return the data for the DataMatrix bitmap from the input array.
825              
826             =cut
827              
828             sub GenData { # CC (int ai[]) : int[][]
829 12     12 1 18 my $self = shift;
830 12         22 my ($ai) = @_;
831 12 50       38 warn "[CC] GenData: ".join(",",@$ai)." [$self->{rows} x $self->{cols} : $self->{regions} : $self->{datacols}x$self->{datarows}]\n" if $DEBUG{TRACE};
832 12         39 my $ai1 = [ map { [ (undef) x $self->{rows} ] } 1..$self->{cols} ]; # reverse cols/rows here, for correct access ->[][]
  390         1417  
833              
834 12         42 my $i = my $j = 0;
835             # Draw border
836 12 50       32 if($self->{regions} == 2) {
837 0         0 FillBorder($ai1, $i, $j, $self->{datacols} + 2, $self->{datarows} + 2);
838 0         0 FillBorder($ai1, $i + $self->{datacols} + 2, $j, $self->{datacols} + 2, $self->{datarows} + 2);
839             } else {
840 12         27 my $k = int(sqrt($self->{regions}));
841 12         33 for(my $l = 0; $l < $k; $l++){
842 20         51 for(my $i1 = 0; $i1 < $k; $i1++) {
843             FillBorder($ai1, $i + $l * ($self->{datacols} + 2), $j
844             + $i1 * ($self->{datarows} + 2),
845 42         163 $self->{datacols} + 2, $self->{datarows} + 2);
846             }
847             }
848              
849             }
850             # End draw border
851 12         746 my $ai2 = [ (undef) x ( ($self->{mapcols} + 10) * $self->{maprows} ) ];
852 12 50       32 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
853 12         33 FillCharData($self->{mapcols},$self->{maprows},$ai2);
854 12 50       37 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
855 12 50       29 warn "--------------\n" if $DEBUG{CALC};
856 12 50       27 warn "[" . join (" ", grep { +defined } @$ai)."]\n" if $DEBUG{CALC};
  0         0  
857 12         18 my $j1 = 1;
858 12         15 my $flag = 0;
859 12         15 my $flag1 = 0;
860 12         42 for(my $i2 = 0; $i2 < $self->{maprows}; $i2++) {
861 350         411 my $j2 = 1;
862 350         762 for(my $k2 = 0; $k2 < $self->{mapcols}; $k2++) {
863 14076         17524 my $l1 = $k2 + $j2;
864 14076         16089 my $k1 = $i2 + $j1;
865 14076 100       28620 if($ai2->[$i2 * $self->{mapcols} + $k2] > 9) {
866 14064         25130 my $l2 = int ( $ai2->[$i2 * $self->{mapcols} + $k2] / 10 );
867 14064         21510 my $i3 = $ai2->[$i2 * $self->{mapcols} + $k2] % 10;
868 14064         21048 my $j3 = $ai->[$l2 - 1] & 1 << 8 - $i3;
869 14064         19751 $ai1->[$l1][$k1] = $j3;
870             } else {
871 12         24 $ai1->[$l1][$k1] = $ai2->[$i2 * $self->{mapcols} + $k2];
872             }
873 14076 100 100     73462 if($k2 > 0 && ($k2 + 1) % $self->{datacols} == 0) {
874 742         1850 $j2 += 2;
875             }
876             }
877              
878 350 100 100     1999 if($i2 > 0 && ($i2 + 1) % $self->{datarows} == 0) {
879 20         70 $j1 += 2;
880             }
881             }
882 12         445 return $ai1;
883             }
884              
885             =head2 FillBorder (ai, i, j, k, l)
886              
887             Fill the border of the ECC200 data matrix bitmap.
888              
889             =cut
890              
891             sub FillBorder { # CD (int ai[][], int i, int j, int k, int l) : void
892 42     42 1 66 my ($ai,$i,$j,$k,$l) = @_;
893 42         48 my $i1 = 0;
894 42         112 for(my $k1 = 0; $k1 < $k; $k1++) {
895 826 100       1321 $i1 = ($k1 % 2 == 0) ? 1 : 0;
896 826         1134 $ai->[$i + $k1][$j + $l - 1] = 1;
897 826         2000 $ai->[$i + $k1][$j] = $i1;
898             }
899 42         50 $i1 = 0;
900 42         95 for(my $l1 = 0; $l1 < $l; $l1++) {
901 826 100       1415 my $j1 = (($l1 + 1) % 2 == 0) ? 1 : 0;
902 826         1105 $ai->[$i][$j + $l1] = 1;
903 826         2319 $ai->[$i + $k - 1][$j + $l1] = $j1;
904             }
905             }
906              
907             =head2 FillCharData (ncol, nrow, array)
908              
909             Fill the data matrix with the character data in the given message array.
910              
911             =cut
912              
913             sub FillCharData { # (int ncol; int nrow; int array;) : void
914 12     12 1 19 my ($ncol,$nrow,$array) = @_;
915 12         64 Barcode::DataMatrix::CharDataFiller->new($ncol,$nrow,$array);
916 12         20 return;
917             }
918              
919             1;