File Coverage

blib/lib/Barcode/DataMatrix/Engine.pm
Criterion Covered Total %
statement 377 517 72.9
branch 129 254 50.7
condition 67 152 44.0
subroutine 36 40 90.0
pod 33 33 100.0
total 642 996 64.4


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

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

307             pseudo random number and C the required pad C.
308              
309             R = ((149 * P) MOD 253) + 1
310             CW = (129 + R) MOD 254
311              
312             =cut
313              
314             sub A253 # C8 (int i, int j) : int
315             {
316 149     149 1 181 my ($i,$j) = @_;
317 149         200 my $l = $i + (149 * $j) % 253 + 1;
318 149 100       328 return $l <= 254 ? $l : $l - 254;
319             }
320              
321             =head2 CreateBitmap
322              
323             Generate and return the bitmap representing the message.
324              
325             =cut
326              
327             sub CreateBitmap #CB (int ai[], String as[]) : int[][]
328             {
329 12     12 1 15 my $self = shift;
330 12         33 my ($ai,$as) = @$self{qw(ai as)};
331 12 50       33 warn "[CB] CreateBitmap(ai[" .join(',',@$ai).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
332 12         21 my $ai1 = [];
333 12         17 my $i = 0;
334 12 100       34 $self->{currentEncoding} = $self->{encoding} if $self->{encoding} != E_AUTO;
335             #warn "AI Before enc: ".join(" ",@$ai)."\n";
336 12         30 for ($self->{encoding}){
337 12 50       33 warn "[CB] Select method for $self->{encoding}, ".typeToString($self->{encoding})."\n" if $DEBUG{ENC};
338 12 100       26 $_ == E_AUTO && do { $i = $self->DetectEncoding($ai1); last;};
  2         9  
  2         5  
339 10 100       21 $_ == E_ASCII && do { $i = $self->EncodeASCII(scalar(@$ai), $ai, $ai1, $as); last;};
  2         8  
  2         5  
340 8 100       19 $_ == E_C40 && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 0, 1, 0); last;};
  2         9  
  2         4  
341 6 100       15 $_ == E_TEXT && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 1, 1, 0); last;};
  2         10  
  2         5  
342 4 100       11 $_ == E_BASE256 && do { $i = $self->EncodeBASE256(scalar(@$ai), [0], $ai, [0], $ai1, 0, $as); last;};
  2         12  
  2         5  
343 2 50       4 $_ == E_NONE && do { $ai1 = [ @$ai ]; $i = @$ai; last };
  2         11  
  2         4  
  2         4  
344             }
345 12 50       39 warn "[CB] selected (ai1[" .join(',',@$ai1).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
346 12         11 DEBUG and print "Use Encoding: " .typeToString($self->{currentEncoding}). "(".typeToString($self->{encoding}).")\n";
347             #warn "AI1 After enc: ".join(" ",@$ai1)."\n";
348 12 50       29 warn "[CB]: enc res: ".typeToString($self->{encoding}).", " .typeToString($self->{currentEncoding}). "\n" if $DEBUG{ENC};
349 12         16 my $k = 0;
350 12 50       31 if($self->{preferredFormat} != -1) {
351 0         0 $k = $self->{preferredFormat};
352 0 0       0 $k = 0 if $i > $FORMATS[$k][7];
353             }
354             #warn "[CB]: format: $k\n";
355 12   66     73 for(; $i > $FORMATS[$k][7] && $k < 30; $k++)
356             {
357 94 100 100     177 next if $self->{currentEncoding} != E_C40 && $self->{currentEncoding} != E_TEXT;
358             #warn "[CB]: enc: E_C40/E_TEXT\n";
359 46 0 33     119 if($self->{C49rest} == 1 && $ai1->[$i - 2] == 254 && $FORMATS[$k][7] == $i - 1) {
      33        
360 0         0 $ai1->[$i - 2] = $ai1->[$i - 1];
361 0         0 $ai1->[$i - 1] = 0;
362 0         0 $i--;
363 0         0 last;
364             }
365 46 100 33     443 next if($self->{C49rest} != 0 || $ai1->[$i - 1] != 254 || $FORMATS[$k][7] != $i - 1);
      66        
366 2         5 $ai1->[$i - 1] = 0;
367 2         2 $i--;
368 2         4 last;
369             }
370              
371 12 50       27 return if $k == 30;
372 12         16 my $l = $k;
373             @$self{qw(
374             rows
375             cols
376             datarows
377             datacols
378             regions
379             maprows
380             mapcols
381             totaldata
382             totalerr
383             reeddata
384             reederr
385             reedblocks
386 12         20 )} = @{$FORMATS[$l]}[0..11];
  12         104  
387 12         21 DEBUG and print "Format: $self->{rows}x$self->{cols}; Data: $self->{totaldata}; i=$i; blocks = $self->{reedblocks}\n";
388             #warn "[CB]: Selected $self->{rows}x$self->{cols} [$self->{totaldata}]; $i\n";
389             $ai1->[$i - 1] = 129 if (
390             ($self->{currentEncoding} == E_C40 || $self->{currentEncoding} == E_TEXT )
391             and
392 12 50 100     29 $self->{C49rest} == 0 && $i == $self->{totaldata} && $ai1->[$i - 1] == 254
      66        
      66        
      66        
393             );
394 12         17 my $flag = 1;
395 12 50       31 warn "Calc begin from $i..$self->{totaldata} ai1=[@{$ai1}]\n" if $DEBUG{CALC};
  0         0  
396 12         33 for(my $i1 = $i; $i1 < $self->{totaldata}; $i1++) {
397             #warn " CB: $i <= $i1 < $self->{totaldata}\n";
398 158 100       388 $ai1->[$i1] = $flag ? 129 : A253(129, $i1 + 1);
399 158         420 $flag = 0;
400             }
401 12         45 return $self->{bitmap} = $self->GenData($self->ecc($l,$ai1));
402             }
403              
404             =head2 ecc (format, ai)
405              
406             Return the ECC200 (DataMatrix) array, formatted for the appropriate matrix
407             size.
408              
409             =cut
410              
411             sub ecc {
412 12     12 1 16 my $self = shift;
413 12         16 my $format = shift;
414 12         14 my $ai = shift;
415 12         21 my ($data,$err,$blocks) = @{$FORMATS[$format]}[9..11];
  12         25  
416 12         17 $blocks--;$data--;
  12         15  
417 12 50       30 warn "ECC: ai=[@{$ai}], blocks=$blocks\n" if $DEBUG{CALC};
  0         0  
418 12         25 my @blocks = map {[]} 0..$blocks;
  16         74  
419 12         19 my $block = 0;
420 12         24 for (@$ai) {
421 1228         1258 push @{$blocks[$block++]}, $_;
  1228         2087  
422 1228 100       2484 $block = 0 if $block > $blocks;
423             }
424             #$#{ $blocks[-1] } = $#{ $blocks[0] };
425 12 50       27 warn "Calc blocks=".Dumper \@blocks if $DEBUG{CALC};
426 12         32 for (0..$#blocks) {
427 16         19 $#{ $blocks[$_] } = $data; # correct padding
  16         53  
428 16 50 33     50 if($self->{rows} == 144 and $_ > 7) {
429             #warn "144 fix: decrease block $_ to size 155 from @{[ 0+@{$blocks[$_]} ]}";
430 0         0 $#{$blocks[$_]} -= 1;
  0         0  
431             }
432              
433 16         43 CalcReed($blocks[$_], $err);
434             }
435             warn "Calc reed=\n".
436 12 50       38 join "\n", map { '['.join(',',@$_).']' } @blocks if $DEBUG{CALC};
  0         0  
437 12         16 my @rv;
438 12         33 for my $n (0..$data+$err) {
439 1130         1650 for my $b (0..$#blocks) {
440             #warn "Calc $n, block $b";
441 1758 50       1703 if ( $n < @{$blocks[$b]} ) { # 144 fix
  1758         3100  
442 1758         3218 push @rv, $blocks[$b][$n];
443             } else {
444             #warn "skip $n from $b: 144 fix";
445             }
446             }
447             }
448 12         123 return \@rv;
449             }
450              
451             =head2 isCDigit (character)
452              
453             Return true if the character is a digit.
454              
455             =cut
456              
457             sub isCDigit { # C1*
458 0 0   0 1 0 return shift =~ /^[0-9]$/ ? 1 : 0;
459             }
460              
461             =head2 isIDigit (character_code)
462              
463             Return true if the character code represents a digit.
464              
465             =cut
466              
467             sub isIDigit { # C1
468 494     494 1 558 my $i = shift;
469 494 50 33     2630 return ( $i >= 48 && $i <= 57 ) ? 1 : 0;
470             }
471              
472             =head2 isILower (character_code)
473              
474             Return true if the character code represents a lower case letter.
475              
476             =cut
477              
478             sub isILower {
479 308     308 1 354 my $i = shift;
480 308 50 33     976 return ( $i >= ord('a') && $i <= ord('z') ) ? 1 : 0;
481             }
482              
483             =head2 isIUpper (character_code)
484              
485             Return true if the character code represents an upper case letter.
486              
487             =cut
488              
489             sub isIUpper {
490 308     308 1 344 my $i = shift;
491 308 50 33     1438 return ( $i >= ord('A') && $i <= ord('Z') ) ? 1 : 0;
492             }
493              
494             =head2 DetectEncoding
495              
496             Detect the encoding type.
497              
498             =cut
499              
500             sub DetectEncoding() #C4 (int i, int ai[], int ai1[], String as[]) : int
501             {
502 2     2 1 3 my $self = shift;
503 2 50       7 warn "[C4] DetectEncoding(@_)\n" if $DEBUG{TRACE};
504 2         5 my $ai = $self->{ai};
505 2         3 my $i = scalar (@$ai);
506 2         4 my $as = $self->{as};
507 2         4 my $ai1 = shift;
508 2         4 my $ai2 = [ ];
509 2         3 my $ai3 = [ ];
510 2         4 my $flag = 0;
511 2         72 my $j1 = 0;
512 2         5 my $k1 = E_ASCII;
513 2         4 my $ai4 = [ 0 ];
514 2         6 my $l2 = E_ASCII;
515 2         3 my $as1 = [ ];
516 2         3 my $iterator = 0;
517 2         6 $self->{currentEncoding} = E_ASCII;
518 2 50       7 warn("DetectENC: starting from ".$encName[$self->{currentEncoding}]."\n") if $DEBUG{EAUTO};
519 2         7 while($iterator < $i) { # while iterator less than length of data
520 2 50       6 warn("DetectENC: at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
521 2   66     6 while($self->{currentEncoding} == E_ASCII and $iterator < $i) {
522 2 50       6 warn("DetectENC: while at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
523 2         3 my $flag1 = 0;
524 2 50 33     11 if(
      33        
525             $iterator + 1 < $i
526             and isIDigit($ai->[$iterator])
527             and isIDigit($ai->[$iterator + 1])
528             ){
529 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};
530 0 0       0 $ai1->[$j1++] = 254 if($l2 != E_ASCII);
531 0         0 $ai2->[0] = $ai->[$iterator];
532 0         0 $ai2->[1] = $ai->[$iterator + 1];
533 0         0 my $j = $self->EncodeASCII(2, $ai2, $ai3, $as1);
534 0         0 splice(@$ai1,$j1,$j, @$ai3[0 .. $j-1 ]);
535 0         0 $j1 += $j;
536 0         0 $iterator++;
537 0         0 $iterator++;
538 0         0 $flag1 = 1;
539 0         0 $l2 = E_ASCII;
540             }
541 2 50       6 if(!$flag1) {
542 2 50       6 warn("DetectENC: !dig !flag1 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
543             #my $l1 = C3(@$ai, $self->{currentEncoding}, $iterator, @$as);
544 2         9 my $l1 = $self->SelectEncoding( $iterator );
545 2 50       4 if( $l1 != E_ASCII) {
546 2 50       5 warn("DetectENC: $encName[$self->{currentEncoding}] => $encName[$l1]\n") if $DEBUG{EAUTO};
547 2         4 $l2 = $self->{currentEncoding};
548 2         4 $self->{currentEncoding} = $l1;
549             }
550             }
551 2 50 33     9 if(!$flag1 and $self->{currentEncoding} == E_ASCII){
552 0 0       0 $ai1->[$j1++] = 254 if($l2 != E_ASCII);
553 0         0 $ai2->[0] = $ai->[$iterator];
554 0         0 $as1->[0] = $as->[$iterator];
555 0         0 my $k = $self->EncodeASCII(1, $ai2, $ai3, $as1);
556 0         0 $as1->[0] = undef;
557 0         0 splice(@$ai1,$j1,$k, @$ai3[0 .. $k-1 ]);
558 0         0 $j1 += $k;
559 0         0 $iterator++;
560 0         0 $l2 = E_ASCII;
561             }
562             }
563 2 50       6 warn("DetectENC: after while at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
564 2         3 my $i2;
565             #warn "DetectEncoding < $iterator < $i > : i2: [$i2] ".typeToString($i2)."\n";
566 2   66     5 for(; $self->{currentEncoding} == E_C40 and $iterator < $i; $self->{currentEncoding} = $i2) {
567 62         80 $ai4->[0] = $iterator;
568 62         104 my $l = $self->EncodeC40TEXT($i, $ai4, $ai, $ai3, 0, $l2 != E_C40, 1);
569 62         99 $iterator = $ai4->[0];
570 62         141 splice(@$ai1,$j1,$l, @$ai3[0 .. $l-1 ]);
571 62         82 $j1 += $l;
572 62         125 $i2 = $self->SelectEncoding($iterator);
573 62         176 $l2 = $self->{currentEncoding};
574             }
575 2 50       7 warn("DetectENC: after C40 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
576              
577 2         3 my $j2;
578 2   33     6 for(; $self->{currentEncoding} == E_TEXT and $iterator < $i; $self->{currentEncoding} = $j2) {
579 0         0 $ai4->[0] = $iterator;
580 0         0 my $i1 = $self->EncodeC40TEXT($i, $ai4, $ai, $ai3, 1, $l2 != E_TEXT, 1);
581 0         0 $iterator = $ai4->[0];
582 0         0 splice(@$ai1,$j1,$i1, @$ai3[0 .. $i1-1 ]);
583 0         0 $j1 += $i1;
584 0         0 $j2 = $self->SelectEncoding($iterator);
585 0         0 $l2 = $self->{currentEncoding};
586             }
587 2 50       6 warn("DetectENC: after TEXT at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
588              
589 2 50       6 if($self->{currentEncoding} == E_BASE256) {
590 0         0 $ai4->[0] = $iterator;
591 0         0 $j1 = $self->EncodeBASE256($i, $ai4, $ai, [$j1], $ai1, 1);
592 0         0 $iterator = $ai4->[0];
593 0         0 my $k2 = $self->SelectEncoding($iterator);
594 0         0 $l2 = $self->{currentEncoding};
595 0         0 $self->{currentEncoding} = $k2;
596             }
597 2 50       9 warn("DetectENC: after B256 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
598             }
599 2         4 return $j1;
600             }
601              
602             =head2 EncodeASCII (i, ai, ai1, as)
603              
604             Encode the message as ASCII.
605              
606             =cut
607              
608             sub EncodeASCII { #CE (int i; int ai[], int ai1[], String as[]) : int
609 2     2 1 3 my $self = shift;
610 2 50       7 warn "[CE] EncodeASCII(@_)\n" if $DEBUG{TRACE};
611 2         4 my ($i,$ai,$ai1,$as) = @_;
612 2 50       7 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  
613 2         3 my $j = 0;
614 2         3 my $flag = 0;
615 2         7 for(my $k = 0; $k < $i; $k++) {
616 186         207 my $flag1 = 0;
617 186 50 66     499 if(
      33        
618             $k < $i - 1
619             and isIDigit($ai->[$k])
620             and isIDigit($ai->[$k+1])
621             ) {
622             #warn "[CE] $flag $flag1 $k $ai->[$k] is type 1";
623 0         0 my $l = ($ai->[$k] - 48) * 10 + ($ai->[$k + 1] - 48);
624 0         0 $ai1->[$j++] = 130 + $l;
625 0         0 $k++;
626 0         0 $flag1 = 1;
627             }
628 186 50 33     743 if(!$flag1 and defined $as->[$k]) {
629             #warn "[CE] $flag $flag1 $k $ai->[$k] is subtype !flag";
630 0 0 0     0 if(
      0        
      0        
631             $ai->[$k] == 234
632             or $ai->[$k] == 237
633             or $ai->[$k] == 236
634             or $ai->[$k] == 232
635             ) {
636             #warn "[CE] $flag $flag1 $k $ai->[$k] is type 2";
637 0         0 $ai1->[$j++] = $ai->[$k];
638 0         0 $flag1 = 1;
639             }
640 0 0 0     0 if($ai->[$k] == 233 || $ai->[$k] == 241) {
641 0         0 $ai1->[$j++] = $ai->[$k];
642             #warn("Additional data by 233/241 for $k: $as->[$k]");
643 0         0 for(my $i1 = 0; $i1 < length $as->[$k]; $i1++){
644 0         0 $ai1->[$j++] = ord substr($as->[$k],$i1,1);
645             }
646 0         0 $flag1 = 1;
647             }
648             }
649 186 50       374 if(!$flag1){
650 186 50       299 if($ai->[$k] < 128) {
651             #warn "[CE] $flag $flag1 $k $ai->[$k] is type 3";
652 186         559 $ai1->[$j++] = $ai->[$k] + 1;
653             } else {
654             #warn "[CE] $flag $flag1 $k $ai->[$k] is type 4";
655 0         0 $ai1->[$j++] = 235;
656 0         0 $ai1->[$j++] = ($ai->[$k] - 128) + 1;
657             }
658             }
659             }
660             #warn Dumper( \@_ );
661 2 50       6 warn "[CE] end $j ai1:{".join(" ",@$ai1)."};\n" if $DEBUG{ENC};
662 2         4 return $j;
663             }
664              
665             =head2 SelectEncoding (j, ai, i)
666              
667             Select a new encoding type for the message.
668              
669             =cut
670              
671             sub SelectEncoding #C3 (int ai[], int i, int j, String as[]) : int # DefineEncoding??
672             #iterator, ai, encoding
673             {
674             #(iterator[,ai[,encoding]])
675             #(ai,i: encoding,j: iterator,as)
676 64     64 1 74 my $self = shift;
677 64 50       130 warn "[C3] SelectEncoding(@_)\n" if $DEBUG{TRACE};
678              
679 64         71 my $j = shift;
680              
681 64         88 my $ai = shift;
682 64 50       173 $ai = $self->{ai} unless defined $ai;
683              
684 64   33     183 my $i = shift || $self->{currentEncoding};
685 64 50       117 $i = $self->{currentEncoding} unless defined $i;
686              
687 64         105 my $as = $self->{as};
688 64         67 my $d = 0.0;
689 64         74 my $d2 = 1.0;
690 64         66 my $d3 = 1.0;
691 64         67 my $d4 = 1.25;
692 64         82 my $k = $j;
693 64 100       107 if($i != E_ASCII)
694             {
695 62         67 $d = 1.0;
696 62         66 $d2 = 2.0;
697 62         71 $d3 = 2.0;
698 62         69 $d4 = 2.25;
699             }
700 64 100       110 $d2 = 0.0 if $i == E_C40;
701 64 50       114 $d3 = 0.0 if $i == E_TEXT;
702 64 50       107 $d4 = 0.0 if $i == E_BASE256;
703 64         132 for(; $j < @$ai; $j++)
704             {
705 308 0 33     627 warn "SelectEncoding: have as[$j]: $as->[$j]\n" if defined $as->[$j] and $DEBUG{EAUTO};
706 308         353 my $c = $ai->[$j];
707 308 50       577 return E_ASCII if defined $as->[$j];
708              
709 308 50       512 if ( isIDigit($c) ) { $d += 0.5 }
  0 50       0  
710 0         0 elsif ( $c > 127 ) { $d = int( $d + 0.5 ) + 2; }
711 308         449 else { $d = int( $d + 0.5 ) + 1; }
712              
713 308 50       330 if ( @{ $C1[$c] } == 1 ) { $d2 += 0.66000000000000003; }
  308 0       587  
  308         383  
714 0         0 elsif ( $c > 127 ) { $d2 += 2.6600000000000001; }
715 0         0 else { $d2 += 1.3300000000000001; }
716 308         397 my $c1 = $c;
717 308 50       477 if( isIUpper($c) ) { $c1 = ord lc chr $c; }
  308         401  
718 308 50       517 if( isILower($c) ) { $c1 = ord uc chr $c; }
  0         0  
719              
720 308 50       360 if ( @{ $C1[$c1] } == 1) { $d3 += 0.66000000000000003; }
  308 50       745  
  0         0  
721 0         0 elsif ( $c1 > 127 ) { $d3 += 2.6600000000000001; }
722 308         353 else { $d3 += 1.3300000000000001; }
723              
724 308         441 $d4++;
725              
726 308 100       921 if($j - $k >= 4) {
727             #warn "$j-$k >= 4: $d $d2 $d3 $d4\n";
728 62 0 33     141 return E_ASCII if $d + 1.0 <= $d2 and $d + 1.0 <= $d3 and $d + 1.0 <= $d4;
      33        
729 62 50       133 return E_BASE256 if $d4 + 1.0 <= $d;
730 62 50 33     269 return E_BASE256 if $d4 + 1.0 < $d3 and $d4 + 1.0 < $d2;
731 62 0 33     157 return E_TEXT if $d3 + 1.0 < $d and $d3 + 1.0 < $d2 and $d3 + 1.0 < $d4;
      33        
732 62 50 66     427 return E_C40 if $d2 + 1.0 < $d and $d2 + 1.0 < $d3 and $d2 + 1.0 < $d4;
      66        
733             }
734             }
735              
736 4         7 $d = int( $d + 0.5 );
737 4         6 $d2 = int( $d2 + 0.5 );
738 4         5 $d3 = int( $d3 + 0.5 );
739 4         6 $d4 = int( $d4 + 0.5 );
740 4 0 33     12 return E_ASCII if $d <= $d2 and $d <= $d3 and $d <= $d4;
      33        
741 4 0 33     11 return E_TEXT if $d3 < $d and $d3 < $d2 and $d3 < $d4;
      33        
742 4 0 33     11 return E_BASE256 if $d4 < $d and $d4 < $d3 and $d4 < $d2;
      33        
743 4         9 return E_C40;
744             }
745              
746             =head2 EncodeC40TEXT (i, ai, ai1, ai2, flag, flag1, flag2)
747              
748             Encode the message as C40/TEXT.
749              
750             =cut
751              
752             sub EncodeC40TEXT { # C6 #(int i, int ai[], int ai1[], int ai2[], boolean flag, boolean flag1, boolean flag2) : int
753             #warn "[C6] EncodeC40TEXT\n";
754 66     66 1 86 my $self = shift;
755 66         118 my ($i,$ai,$ai1,$ai2,$flag,$flag1,$flag2) = @_;
756 66         78 my $j = my $k = 0;
757 66         114 my $ai3 = [ 0, 0, 0 ];
758 66         76 my $flag3 = 0;
759 66         79 my $as = [ ];
760 66 100       129 if($flag1) {
761 6 100       18 $ai2->[$j++] = $flag ? 239 : 230;
762             }
763 66         163 for(my $j1 = $ai->[0]; $j1 < $i; $j1++) {
764 558         710 my $l = $ai1->[$j1];
765 558 100       918 if($flag) {
766 186         275 my $s = chr($l);
767 186 50 33     411 $s = uc($s) if($l >= 97 && $l <= 122);
768 186 50 33     784 $s = lc($s) if($l >= 65 && $l <= 90);
769 186         269 $l = ord(substr($s,0,1));
770             }
771 558         734 my $ai4 = $C1[$l];
772 558         999 for my $l1 (0 .. $#$ai4) {
773 744         1031 $ai3->[$k++] = $ai4->[$l1];
774 744 100       1551 if($k == 3) {
775 248         380 my $i2 = $ai3->[0] * 1600 + $ai3->[1] * 40 + $ai3->[2] + 1;
776 248         394 $ai2->[$j++] = int $i2 / 256;
777 248         373 $ai2->[$j++] = $i2 % 256;
778 248         418 $k = 0;
779             }
780             }
781              
782 558 100 100     2272 if($flag2 && $k == 0) {
783 62         87 $self->{C49rest} = $k;
784 62         85 $ai->[0] = $j1 + 1;
785 62 100       119 $ai2->[$j++] = 254 if($ai->[0] == $i);
786 62         153 return $j;
787             }
788             }
789              
790 4         6 $ai->[0] = $i;
791 4 50       10 if($k > 0) {
792 0 0       0 if($k == 1) {
793 0         0 $ai2->[$j++] = 254;
794 0         0 $ai2->[$j++] = $ai1->[$i - 1] + 1;
795 0         0 return $j;
796             }
797 0 0       0 if($k == 2) {
798 0         0 $ai3->[2] = 0;
799 0         0 my $k1 = $ai3->[0] * 1600 + $ai3->[1] * 40 + $ai3->[2] + 1;
800 0         0 $ai2->[$j++] = int $k1 / 256;
801 0         0 $ai2->[$j++] = $k1 % 256;
802 0         0 $ai2->[$j++] = 254;
803 0         0 $self->{C49rest} = $k;
804 0         0 return $j;
805             }
806             } else {
807 4         6 $ai2->[$j++] = 254;
808             }
809 4         7 $self->{C49rest} = $k;
810 4         13 return $j;
811             }
812              
813             =head2 state255 (V, P)
814              
815             The 255-state algorithm. Used when encoding strings with the BASE256 type.
816              
817             This information originally from
818             L.
819              
820             Let C

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

821             word). Let C be a pseudo random number, C the base 256 C value
822             and C the required C.
823              
824             R = ((149 * P) MOD 255) + 1
825             CW = (V + R) MOD 256
826              
827             =cut
828              
829             sub state255 # (int V, int P) : int
830             {
831 188     188 1 216 my ($V,$P) = @_;
832 188         555 return ( $V + (149 * $P) % 255 + 1 ) % 256;
833             }
834              
835             =head2 hexary (src)
836              
837             Return a string representation of the input hexadecimal number.
838              
839             =cut
840              
841             sub hexary {
842 0     0 1 0 join(" ",map{ sprintf '%02x',$_} @{ shift() } )
  0         0  
  0         0  
843             }
844              
845             =head2 decary (src)
846              
847             Return a string representation of the input decimal number.
848              
849             =cut
850              
851             sub decary {
852 0     0 1 0 join(" ",map{ sprintf '%3d',$_} @{ shift() } )
  0         0  
  0         0  
853             }
854              
855             =head2 EncodeBASE256 (i, hint, src, stat, res, flag)
856              
857             Encode the message as BASE256.
858              
859             =cut
860              
861             sub EncodeBASE256 {
862 2     2 1 4 my $self = shift;
863 2         4 my ($i,$hint,$src,$stat,$res,$flag) = @_;
864 2         4 my $j = 0;
865 2         3 my $xv = [];
866 2         5 my $k =
867             my $l = $stat->[0];
868 2         4 my $flag1 = 0;
869 2         3 my $j1 = 0;
870 2 50       6 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
871 2 50       18 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
872 2         8 for( $j1 = $hint->[0]; $j1 < $i; $j1++){
873 186         238 $xv->[$j++] = $src->[$j1];
874 186 50 33     558 last if $flag and $self->SelectEncoding($j1 + 1,$src,E_BASE256) != E_BASE256;
875             }
876 2 50       7 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
877 2 50       6 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
878             #warn "$j1 : $l\n";
879 2         3 $hint->[0] = $j1;
880 2         5 $res->[$l++] = 231;
881 2 50       6 if($j < 250) {
882 2         9 $res->[$l++] = state255($j, $l + 1);
883             } else {
884 0         0 $res->[$l++] = state255(249 + ($i - $i % 250) / 250, $l + 1);
885 0         0 $res->[$l++] = state255($i % 250, $l + 1);
886             }
887 2         11 $res->[$l++] = state255($xv->[$_], $l + 1) for 0..$j-1;
888 2         4 $stat->[0] = $l;
889 2         8 return $l;
890             }
891              
892             =head2 GenData (ai)
893              
894             Generate and return the data for the DataMatrix bitmap from the input array.
895              
896             =cut
897              
898             sub GenData { # CC (int ai[]) : int[][]
899 12     12 1 27 my $self = shift;
900 12         17 my ($ai) = @_;
901 12 50       39 warn "[CC] GenData: ".join(",",@$ai)." [$self->{rows} x $self->{cols} : $self->{regions} : $self->{datacols}x$self->{datarows}]\n" if $DEBUG{TRACE};
902 12         39 my $ai1 = [ map { [ (undef) x $self->{rows} ] } 1..$self->{cols} ]; # reverse cols/rows here, for correct access ->[][]
  390         1417  
903              
904 12         44 my $i = my $j = 0;
905             # Draw border
906 12 50       30 if($self->{regions} == 2) {
907 0         0 FillBorder($ai1, $i, $j, $self->{datacols} + 2, $self->{datarows} + 2);
908 0         0 FillBorder($ai1, $i + $self->{datacols} + 2, $j, $self->{datacols} + 2, $self->{datarows} + 2);
909             } else {
910 12         39 my $k = int(sqrt($self->{regions}));
911 12         45 for(my $l = 0; $l < $k; $l++){
912 20         50 for(my $i1 = 0; $i1 < $k; $i1++) {
913             FillBorder($ai1, $i + $l * ($self->{datacols} + 2), $j
914             + $i1 * ($self->{datarows} + 2),
915 42         148 $self->{datacols} + 2, $self->{datarows} + 2);
916             }
917             }
918              
919             }
920             # End draw border
921 12         765 my $ai2 = [ (undef) x ( ($self->{mapcols} + 10) * $self->{maprows} ) ];
922 12 50       36 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
923 12         69 FillCharData($self->{mapcols},$self->{maprows},$ai2);
924 12 50       31 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
925 12 50       29 warn "--------------\n" if $DEBUG{CALC};
926 12 50       26 warn "[" . join (" ", grep { +defined } @$ai)."]\n" if $DEBUG{CALC};
  0         0  
927 12         18 my $j1 = 1;
928 12         16 my $flag = 0;
929 12         17 my $flag1 = 0;
930 12         39 for(my $i2 = 0; $i2 < $self->{maprows}; $i2++) {
931 350         402 my $j2 = 1;
932 350         855 for(my $k2 = 0; $k2 < $self->{mapcols}; $k2++) {
933 14076         17477 my $l1 = $k2 + $j2;
934 14076         16327 my $k1 = $i2 + $j1;
935 14076 100       29972 if($ai2->[$i2 * $self->{mapcols} + $k2] > 9) {
936 14064         25076 my $l2 = int ( $ai2->[$i2 * $self->{mapcols} + $k2] / 10 );
937 14064         21421 my $i3 = $ai2->[$i2 * $self->{mapcols} + $k2] % 10;
938 14064         20972 my $j3 = $ai->[$l2 - 1] & 1 << 8 - $i3;
939 14064         19756 $ai1->[$l1][$k1] = $j3;
940             } else {
941 12         23 $ai1->[$l1][$k1] = $ai2->[$i2 * $self->{mapcols} + $k2];
942             }
943 14076 100 100     77849 if($k2 > 0 && ($k2 + 1) % $self->{datacols} == 0) {
944 742         1949 $j2 += 2;
945             }
946             }
947              
948 350 100 100     1877 if($i2 > 0 && ($i2 + 1) % $self->{datarows} == 0) {
949 20         53 $j1 += 2;
950             }
951             }
952 12         432 return $ai1;
953             }
954              
955             =head2 FillBorder (ai, i, j, k, l)
956              
957             Fill the border of the ECC200 data matrix bitmap.
958              
959             =cut
960              
961             sub FillBorder { # CD (int ai[][], int i, int j, int k, int l) : void
962 42     42 1 64 my ($ai,$i,$j,$k,$l) = @_;
963             #warn "[CD] FillBorder([".join(",",@$ai)."],$i,$j,$k,$l)\n";
964 42         51 my $i1 = 0;
965 42         106 for(my $k1 = 0; $k1 < $k; $k1++) {
966 826 100       1260 $i1 = ($k1 % 2 == 0) ? 1 : 0;
967 826         1123 $ai->[$i + $k1][$j + $l - 1] = 1;
968 826         2008 $ai->[$i + $k1][$j] = $i1;
969             }
970 42         47 $i1 = 0;
971 42         112 for(my $l1 = 0; $l1 < $l; $l1++) {
972 826 100       1559 my $j1 = (($l1 + 1) % 2 == 0) ? 1 : 0;
973 826         1104 $ai->[$i][$j + $l1] = 1;
974 826         2279 $ai->[$i + $k - 1][$j + $l1] = $j1;
975             }
976             }
977              
978             =head2 FillCharData (ncol, nrow, array)
979              
980             Fill the data matrix with the character data in the given message array.
981              
982             =cut
983              
984             sub FillCharData { # (int ncol; int nrow; int array;) : void
985 12     12 1 21 my ($ncol,$nrow,$array) = @_;
986 12         69 Barcode::DataMatrix::CharDataFiller->new($ncol,$nrow,$array);
987 12         18 return;
988             }
989              
990             1;