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   7 use strict;
  2         3  
  2         44  
10 2     2   7 use warnings;
  2         2  
  2         38  
11 2     2   6 no warnings qw(uninitialized);
  2         2  
  2         49  
12 2     2   605 use Barcode::DataMatrix::Reed;
  2         3  
  2         45  
13 2     2   658 use Barcode::DataMatrix::Constants ();
  2         8  
  2         36  
14 2     2   643 use Barcode::DataMatrix::CharDataFiller ();
  2         4  
  2         33  
15 2     2   1081 use Data::Dumper;$Data::Dumper::Useqq = 1;
  2         12707  
  2         119  
16              
17             =head2 DEBUG
18              
19             Turn on/off general debugging information.
20              
21             =cut
22              
23 2     2   10 use constant DEBUG => 0;
  2         2  
  2         8910  
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 253 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 673 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 348 sub E_TEXT { 2 }
60              
61             =head2 E_BASE256
62              
63             Represent the BASE256 encoding type.
64              
65             =cut
66              
67 78     78 1 107 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 18 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 71 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 18 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 64 my $m = 'E_'.shift;
105 54         41 return eval { __PACKAGE__->$m(); };
  54         94  
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 9 my $i = shift;
116 12         13 for (Types) {
117 42 100 66     35 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 15 my $sz = shift;
132 12 50       66 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 16 my $self = shift;
150 12         13 my $type = shift;
151 12         35 my $t = stringToType($type);
152 12 50       27 warn "setType $type => $t\n" if $DEBUG{ENC};
153 12 50       26 $t = E_ASCII unless defined $t;
154 12         14 $self->{encoding} = $self->{currentEncoding} = $t;
155 12 50       25 warn "Have type $t (".typeToString($t).")\n" if $DEBUG{ENC};
156 12         15 return;
157             }
158              
159             =head2 new
160              
161             Construct a C object.
162              
163             =cut
164              
165             sub new {
166 12     12 1 27 my $self = bless{},shift;
167 12         30 $self->init();
168 12 50       47 warn "[CA] new(@_)\n" if $DEBUG{TRACE};
169 12         27 $self->{orig} = $self->{code} = shift; # text
170 12         33 $self->setType(shift); # type of encoding
171 12   50     26 $self->{preferredFormat} = stringToFormat(shift) || -1; # type of format
172 12         30 $self->{as} = [ ]; # additional streams
173 12 50       27 $self->ProcessTilde if (shift); # process tilde
174 12 50       36 return unless ( my $l = length($self->{code}) ); # no data to encode
175 12         260 $self->{ac} = [ split //,$self->{code} ]; # create an char array
176 12         51 $self->{ai} = [ map { +ord } @{ $self->{ac} } ]; # create an int array
  1116         778  
  12         26  
177 12         52 $self->CreateBitmap();
178 12         74 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 14 my $self = shift;
189 12         35 my %p = (
190             processTilde => 0,#0
191             encoding => E_ASCII,
192             preferredFormat => -1,
193             currentEncoding => E_ASCII,
194             C49rest => 0,
195             );
196 12         38 for (keys %p){
197 60         91 $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 16 my ($ai,$err) = @_;
258 16         60 my $rv = Barcode::DataMatrix::Reed::encode($ai,$err);
259 16         207 @$ai = @$rv;
260 16         57 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 92 my ($i,$j) = @_;
290 149         125 my $l = $i + (149 * $j) % 253 + 1;
291 149 100       167 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 15 my $self = shift;
303 12         21 my ($ai,$as) = @$self{qw(ai as)};
304 12 50       26 warn "[CB] CreateBitmap(ai[" .join(',',@$ai).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
305 12         16 my $ai1 = [];
306 12         13 my $i = 0;
307 12 100       29 $self->{currentEncoding} = $self->{encoding} if $self->{encoding} != E_AUTO;
308 12         32 for ($self->{encoding}){
309 12 50       28 warn "[CB] Select method for $self->{encoding}, ".typeToString($self->{encoding})."\n" if $DEBUG{ENC};
310 12 100       19 $_ == E_AUTO && do { $i = $self->DetectEncoding($ai1); last;};
  2         5  
  2         3  
311 10 100       19 $_ == E_ASCII && do { $i = $self->EncodeASCII(scalar(@$ai), $ai, $ai1, $as); last;};
  2         8  
  2         9  
312 8 100       19 $_ == E_C40 && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 0, 1, 0); last;};
  2         9  
  2         4  
313 6 100       13 $_ == E_TEXT && do { $i = $self->EncodeC40TEXT(scalar(@$ai), [0], $ai, $ai1, 1, 1, 0); last;};
  2         9  
  2         5  
314 4 100       8 $_ == E_BASE256 && do { $i = $self->EncodeBASE256(scalar(@$ai), [0], $ai, [0], $ai1, 0, $as); last;};
  2         10  
  2         4  
315 2 50       5 $_ == E_NONE && do { $ai1 = [ @$ai ]; $i = @$ai; last };
  2         8  
  2         2  
  2         3  
316             }
317 12 50       25 warn "[CB] selected (ai1[" .join(',',@$ai1).'], as[' . scalar(@$as) . "])\n" if $DEBUG{TRACE};
318 12         9 DEBUG and print "Use Encoding: " .typeToString($self->{currentEncoding}). "(".typeToString($self->{encoding}).")\n";
319 12 50       22 warn "[CB]: enc res: ".typeToString($self->{encoding}).", " .typeToString($self->{currentEncoding}). "\n" if $DEBUG{ENC};
320 12         13 my $k = 0;
321 12 50       21 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     64 for(; $i > $FORMATS[$k][7] && $k < 30; $k++)
326             {
327 94 100 100     89 next if $self->{currentEncoding} != E_C40 && $self->{currentEncoding} != E_TEXT;
328 46 0 33     76 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     286 next if($self->{C49rest} != 0 || $ai1->[$i - 1] != 254 || $FORMATS[$k][7] != $i - 1);
      66        
335 2         3 $ai1->[$i - 1] = 0;
336 2         2 $i--;
337 2         1 last;
338             }
339              
340 12 50       23 return if $k == 30;
341 12         9 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         12 )} = @{$FORMATS[$l]}[0..11];
  12         84  
356 12         13 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     24 $self->{C49rest} == 0 && $i == $self->{totaldata} && $ai1->[$i - 1] == 254
      66        
      66        
      66        
361             );
362 12         15 my $flag = 1;
363 12 50       20 warn "Calc begin from $i..$self->{totaldata} ai1=[@{$ai1}]\n" if $DEBUG{CALC};
  0         0  
364 12         29 for(my $i1 = $i; $i1 < $self->{totaldata}; $i1++) {
365 158 100       211 $ai1->[$i1] = $flag ? 129 : A253(129, $i1 + 1);
366 158         203 $flag = 0;
367             }
368 12         30 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 12 my $self = shift;
380 12         11 my $format = shift;
381 12         9 my $ai = shift;
382 12         20 my ($data,$err,$blocks) = @{$FORMATS[$format]}[9..11];
  12         19  
383 12         10 $blocks--;$data--;
  12         7  
384 12 50       23 warn "ECC: ai=[@{$ai}], blocks=$blocks\n" if $DEBUG{CALC};
  0         0  
385 12         25 my @blocks = map {[]} 0..$blocks;
  16         35  
386 12         17 my $block = 0;
387 12         21 for (@$ai) {
388 1228         667 push @{$blocks[$block++]}, $_;
  1228         898  
389 1228 100       1489 $block = 0 if $block > $blocks;
390             }
391 12 50       22 warn "Calc blocks=".Dumper \@blocks if $DEBUG{CALC};
392 12         31 for (0..$#blocks) {
393 16         43 $#{ $blocks[$_] } = $data; # correct padding
  16         55  
394 16 50 33     46 if($self->{rows} == 144 and $_ > 7) {
395 0         0 $#{$blocks[$_]} -= 1;
  0         0  
396             }
397              
398 16         37 CalcReed($blocks[$_], $err);
399             }
400             warn "Calc reed=\n".
401 12 50       42 join "\n", map { '['.join(',',@$_).']' } @blocks if $DEBUG{CALC};
  0         0  
402 12         16 my @rv;
403 12         29 for my $n (0..$data+$err) {
404 1130         996 for my $b (0..$#blocks) {
405 1758 50       951 if ( $n < @{$blocks[$b]} ) { # 144 fix
  1758         2096  
406 1758         1679 push @rv, $blocks[$b][$n];
407             }
408             }
409             }
410 12         96 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 302 my $i = shift;
421 494 50 33     1599 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 167 my $i = shift;
432 308 50 33     581 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 169 my $i = shift;
443 308 50 33     841 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 2 my $self = shift;
455 2 50       5 warn "[C4] DetectEncoding(@_)\n" if $DEBUG{TRACE};
456 2         2 my $ai = $self->{ai};
457 2         3 my $i = scalar (@$ai);
458 2         2 my $as = $self->{as};
459 2         3 my $ai1 = shift;
460 2         2 my $ai2 = [ ];
461 2         3 my $ai3 = [ ];
462 2         3 my $flag = 0;
463 2         2 my $j1 = 0;
464 2         3 my $k1 = E_ASCII;
465 2         2 my $ai4 = [ 0 ];
466 2         3 my $l2 = E_ASCII;
467 2         1 my $as1 = [ ];
468 2         3 my $iterator = 0;
469 2         3 $self->{currentEncoding} = E_ASCII;
470 2 50       5 warn("DetectENC: starting from ".$encName[$self->{currentEncoding}]."\n") if $DEBUG{EAUTO};
471 2         61 while($iterator < $i) { # while iterator less than length of data
472 2 50       5 warn("DetectENC: at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
473 2   66     4 while($self->{currentEncoding} == E_ASCII and $iterator < $i) {
474 2 50       3 warn("DetectENC: while at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
475 2         3 my $flag1 = 0;
476 2 50 33     7 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       3 if(!$flag1) {
494 2 50       5 warn("DetectENC: !dig !flag1 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
495 2         6 my $l1 = $self->SelectEncoding( $iterator );
496 2 50       4 if( $l1 != E_ASCII) {
497 2 50       4 warn("DetectENC: $encName[$self->{currentEncoding}] => $encName[$l1]\n") if $DEBUG{EAUTO};
498 2         3 $l2 = $self->{currentEncoding};
499 2         2 $self->{currentEncoding} = $l1;
500             }
501             }
502 2 50 33     6 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       4 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     4 for(; $self->{currentEncoding} == E_C40 and $iterator < $i; $self->{currentEncoding} = $i2) {
517 62         48 $ai4->[0] = $iterator;
518 62         63 my $l = $self->EncodeC40TEXT($i, $ai4, $ai, $ai3, 0, $l2 != E_C40, 1);
519 62         39 $iterator = $ai4->[0];
520 62         110 splice(@$ai1,$j1,$l, @$ai3[0 .. $l-1 ]);
521 62         36 $j1 += $l;
522 62         69 $i2 = $self->SelectEncoding($iterator);
523 62         87 $l2 = $self->{currentEncoding};
524             }
525 2 50       7 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     5 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       4 warn("DetectENC: after TEXT at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
538              
539 2 50       3 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       8 warn("DetectENC: after B256 at $iterator ce=$encName[$self->{currentEncoding}] k1=$encName[$k1] l2=$encName[$l2]\n") if $DEBUG{EAUTO};
548             }
549 2         5 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 2 my $self = shift;
560 2 50       5 warn "[CE] EncodeASCII(@_)\n" if $DEBUG{TRACE};
561 2         3 my ($i,$ai,$ai1,$as) = @_;
562 2 50       5 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         2 my $j = 0;
564 2         2 my $flag = 0;
565 2         7 for(my $k = 0; $k < $i; $k++) {
566 186         105 my $flag1 = 0;
567 186 50 66     267 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     430 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       186 if(!$flag1){
596 186 50       174 if($ai->[$k] < 128) {
597 186         279 $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       3 warn "[CE] end $j ai1:{".join(" ",@$ai1)."};\n" if $DEBUG{ENC};
605 2         4 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 46 my $self = shift;
620 64 50       83 warn "[C3] SelectEncoding(@_)\n" if $DEBUG{TRACE};
621              
622 64         40 my $j = shift;
623              
624 64         37 my $ai = shift;
625 64 50       93 $ai = $self->{ai} unless defined $ai;
626              
627 64   33     83 my $i = shift || $self->{currentEncoding};
628 64 50       76 $i = $self->{currentEncoding} unless defined $i;
629              
630 64         37 my $as = $self->{as};
631 64         39 my $d = 0.0;
632 64         41 my $d2 = 1.0;
633 64         34 my $d3 = 1.0;
634 64         42 my $d4 = 1.25;
635 64         35 my $k = $j;
636 64 100       54 if($i != E_ASCII)
637             {
638 62         36 $d = 1.0;
639 62         43 $d2 = 2.0;
640 62         29 $d3 = 2.0;
641 62         48 $d4 = 2.25;
642             }
643 64 100       61 $d2 = 0.0 if $i == E_C40;
644 64 50       67 $d3 = 0.0 if $i == E_TEXT;
645 64 50       64 $d4 = 0.0 if $i == E_BASE256;
646 64         94 for(; $j < @$ai; $j++)
647             {
648 308 0 33     361 warn "SelectEncoding: have as[$j]: $as->[$j]\n" if defined $as->[$j] and $DEBUG{EAUTO};
649 308         171 my $c = $ai->[$j];
650 308 50       315 return E_ASCII if defined $as->[$j];
651              
652 308 50       255 if ( isIDigit($c) ) { $d += 0.5 }
  0 50       0  
653 0         0 elsif ( $c > 127 ) { $d = int( $d + 0.5 ) + 2; }
654 308         229 else { $d = int( $d + 0.5 ) + 1; }
655              
656 308 50       195 if ( @{ $C1[$c] } == 1 ) { $d2 += 0.66000000000000003; }
  308 0       352  
  308         177  
657 0         0 elsif ( $c > 127 ) { $d2 += 2.6600000000000001; }
658 0         0 else { $d2 += 1.3300000000000001; }
659 308         200 my $c1 = $c;
660 308 50       254 if( isIUpper($c) ) { $c1 = ord lc chr $c; }
  308         227  
661 308 50       282 if( isILower($c) ) { $c1 = ord uc chr $c; }
  0         0  
662              
663 308 50       189 if ( @{ $C1[$c1] } == 1) { $d3 += 0.66000000000000003; }
  308 50       423  
  0         0  
664 0         0 elsif ( $c1 > 127 ) { $d3 += 2.6600000000000001; }
665 308         187 else { $d3 += 1.3300000000000001; }
666              
667 308         210 $d4++;
668              
669 308 100       549 if($j - $k >= 4) {
670 62 0 33     84 return E_ASCII if $d + 1.0 <= $d2 and $d + 1.0 <= $d3 and $d + 1.0 <= $d4;
      33        
671 62 50       74 return E_BASE256 if $d4 + 1.0 <= $d;
672 62 50 33     161 return E_BASE256 if $d4 + 1.0 < $d3 and $d4 + 1.0 < $d2;
673 62 0 33     82 return E_TEXT if $d3 + 1.0 < $d and $d3 + 1.0 < $d2 and $d3 + 1.0 < $d4;
      33        
674 62 50 66     246 return E_C40 if $d2 + 1.0 < $d and $d2 + 1.0 < $d3 and $d2 + 1.0 < $d4;
      66        
675             }
676             }
677              
678 4         4 $d = int( $d + 0.5 );
679 4         4 $d2 = int( $d2 + 0.5 );
680 4         3 $d3 = int( $d3 + 0.5 );
681 4         4 $d4 = int( $d4 + 0.5 );
682 4 0 33     7 return E_ASCII if $d <= $d2 and $d <= $d3 and $d <= $d4;
      33        
683 4 0 33     9 return E_TEXT if $d3 < $d and $d3 < $d2 and $d3 < $d4;
      33        
684 4 0 33     9 return E_BASE256 if $d4 < $d and $d4 < $d3 and $d4 < $d2;
      33        
685 4         6 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 39 my $self = shift;
696 66         71 my ($i,$ai,$ai1,$ai2,$flag,$flag1,$flag2) = @_;
697 66         55 my $j = my $k = 0;
698 66         80 my $ai3 = [ 0, 0, 0 ];
699 66         52 my $flag3 = 0;
700 66         39 my $as = [ ];
701 66 100       82 if($flag1) {
702 6 100       15 $ai2->[$j++] = $flag ? 239 : 230;
703             }
704 66         106 for(my $j1 = $ai->[0]; $j1 < $i; $j1++) {
705 558         361 my $l = $ai1->[$j1];
706 558 100       559 if($flag) {
707 186         129 my $s = chr($l);
708 186 50 33     256 $s = uc($s) if($l >= 97 && $l <= 122);
709 186 50 33     432 $s = lc($s) if($l >= 65 && $l <= 90);
710 186         139 $l = ord(substr($s,0,1));
711             }
712 558         353 my $ai4 = $C1[$l];
713 558         548 for my $l1 (0 .. $#$ai4) {
714 744         498 $ai3->[$k++] = $ai4->[$l1];
715 744 100       900 if($k == 3) {
716 248         228 my $i2 = $ai3->[0] * 1600 + $ai3->[1] * 40 + $ai3->[2] + 1;
717 248         223 $ai2->[$j++] = int $i2 / 256;
718 248         193 $ai2->[$j++] = $i2 % 256;
719 248         206 $k = 0;
720             }
721             }
722              
723 558 100 100     1271 if($flag2 && $k == 0) {
724 62         49 $self->{C49rest} = $k;
725 62         53 $ai->[0] = $j1 + 1;
726 62 100       70 $ai2->[$j++] = 254 if($ai->[0] == $i);
727 62         92 return $j;
728             }
729             }
730              
731 4         3 $ai->[0] = $i;
732 4 50       9 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         7 $ai2->[$j++] = 254;
749             }
750 4         6 $self->{C49rest} = $k;
751 4         6 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 107 my ($V,$P) = @_;
773 188         275 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 4 my $self = shift;
794 2         2 my ($i,$hint,$src,$stat,$res,$flag) = @_;
795 2         3 my $j = 0;
796 2         2 my $xv = [];
797 2         3 my $l = $stat->[0];
798 2         3 my $flag1 = 0;
799 2         3 my $j1 = 0;
800 2 50       5 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
801 2 50       5 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
802 2         5 for( $j1 = $hint->[0]; $j1 < $i; $j1++){
803 186         124 $xv->[$j++] = $src->[$j1];
804 186 50 33     326 last if $flag and $self->SelectEncoding($j1 + 1,$src,E_BASE256) != E_BASE256;
805             }
806 2 50       5 warn "AI1{".hexary($src)."}\n" if $DEBUG{B256};
807 2 50       5 warn "AI4{".hexary($xv)."}\n" if $DEBUG{B256};
808 2         3 $hint->[0] = $j1;
809 2         4 $res->[$l++] = 231;
810 2 50       4 if($j < 250) {
811 2         5 $res->[$l++] = state255($j, $l + 1);
812             } else {
813 0         0 $res->[$l++] = state255(249 + ($i - $i % 250) / 250, $l + 1);
814 0         0 $res->[$l++] = state255($i % 250, $l + 1);
815             }
816 2         10 $res->[$l++] = state255($xv->[$_], $l + 1) for 0..$j-1;
817 2         4 $stat->[0] = $l;
818 2         6 return $l;
819             }
820              
821             =head2 GenData (ai)
822              
823             Generate and return the data for the DataMatrix bitmap from the input array.
824              
825             =cut
826              
827             sub GenData { # CC (int ai[]) : int[][]
828 12     12 1 15 my $self = shift;
829 12         16 my ($ai) = @_;
830 12 50       28 warn "[CC] GenData: ".join(",",@$ai)." [$self->{rows} x $self->{cols} : $self->{regions} : $self->{datacols}x$self->{datarows}]\n" if $DEBUG{TRACE};
831 12         34 my $ai1 = [ map { [ (undef) x $self->{rows} ] } 1..$self->{cols} ]; # reverse cols/rows here, for correct access ->[][]
  390         825  
832              
833 12         31 my $i = my $j = 0;
834             # Draw border
835 12 50       36 if($self->{regions} == 2) {
836 0         0 FillBorder($ai1, $i, $j, $self->{datacols} + 2, $self->{datarows} + 2);
837 0         0 FillBorder($ai1, $i + $self->{datacols} + 2, $j, $self->{datacols} + 2, $self->{datarows} + 2);
838             } else {
839 12         34 my $k = int(sqrt($self->{regions}));
840 12         30 for(my $l = 0; $l < $k; $l++){
841 20         44 for(my $i1 = 0; $i1 < $k; $i1++) {
842             FillBorder($ai1, $i + $l * ($self->{datacols} + 2), $j
843             + $i1 * ($self->{datarows} + 2),
844 42         100 $self->{datacols} + 2, $self->{datarows} + 2);
845             }
846             }
847              
848             }
849             # End draw border
850 12         508 my $ai2 = [ (undef) x ( ($self->{mapcols} + 10) * $self->{maprows} ) ];
851 12 50       31 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
852 12         40 FillCharData($self->{mapcols},$self->{maprows},$ai2);
853 12 50       33 warn "[" . join (" ", grep { +defined } @$ai2)."]\n" if $DEBUG{CALC};
  0         0  
854 12 50       22 warn "--------------\n" if $DEBUG{CALC};
855 12 50       24 warn "[" . join (" ", grep { +defined } @$ai)."]\n" if $DEBUG{CALC};
  0         0  
856 12         17 my $j1 = 1;
857 12         11 my $flag = 0;
858 12         9 my $flag1 = 0;
859 12         30 for(my $i2 = 0; $i2 < $self->{maprows}; $i2++) {
860 350         203 my $j2 = 1;
861 350         408 for(my $k2 = 0; $k2 < $self->{mapcols}; $k2++) {
862 14076         8940 my $l1 = $k2 + $j2;
863 14076         8289 my $k1 = $i2 + $j1;
864 14076 100       14775 if($ai2->[$i2 * $self->{mapcols} + $k2] > 9) {
865 14064         13337 my $l2 = int ( $ai2->[$i2 * $self->{mapcols} + $k2] / 10 );
866 14064         10451 my $i3 = $ai2->[$i2 * $self->{mapcols} + $k2] % 10;
867 14064         10696 my $j3 = $ai->[$l2 - 1] & 1 << 8 - $i3;
868 14064         10133 $ai1->[$l1][$k1] = $j3;
869             } else {
870 12         14 $ai1->[$l1][$k1] = $ai2->[$i2 * $self->{mapcols} + $k2];
871             }
872 14076 100 100     43382 if($k2 > 0 && ($k2 + 1) % $self->{datacols} == 0) {
873 742         1027 $j2 += 2;
874             }
875             }
876              
877 350 100 100     1131 if($i2 > 0 && ($i2 + 1) % $self->{datarows} == 0) {
878 20         32 $j1 += 2;
879             }
880             }
881 12         378 return $ai1;
882             }
883              
884             =head2 FillBorder (ai, i, j, k, l)
885              
886             Fill the border of the ECC200 data matrix bitmap.
887              
888             =cut
889              
890             sub FillBorder { # CD (int ai[][], int i, int j, int k, int l) : void
891 42     42 1 33 my ($ai,$i,$j,$k,$l) = @_;
892 42         32 my $i1 = 0;
893 42         62 for(my $k1 = 0; $k1 < $k; $k1++) {
894 826 100       785 $i1 = ($k1 % 2 == 0) ? 1 : 0;
895 826         633 $ai->[$i + $k1][$j + $l - 1] = 1;
896 826         1029 $ai->[$i + $k1][$j] = $i1;
897             }
898 42         24 $i1 = 0;
899 42         77 for(my $l1 = 0; $l1 < $l; $l1++) {
900 826 100       816 my $j1 = (($l1 + 1) % 2 == 0) ? 1 : 0;
901 826         541 $ai->[$i][$j + $l1] = 1;
902 826         1185 $ai->[$i + $k - 1][$j + $l1] = $j1;
903             }
904             }
905              
906             =head2 FillCharData (ncol, nrow, array)
907              
908             Fill the data matrix with the character data in the given message array.
909              
910             =cut
911              
912             sub FillCharData { # (int ncol; int nrow; int array;) : void
913 12     12 1 16 my ($ncol,$nrow,$array) = @_;
914 12         70 Barcode::DataMatrix::CharDataFiller->new($ncol,$nrow,$array);
915 12         16 return;
916             }
917              
918             1;