Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
147 - 1
<?php
2
/*
3
 *  BarCode Coder Library (BCC Library)
4
 *  BCCL Version 2.0
5
 *
6
 *  Porting : PHP
7
 *  Version : 2.0.4
8
 *
9
 *  Date    : 2013-01-06
10
 *  Author  : DEMONTE Jean-Baptiste <jbdemonte@gmail.com>
11
 *            HOUREZ Jonathan
12
 *
13
 *  Date    : 2013-12-24
14
 *  Leszek Boroch <borek@borek.net.pl>
15
 *  Modification in class Barcode128 to enable encoding extended characters
16
 *  (ASCII above 127). To use barcodes, keypad emulation must be enabled in scanner configuration
17
 *  (tested with Motorola/Symbol LS2208).
18
 *
19
 *  Web site: http://barcode-coder.com/
20
 *  dual licence :  http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
21
 *                  http://www.gnu.org/licenses/gpl.html
22
 */
23
 
24
class Barcode {
25
 
26
    static public function gd($res, $color, $x, $y, $angle, $type, $datas, $width = null, $height = null){
27
        return self::_draw(__FUNCTION__, $res, $color, $x, $y, $angle, $type, $datas, $width, $height);
28
    }
29
 
30
    static public function fpdf($res, $color, $x, $y, $angle, $type, $datas, $width = null, $height = null){
31
        return self::_draw(__FUNCTION__, $res, $color, $x, $y, $angle, $type, $datas, $width, $height);
32
    }
33
 
34
	static public function raw($type, $datas) {
35
		$digit = '';
36
        $hri   = '';
37
        $code  = '';
38
        $crc   = true;
39
		$rect  = false;
40
 
41
        if (is_array($datas)){
42
            foreach(array('code' => '', 'crc' => true, 'rect' => false) as $v => $def){
43
                $$v = isset($datas[$v]) ? $datas[$v] : $def;
44
            }
45
            $code = $code;
46
        } else {
47
            $code = $datas;
48
        }
49
        if ($code == '') return false;
50
        $code = (string) $code;
51
 
52
        $type = strtolower($type);
53
 
54
        switch($type){
55
            case 'std25':
56
            case 'int25':
57
                $digit = BarcodeI25::getDigit($code, $crc, $type);
58
                $hri = BarcodeI25::compute($code, $crc, $type);
59
                break;
60
            case 'ean8':
61
            case 'ean13':
62
                $digit = BarcodeEAN::getDigit($code, $type);
63
                $hri = BarcodeEAN::compute($code, $type);
64
                break;
65
            case 'upc':
66
                $digit = BarcodeUPC::getDigit($code);
67
                $hri = BarcodeUPC::compute($code);
68
                break;
69
            case 'code11':
70
                $digit = Barcode11::getDigit($code);
71
                $hri = $code;
72
                break;
73
            case 'code39':
74
                $digit = Barcode39::getDigit($code);
75
                $hri = $code;
76
                break;
77
            case 'code93':
78
                $digit = Barcode93::getDigit($code, $crc);
79
                $hri = $code;
80
                break;
81
            case 'code128':
82
                $digit = Barcode128::getDigit($code);
83
                $hri = $code;
84
                break;
85
            case 'codabar':
86
                $digit = BarcodeCodabar::getDigit($code);
87
                $hri = $code;
88
                break;
89
            case 'msi':
90
                $digit = BarcodeMSI::getDigit($code, $crc);
91
                $hri = BarcodeMSI::compute($code, $crc);
92
                break;
93
            case 'datamatrix':
94
                $digit = BarcodeDatamatrix::getDigit($code, $rect);
95
                $hri = $code;
96
                break;
97
        }
98
 
99
		return array($digit, $hri);
100
	}
101
 
102
    static private function _draw($call, $res, $color, $x, $y, $angle, $type, $datas, $width, $height){
103
        $digit = '';
104
        $hri   = '';
105
 
106
		list($digit, $hri) = self::raw($type, $datas);
107
 
108
        $type = strtolower($type);
109
 
110
        if ($digit == '') return false;
111
 
112
        if ($type == 'datamatrix'){
113
            $width = is_null($width) ? 5 : $width;
114
            $height = $width;
115
        } else {
116
            $width = is_null($width) ? 1 : $width;
117
            $height = is_null($height) ? 50 : $height;
118
            $digit = self::bitStringTo2DArray($digit);
119
        }
120
 
121
        if ( $call == 'gd' ){
122
            $result = self::digitToGDRenderer($res, $color, $x, $y, $angle, $width, $height, $digit);
123
        } else if ( $call == 'fpdf' ){
124
            $result = self::digitToFPDFRenderer($res, $color, $x, $y, $angle, $width, $height, $digit);
125
        }
126
 
127
        $result['hri'] = $hri;
128
        return $result;
129
    }
130
 
131
    // convert a bit string to an array of array of bit char
132
    public static function bitStringTo2DArray( $digit ){
133
        $d = array();
134
        $len = strlen($digit);
135
        for($i=0; $i<$len; $i++) $d[$i] = $digit[$i];
136
        return(array($d));
137
    }
138
 
139
    public static function digitToRenderer($fn, $xi, $yi, $angle, $mw, $mh, $digit){
140
        $lines = count($digit);
141
        $columns = count($digit[0]);
142
        $angle = deg2rad(-$angle);
143
        $cos = cos($angle);
144
        $sin = sin($angle);
145
 
146
        self::_rotate($columns * $mw / 2, $lines * $mh / 2, $cos, $sin , $x, $y);
147
        $xi -=$x;
148
        $yi -=$y;
149
        for($y=0; $y<$lines; $y++){
150
            $x = -1;
151
            while($x < ($columns-1)) {
152
                $x++;
153
                if ($digit[$y][$x] == '1') {
154
                    $z = $x;
155
                    while(($z + 1 <$columns) && ($digit[$y][$z + 1] == '1')) {
156
                        $z++;
157
                    }
158
                    $x1 = $x * $mw;
159
                    $y1 = $y * $mh;
160
                    $x2 = ($z + 1) * $mw;
161
                    $y2 = ($y + 1) * $mh;
162
                    self::_rotate($x1, $y1, $cos, $sin, $xA, $yA);
163
                    self::_rotate($x2, $y1, $cos, $sin, $xB, $yB);
164
                    self::_rotate($x2, $y2, $cos, $sin, $xC, $yC);
165
                    self::_rotate($x1, $y2, $cos, $sin, $xD, $yD);
166
                    $fn(array(
167
                        $xA + $xi, $yA + $yi,
168
                        $xB + $xi, $yB + $yi,
169
                        $xC + $xi, $yC + $yi,
170
                        $xD + $xi, $yD + $yi
171
                    ));
172
                    $x = $z + 1;
173
                }
174
            }
175
        }
176
        return self::result($xi, $yi, $columns, $lines, $mw, $mh, $cos, $sin);
177
    }
178
 
179
    // GD barcode renderer
180
    private static function digitToGDRenderer($gd, $color, $xi, $yi, $angle, $mw, $mh, $digit){
181
        $fn = function($points) use ($gd, $color) {
182
            imagefilledpolygon($gd, $points, 4, $color);
183
        };
184
        return self::digitToRenderer($fn, $xi, $yi, $angle, $mw, $mh, $digit);
185
    }
186
    // FPDF barcode renderer
187
    private static function digitToFPDFRenderer($pdf, $color, $xi, $yi, $angle, $mw, $mh, $digit){
188
        if (!is_array($color)){
189
            if (preg_match('`([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})`i', $color, $m)){
190
                $color = array(hexdec($m[1]),hexdec($m[2]),hexdec($m[3]));
191
            } else {
192
                $color = array(0,0,0);
193
            }
194
        }
195
        $color = array_values($color);
196
        $pdf->SetDrawColor($color[0],$color[1],$color[2]);
197
        $pdf->SetFillColor($color[0],$color[1],$color[2]);
198
 
199
        $fn = function($points) use ($pdf)
200
        {
201
            $op = 'f';
202
            $h = $pdf->h;
203
            $k = $pdf->k;
204
            $points_string = '';
205
            for($i=0; $i < 8; $i+=2){
206
                $points_string .= sprintf('%.2F %.2F', $points[$i]*$k, ($h-$points[$i+1])*$k);
207
                $points_string .= $i ? ' l ' : ' m ';
208
            }
209
            $pdf->_out($points_string . $op);
210
        };
211
        return self::digitToRenderer($fn, $xi, $yi, $angle, $mw, $mh, $digit);
212
    }
213
 
214
    static private function result($xi, $yi, $columns, $lines, $mw, $mh, $cos, $sin){
215
        self::_rotate(0, 0, $cos, $sin , $x1, $y1);
216
        self::_rotate($columns * $mw, 0, $cos, $sin , $x2, $y2);
217
        self::_rotate($columns * $mw, $lines * $mh, $cos, $sin , $x3, $y3);
218
        self::_rotate(0, $lines * $mh, $cos, $sin , $x4, $y4);
219
 
220
        return array(
221
            'width' => $columns * $mw,
222
            'height'=> $lines * $mh,
223
            'p1' => array(
224
                'x' => $xi + $x1,
225
                'y' => $yi + $y1
226
            ),
227
            'p2' => array(
228
                'x' => $xi + $x2,
229
                'y' => $yi + $y2
230
            ),
231
            'p3' => array(
232
                'x' => $xi + $x3,
233
                'y' => $yi + $y3
234
            ),
235
            'p4' => array(
236
                'x' => $xi + $x4,
237
                'y' => $yi + $y4
238
            )
239
        );
240
    }
241
 
242
    static private function _rotate($x1, $y1, $cos, $sin , &$x, &$y){
243
        $x = $x1 * $cos - $y1 * $sin;
244
        $y = $x1 * $sin + $y1 * $cos;
245
    }
246
 
247
    static public function rotate($x1, $y1, $angle , &$x, &$y){
248
        $angle = deg2rad(-$angle);
249
        $cos = cos($angle);
250
        $sin = sin($angle);
251
        $x = $x1 * $cos - $y1 * $sin;
252
        $y = $x1 * $sin + $y1 * $cos;
253
    }
254
}
255
 
256
class BarcodeI25 {
257
    static private $encoding = array('NNWWN', 'WNNNW', 'NWNNW', 'WWNNN', 'NNWNW', 'WNWNN', 'NWWNN', 'NNNWW', 'WNNWN','NWNWN');
258
 
259
    static public function compute($code, $crc, $type){
260
        if (! $crc) {
261
            if (strlen($code) % 2) $code = '0' . $code;
262
        } else {
263
            if ( ($type == 'int25') && (strlen($code) % 2 == 0) ) $code = '0' . $code;
264
            $odd = true;
265
            $sum = 0;
266
            for($i=strlen($code)-1; $i>-1; $i--){
267
                $v = intval($code[$i]);
268
                $sum += $odd ? 3 * $v : $v;
269
                $odd = ! $odd;
270
            }
271
            $code .= (string) ((10 - $sum % 10) % 10);
272
        }
273
        return($code);
274
    }
275
 
276
    static public function getDigit($code, $crc, $type){
277
        $code = self::compute($code, $crc, $type);
278
        if ($code == '') return($code);
279
        $result = '';
280
 
281
        if ($type == 'int25') { // Interleaved 2 of 5
282
            // start
283
            $result .= '1010';
284
 
285
            // digits + CRC
286
            $end = strlen($code) / 2;
287
            for($i=0; $i<$end; $i++){
288
                $c1 = $code[2*$i];
289
                $c2 = $code[2*$i+1];
290
                for($j=0; $j<5; $j++){
291
                    $result .= '1';
292
                    if (self::$encoding[$c1][$j] == 'W') $result .= '1';
293
                    $result .= '0';
294
                    if (self::$encoding[$c2][$j] == 'W') $result .= '0';
295
                }
296
            }
297
            // stop
298
            $result .= '1101';
299
        } else if ($type == 'std25') {
300
            // Standard 2 of 5 is a numeric-only barcode that has been in use a long time.
301
            // Unlike Interleaved 2 of 5, all of the information is encoded in the bars; the spaces are fixed width and are used only to separate the bars.
302
            // The code is self-checking and does not include a checksum.
303
 
304
            // start
305
            $result .= '11011010';
306
 
307
            // digits + CRC
308
            $end = strlen($code);
309
            for($i=0; $i<$end; $i++){
310
                $c = $code[$i];
311
                for($j=0; $j<5; $j++){
312
                    $result .= '1';
313
                    if (self::$encoding[$c][$j] == 'W') $result .= '11';
314
                    $result .= '0';
315
                }
316
            }
317
            // stop
318
            $result .= '11010110';
319
        }
320
        return($result);
321
    }
322
}
323
 
324
 
325
class BarcodeEAN {
326
    static private $encoding = array(
327
        array('0001101', '0100111', '1110010'),
328
        array('0011001', '0110011', '1100110'),
329
        array('0010011', '0011011', '1101100'),
330
        array('0111101', '0100001', '1000010'),
331
        array('0100011', '0011101', '1011100'),
332
        array('0110001', '0111001', '1001110'),
333
        array('0101111', '0000101', '1010000'),
334
        array('0111011', '0010001', '1000100'),
335
        array('0110111', '0001001', '1001000'),
336
        array('0001011', '0010111', '1110100')
337
    );
338
 
339
    static private $first = array('000000','001011','001101','001110','010011','011001','011100','010101','010110','011010');
340
 
341
    static public function getDigit($code, $type){
342
        // Check len (12 for ean13, 7 for ean8)
343
        $len = $type == 'ean8' ? 7 : 12;
344
        $code = substr($code, 0, $len);
345
        if (!preg_match('`[0-9]{'.$len.'}`', $code)) return('');
346
 
347
        // get checksum
348
        $code = self::compute($code, $type);
349
 
350
        // process analyse
351
        $result = '101'; // start
352
 
353
        if ($type == 'ean8'){
354
            // process left part
355
            for($i=0; $i<4; $i++){
356
                $result .= self::$encoding[intval($code[$i])][0];
357
            }
358
 
359
            // center guard bars
360
            $result .= '01010';
361
 
362
            // process right part
363
            for($i=4; $i<8; $i++){
364
                $result .= self::$encoding[intval($code[$i])][2];
365
            }
366
 
367
        } else { // ean13
368
            // extract first digit and get sequence
369
            $seq = self::$first[ intval($code[0]) ];
370
 
371
            // process left part
372
            for($i=1; $i<7; $i++){
373
                $result .= self::$encoding[intval($code[$i])][ intval($seq[$i-1]) ];
374
            }
375
 
376
            // center guard bars
377
            $result .= '01010';
378
 
379
            // process right part
380
            for($i=7; $i<13; $i++){
381
                $result .= self::$encoding[intval($code[$i])][ 2 ];
382
            }
383
        } // ean13
384
 
385
        $result .= '101'; // stop
386
        return($result);
387
    }
388
 
389
    static public function compute($code, $type){
390
        $len = $type == 'ean13' ? 12 : 7;
391
        $code = substr($code, 0, $len);
392
        if (!preg_match('`[0-9]{'.$len.'}`', $code)) return('');
393
        $sum = 0;
394
        $odd = true;
395
        for($i=$len-1; $i>-1; $i--){
396
            $sum += ($odd ? 3 : 1) * intval($code[$i]);
397
            $odd = ! $odd;
398
        }
399
        return($code . ( (string) ((10 - $sum % 10) % 10)));
400
    }
401
}
402
 
403
class BarcodeUPC {
404
 
405
    static public function getDigit($code){
406
        if (strlen($code) < 12) {
407
            $code = '0' . $code;
408
        }
409
        return BarcodeEAN::getDigit($code, 'ean13');
410
    }
411
 
412
    static public function compute($code){
413
        if (strlen($code) < 12) {
414
            $code = '0' . $code;
415
        }
416
        return substr(BarcodeEAN::compute($code, 'ean13'), 1);
417
    }
418
}
419
 
420
class BarcodeMSI {
421
    static private $encoding = array(
422
        '100100100100', '100100100110', '100100110100', '100100110110',
423
        '100110100100', '100110100110', '100110110100', '100110110110',
424
        '110100100100', '110100100110');
425
 
426
    static public function compute($code, $crc){
427
        if (is_array($crc)){
428
            if ($crc['crc1'] == 'mod10'){
429
                $code = self::computeMod10($code);
430
            } else if ($crc['crc1'] == 'mod11'){
431
                $code = self::computeMod11($code);
432
            }
433
            if ($crc['crc2'] == 'mod10'){
434
                $code = self::computeMod10($code);
435
            } else if ($crc['crc2'] == 'mod11'){
436
                $code = self::computeMod11($code);
437
            }
438
        } else if ($crc){
439
            $code = self::computeMod10($code);
440
        }
441
        return($code);
442
    }
443
 
444
    static private function computeMod10($code){
445
        $len = strlen($code);
446
        $toPart1 = $len % 2;
447
        $n1 = 0;
448
        $sum = 0;
449
        for($i=0; $i<$len; $i++){
450
            if ($toPart1) {
451
                $n1 = 10 * $n1 + intval($code[$i]);
452
            } else {
453
                $sum += intval($code[$i]);
454
            }
455
            $toPart1 = ! $toPart1;
456
        }
457
        $s1 = (string) (2 * $n1);
458
        $len = strlen($s1);
459
        for($i=0; $i<$len; $i++){
460
            $sum += intval($s1[$i]);
461
        }
462
        return($code . ( (string) (10 - $sum % 10) % 10));
463
    }
464
 
465
    static private function computeMod11($code){
466
        $sum = 0;
467
        $weight = 2;
468
        for($i=strlen($code)-1; $i>-1; $i--){
469
            $sum += $weight * intval($code[$i]);
470
            $weight = $weight == 7 ? 2 : $weight + 1;
471
        }
472
        return($code . ( (string) (11 - $sum % 11) % 11) );
473
    }
474
 
475
    static public function getDigit($code, $crc){
476
        if (preg_match('`[^0-9]`', $code)) return '';
477
        $index = 0;
478
        $result = '';
479
 
480
        $code = self::compute($code, false);
481
 
482
        // start
483
        $result = '110';
484
 
485
        // digits
486
        $len = strlen($code);
487
        for($i=0; $i<$len; $i++){
488
            $result .= self::$encoding[ intval($code[$i]) ];
489
        }
490
 
491
        // stop
492
        $result .= '1001';
493
 
494
        return($result);
495
    }
496
}
497
 
498
class Barcode11 {
499
    static private $encoding = array(
500
        '101011', '1101011', '1001011', '1100101',
501
        '1011011', '1101101', '1001101', '1010011',
502
        '1101001', '110101', '101101');
503
 
504
    static public function getDigit($code){
505
        if (preg_match('`[^0-9\-]`', $code)) return '';
506
        $result = '';
507
        $intercharacter = '0';
508
 
509
        // start
510
        $result = '1011001' . $intercharacter;
511
 
512
        // digits
513
        $len = strlen($code);
514
        for($i=0; $i<$len; $i++){
515
            $index = $code[$i] == '-' ? 10 : intval($code[$i]);
516
            $result .= self::$encoding[ $index ] . $intercharacter;
517
        }
518
 
519
        // checksum
520
        $weightC    = 0;
521
        $weightSumC = 0;
522
        $weightK    = 1; // start at 1 because the right-most character is 'C' checksum
523
        $weightSumK = 0;
524
        for($i=$len-1; $i>-1; $i--){
525
            $weightC = $weightC == 10 ? 1 : $weightC + 1;
526
            $weightK = $weightK == 10 ? 1 : $weightK + 1;
527
 
528
            $index = $code[$i] == '-' ? 10 : intval($code[$i]);
529
 
530
            $weightSumC += $weightC * $index;
531
            $weightSumK += $weightK * $index;
532
        }
533
 
534
        $c = $weightSumC % 11;
535
        $weightSumK += $c;
536
        $k = $weightSumK % 11;
537
 
538
        $result .= self::$encoding[$c] . $intercharacter;
539
 
540
        if ($len >= 10){
541
            $result .= self::$encoding[$k] . $intercharacter;
542
        }
543
 
544
        // stop
545
        $result  .= '1011001';
546
 
547
        return($result);
548
    }
549
}
550
 
551
class Barcode39 {
552
    static private $encoding = array(
553
        '101001101101', '110100101011', '101100101011', '110110010101',
554
        '101001101011', '110100110101', '101100110101', '101001011011',
555
        '110100101101', '101100101101', '110101001011', '101101001011',
556
        '110110100101', '101011001011', '110101100101', '101101100101',
557
        '101010011011', '110101001101', '101101001101', '101011001101',
558
        '110101010011', '101101010011', '110110101001', '101011010011',
559
        '110101101001', '101101101001', '101010110011', '110101011001',
560
        '101101011001', '101011011001', '110010101011', '100110101011',
561
        '110011010101', '100101101011', '110010110101', '100110110101',
562
        '100101011011', '110010101101', '100110101101', '100100100101',
563
        '100100101001', '100101001001', '101001001001', '100101101101');
564
    static public function getDigit($code){
565
        $table = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*';
566
        $result = '';
567
        $intercharacter = '0';
568
 
569
        if (strpos($code, '*') !== false) return('');
570
 
571
        // Add Start and Stop charactere : *
572
        $code = strtoupper('*' . $code . '*');
573
 
574
        $len = strlen($code);
575
        for($i=0; $i<$len; $i++){
576
            $index = strpos($table, $code[$i]);
577
            if ($index === false) return('');
578
            if ($i > 0) $result .= $intercharacter;
579
            $result .= self::$encoding[ $index ];
580
        }
581
        return($result);
582
    }
583
}
584
 
585
class Barcode93{
586
    static private $encoding = array(
587
        '100010100', '101001000', '101000100', '101000010',
588
        '100101000', '100100100', '100100010', '101010000',
589
        '100010010', '100001010', '110101000', '110100100',
590
        '110100010', '110010100', '110010010', '110001010',
591
        '101101000', '101100100', '101100010', '100110100',
592
        '100011010', '101011000', '101001100', '101000110',
593
        '100101100', '100010110', '110110100', '110110010',
594
        '110101100', '110100110', '110010110', '110011010',
595
        '101101100', '101100110', '100110110', '100111010',
596
        '100101110', '111010100', '111010010', '111001010',
597
        '101101110', '101110110', '110101110', '100100110',
598
        '111011010', '111010110', '100110010', '101011110');
599
 
600
    static public function getDigit($code, $crc){
601
        $table = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%____*'; // _ => ($), (%), (/) et (+)
602
        $result = '';
603
 
604
        if (strpos($code, '*') !== false) return('');
605
 
606
        $code = strtoupper($code);
607
 
608
        // start :  *
609
        $result  .= self::$encoding[47];
610
 
611
        // digits
612
        $len = strlen($code);
613
        for($i=0; $i<$len; $i++){
614
            $c = $code[$i];
615
            $index = strpos($table, $c);
616
            if ( ($c == '_') || ($index === false) ) return('');
617
            $result .= self::$encoding[ $index ];
618
        }
619
 
620
        // checksum
621
        if ($crc){
622
            $weightC    = 0;
623
            $weightSumC = 0;
624
            $weightK    = 1; // start at 1 because the right-most character is 'C' checksum
625
            $weightSumK = 0;
626
            for($i=$len-1; $i>-1; $i--){
627
                $weightC = $weightC == 20 ? 1 : $weightC + 1;
628
                $weightK = $weightK == 15 ? 1 : $weightK + 1;
629
 
630
                $index = strpos($table, $code[$i]);
631
 
632
                $weightSumC += $weightC * $index;
633
                $weightSumK += $weightK * $index;
634
            }
635
 
636
            $c = $weightSumC % 47;
637
            $weightSumK += $c;
638
            $k = $weightSumK % 47;
639
 
640
            $result .= self::$encoding[$c];
641
            $result .= self::$encoding[$k];
642
        }
643
 
644
        // stop : *
645
        $result  .= self::$encoding[47];
646
 
647
        // Terminaison bar
648
        $result  .= '1';
649
        return($result);
650
    }
651
}
652
 
653
class Barcode128 {
654
    static private $encoding = array(
655
               // descriptive encoding array, helpful when debugging
656
               // Value	Table A	Table B	Table C	ASCII Code	Character	Pattern
657
'11011001100', //  0	Space	Space	00	0032 or 0212	Space or O	11011001100
658
'11001101100', //  1	!	!	01	0033	!	11001101100
659
'11001100110', //  2	"	"	02	0034	"	11001100110
660
'10010011000', //  3	#	#	03	0035	#	10010011000
661
'10010001100', //  4	$	$	04	0036	$	10010001100
662
'10001001100', //  5	%	%	05	0037	%	10001001100
663
'10011001000', //  6	&	&	06	0038	&	10011001000
664
'10011000100', //  7	'	'	07	0039	'	10011000100
665
'10001100100', //  8	(	(	08	0040	(	10001100100
666
'11001001000', //  9	)	)	09	0041	)	11001001000
667
'11001000100', //  10	*	*	10	0042	*	11001000100
668
'11000100100', //  11	+	+	11	0043	+	11000100100
669
'10110011100', //  12	,	,	12	0044	,	10110011100
670
'10011011100', //  13	-	-	13	0045	-	10011011100
671
'10011001110', //  14	.	.	14	0046	.	10011001110
672
'10111001100', //  15	/	/	15	0047	/	10111001100
673
'10011101100', //  16	0	0	16	0048	0	10011101100
674
'10011100110', //  17	1	1	17	0049	1	10011100110
675
'11001110010', //  18	2	2	18	0050	2	11001110010
676
'11001011100', //  19	3	3	19	0051	3	11001011100
677
'11001001110', //  20	4	4	20	0052	4	11001001110
678
'11011100100', //  21	5	5	21	0053	5	11011100100
679
'11001110100', //  22	6	6	22	0054	6	11001110100
680
'11101101110', //  23	7	7	23	0055	7	11101101110
681
'11101001100', //  24	8	8	24	0056	8	11101001100
682
'11100101100', //  25	9	9	25	0057	9	11100101100
683
'11100100110', //  26	:	:	26	0058	:	11100100110
684
'11101100100', //  27	;	;	27	0059	;	11101100100
685
'11100110100', //  28	<	<	28	0060	<	11100110100
686
'11100110010', //  29	=	=	29	0061	=	11100110010
687
'11011011000', //  30	>	>	30	0062	>	11011011000
688
'11011000110', //  31	?	?	31	0063	?	11011000110
689
'11000110110', //  32	@	@	32	0064	@	11000110110
690
'10100011000', //  33	A	A	33	0065	A	10100011000
691
'10001011000', //  34	B	B	34	0066	B	10001011000
692
'10001000110', //  35	C	C	35	0067	C	10001000110
693
'10110001000', //  36	D	D	36	0068	D	10110001000
694
'10001101000', //  37	E	E	37	0069	E	10001101000
695
'10001100010', //  38	F	F	38	0070	F	10001100010
696
'11010001000', //  39	G	G	39	0071	G	11010001000
697
'11000101000', //  40	H	H	40	0072	H	11000101000
698
'11000100010', //  41	I	I	41	0073	I	11000100010
699
'10110111000', //  42	J	J	42	0074	J	10110111000
700
'10110001110', //  43	K	K	43	0075	K	10110001110
701
'10001101110', //  44	L	L	44	0076	L	10001101110
702
'10111011000', //  45	M	M	45	0077	M	10111011000
703
'10111000110', //  46	N	N	46	0078	N	10111000110
704
'10001110110', //  47	O	O	47	0079	O	10001110110
705
'11101110110', //  48	P	P	48	0080	P	11101110110
706
'11010001110', //  49	Q	Q	49	0081	Q	11010001110
707
'11000101110', //  50	R	R	50	0082	R	11000101110
708
'11011101000', //  51	S	S	51	0083	S	11011101000
709
'11011100010', //  52	T	T	52	0084	T	11011100010
710
'11011101110', //  53	U	U	53	0085	U	11011101110
711
'11101011000', //  54	V	V	54	0086	V	11101011000
712
'11101000110', //  55	W	W	55	0087	W	11101000110
713
'11100010110', //  56	X	X	56	0088	X	11100010110
714
'11101101000', //  57	Y	Y	57	0089	Y	11101101000
715
'11101100010', //  58	Z	Z	58	0090	Z	11101100010
716
'11100011010', //  59	[	[	59	0091	[	11100011010
717
'11101111010', //  60	\	\	60	0092	\	11101111010
718
'11001000010', //  61	]	]	61	0093	]	11001000010
719
'11110001010', //  62	^	^	62	0094	^	11110001010
720
'10100110000', //  63	_	_	63	0095	_	10100110000
721
'10100001100', //  64	nul	`	64	0096	`	10100001100
722
'10010110000', //  65	soh	a	65	0097	a	10010110000
723
'10010000110', //  66	stx	b	66	0098	b	10010000110
724
'10000101100', //  67	etx	c	67	0099	c	10000101100
725
'10000100110', //  68	eot	d	68	0100	d	10000100110
726
'10110010000', //  69	eno	e	69	0101	e	10110010000
727
'10110000100', //  70	ack	f	70	0102	f	10110000100
728
'10011010000', //  71	bel	g	71	0103	g	10011010000
729
'10011000010', //  72	bs	h	72	0104	h	10011000010
730
'10000110100', //  73	ht	i	73	0105	i	10000110100
731
'10000110010', //  74	lf	j	74	0106	j	10000110010
732
'11000010010', //  75	vt	k	75	0107	k	11000010010
733
'11001010000', //  76	ff	l	76	0108	l	11001010000
734
'11110111010', //  77	cr	m	77	0109	m	11110111010
735
'11000010100', //  78	s0	n	78	0110	n	11000010100
736
'10001111010', //  79	s1	o	79	0111	o	10001111010
737
'10100111100', //  80	dle	p	80	0112	p	10100111100
738
'10010111100', //  81	dc1	q	81	0113	q	10010111100
739
'10010011110', //  82	dc2	r	82	0114	r	10010011110
740
'10111100100', //  83	dc3	s	83	0115	s	10111100100
741
'10011110100', //  84	dc4	t	84	0116	t	10011110100
742
'10011110010', //  85	nak	u	85	0117	u	10011110010
743
'11110100100', //  86	syn	v	86	0118	v	11110100100
744
'11110010100', //  87	etb	w	87	0119	w	11110010100
745
'11110010010', //  88	can	x	88	0120	x	11110010010
746
'11011011110', //  89	em	y	89	0121	y	11011011110
747
'11011110110', //  90	sub	z	90	0122	z	11011110110
748
'11110110110', //  91	esc	{	91	0123	{	11110110110
749
'10101111000', //  92	fs	|	92	0124	|	10101111000
750
'10100011110', //  93	gs	}	93	0125	}	10100011110
751
'10001011110', //  94	rs	~	94	0126	~	10001011110
752
'10111101000', //  95	us	del	95	0200	E	10111101000
753
'10111100010', //  96	Fnc 3	Fnc 3	96	0201	E	10111100010
754
'11110101000', //  97	Fnc 2	Fnc2	97	0202	E	11110101000
755
'11110100010', //  98	Shift	Shift	98	0203	E	11110100010
756
'10111011110', //  99	Code C	Code C	99	0204	I	10111011110
757
'10111101110', //  100	Code B	Fnc 4	Code B	0205	I	10111101110
758
'11101011110', //  101	Fnc 4	Code A	Code A	0206	I	11101011110
759
'11110101110', //  102	Fnc 1	Fnc 1	Fnc 1	0207	I	11110101110
760
'11010000100', //  103	Start A	Start A	Start A	0208	D	11010000100
761
'11010010000', //  104	Start B	Start B	Start B	0209	N	11010010000
762
'11010011100', //  105	Start C	Start C	Start C	0210	O	11010011100
763
'11000111010'  //  106	Stop	Stop	Stop	0211	O	1100011101011
764
);
765
    static public function getDigit($code){
766
        $tableB = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
767
        $result = "";
768
        $sum = 0;
769
        $isum = 0;
770
        $i = 0;
771
        $j = 0;
772
        $value = 0;
773
 
774
        // check each characters
775
        $len = strlen($code);
776
// we allow now extended ASCII so no need to check against table B
777
//        for($i=0; $i<$len; $i++){
778
//            if (strpos($tableB, $code[$i]) === false) return("");
779
//        }
780
 
781
        // check firsts characters : start with C table only if enough numeric
782
        $tableCActivated = $len> 1;
783
        $c = '';
784
        for($i=0; $i<3 && $i<$len; $i++){
785
            $tableCActivated &= preg_match('`[0-9]`', $code[$i]);
786
        }
787
 
788
        $sum = $tableCActivated ? 105 : 104;
789
 
790
        // start : [105] : C table or [104] : B table
791
        $result = self::$encoding[ $sum ];
792
 
793
        $i = 0;
794
        while( $i < $len ){
795
            if (! $tableCActivated){
796
                $j = 0;
797
                // check next character to activate C table if interresting
798
                while ( ($i + $j < $len) && preg_match('`[0-9]`', $code[$i+$j]) ) $j++;
799
 
800
                // 6 min everywhere or 4 mini at the end
801
                $tableCActivated = ($j > 5) || (($i + $j - 1 == $len) && ($j > 3));
802
 
803
                if ( $tableCActivated ){
804
                    $result .= self::$encoding[ 99 ]; // C table
805
                    $sum += ++$isum * 99;
806
                }
807
                // 2 min for table C so need table B
808
            } else if ( ($i == $len - 1) || (preg_match('`[^0-9]`', $code[$i])) || (preg_match('`[^0-9]`', $code[$i+1])) ) { //todo : verifier le JS : len - 1!!! XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
809
                $tableCActivated = false;
810
                $result .= self::$encoding[ 100 ]; // B table
811
                $sum += ++$isum * 100;
812
            }
813
 
814
            if ( $tableCActivated ) {
815
                $value = intval(substr($code, $i, 2)); // Add two characters (numeric)
816
                $i += 2;
817
            } else {
818
                // take care of extended characters (ASCII above 127)
819
                if (ord($code[$i])>126) {
820
                    $result .= self::$encoding[ 100 ];
821
                    $sum += ++$isum * 100;
822
                    $value = strpos($tableB, chr(ord($code[$i])-128)); // Add one character
823
                } else {
824
                $value = strpos($tableB, $code[$i]); // Add one character
825
                }
826
                $i++;
827
            }
828
            $result  .= self::$encoding[ $value ];
829
            $sum += ++$isum * $value;
830
        }
831
 
832
        // Add CRC
833
        $result  .= self::$encoding[ $sum % 103 ];
834
 
835
        // Stop
836
        $result .= self::$encoding[ 106 ];
837
 
838
        // Termination bar
839
        $result .= '11';
840
 
841
        return($result);
842
    }
843
}
844
 
845
class BarcodeCodabar {
846
    static private $encoding = array(
847
        '101010011', '101011001', '101001011', '110010101',
848
        '101101001', '110101001', '100101011', '100101101',
849
        '100110101', '110100101', '101001101', '101100101',
850
        '1101011011', '1101101011', '1101101101', '1011011011',
851
        '1011001001', '1010010011', '1001001011', '1010011001');
852
 
853
    static public function getDigit($code){
854
        $table = '0123456789-$:/.+';
855
        $result = '';
856
        $intercharacter = '0';
857
 
858
        // add start : A->D : arbitrary choose A
859
        $result .= self::$encoding[16] . $intercharacter;
860
 
861
        $len = strlen($code);
862
        for($i=0; $i<$len; $i++){
863
            $index = strpos($table, $code[$i]);
864
            if ($index === false) return('');
865
            $result .= self::$encoding[ $index ] . $intercharacter;
866
        }
867
 
868
        // add stop : A->D : arbitrary choose A
869
        $result .= self::$encoding[16];
870
        return($result);
871
    }
872
}
873
 
874
class BarcodeDatamatrix {
875
    static private $lengthRows = array(
876
        10, 12, 14, 16, 18, 20, 22, 24, 26,  // 24 squares et 6 rectangular
877
        32, 36, 40, 44, 48, 52, 64, 72, 80,  88, 96, 104, 120, 132, 144,
878
        8, 8, 12, 12, 16, 16);
879
    static private $lengthCols = array(
880
        10, 12, 14, 16, 18, 20, 22, 24, 26,  // Number of columns for the entire datamatrix
881
        32, 36, 40, 44, 48, 52, 64, 72, 80, 88, 96, 104, 120, 132, 144,
882
        18, 32, 26, 36, 36, 48);
883
    static private $dataCWCount = array(
884
        3, 5, 8, 12,  18,  22,  30,  36,  // Number of data codewords for the datamatrix
885
        44, 62, 86, 114, 144, 174, 204, 280, 368, 456, 576, 696, 816, 1050,
886
        1304, 1558, 5, 10, 16, 22, 32, 49);
887
    static private $solomonCWCount = array(
888
        5, 7, 10, 12, 14, 18, 20, 24, 28, // Number of Reed-Solomon codewords for the datamatrix
889
        36, 42, 48, 56, 68, 84, 112, 144, 192, 224, 272, 336, 408, 496, 620,
890
        7, 11, 14, 18, 24, 28);
891
    static private $dataRegionRows = array(
892
        8, 10, 12, 14, 16, 18, 20, 22, // Number of rows per region
893
        24, 14, 16, 18, 20, 22, 24, 14, 16, 18, 20, 22, 24, 18, 20, 22,
894
        6,  6, 10, 10, 14, 14);
895
    static private $dataRegionCols = array(
896
        8, 10, 12, 14, 16, 18, 20, 22, // Number of columns per region
897
        24, 14, 16, 18, 20, 22, 24, 14, 16, 18, 20, 22, 24, 18, 20, 22,
898
        16, 14, 24, 16, 16, 22);
899
    static private $regionRows = array(
900
        1, 1, 1, 1, 1, 1, 1, 1, // Number of regions per row
901
        1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6,
902
        1, 1, 1, 1, 1, 1);
903
    static private $regionCols = array(
904
        1, 1, 1, 1, 1, 1, 1, 1, // Number of regions per column
905
        1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6,
906
        1, 2, 1, 2, 2, 2);
907
    static private $interleavedBlocks = array(
908
        1, 1, 1, 1, 1, 1, 1, 1, // Number of blocks
909
        1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 4, 4, 6, 6, 8, 8,
910
        1, 1, 1, 1, 1, 1);
911
    static private $logTab = array(
912
        -255, 255, 1, 240, 2, 225, 241, 53, 3,  // Table of log for the Galois field
913
        38, 226, 133, 242, 43, 54, 210, 4, 195, 39, 114, 227, 106, 134, 28,
914
        243, 140, 44, 23, 55, 118, 211, 234, 5, 219, 196, 96, 40, 222, 115,
915
        103, 228, 78, 107, 125, 135, 8, 29, 162, 244, 186, 141, 180, 45, 99,
916
        24, 49, 56, 13, 119, 153, 212, 199, 235, 91, 6, 76, 220, 217, 197,
917
        11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, 229, 86, 79, 171,
918
        108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, 245, 173, 187,
919
        204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, 57, 147,
920
        14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, 7,
921
        161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179,
922
        42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194,
923
        113, 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127,
924
        247, 146, 66, 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73,
925
        164, 144, 85, 170, 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82,
926
        72, 182, 215, 191, 251, 47, 178, 89, 151, 101, 94, 160, 123, 26, 112,
927
        232, 21, 51, 238, 208, 131, 58, 69, 148, 18, 15, 16, 68, 17, 121, 149,
928
        129, 19, 155, 59, 249, 70, 214, 250, 168, 71, 201, 156, 64, 60, 237,
929
        130, 111, 20, 93, 122, 177, 150);
930
    static private $aLogTab = array(
931
        1, 2, 4, 8, 16, 32, 64, 128, 45, 90, // Table of aLog for the Galois field
932
        180, 69, 138, 57, 114, 228, 229, 231, 227, 235, 251, 219, 155, 27, 54,
933
        108, 216, 157, 23, 46, 92, 184, 93, 186, 89, 178, 73, 146, 9, 18, 36,
934
        72, 144, 13, 26, 52, 104, 208, 141, 55, 110, 220, 149, 7, 14, 28, 56,
935
        112, 224, 237, 247, 195, 171, 123, 246, 193, 175, 115, 230, 225, 239,
936
        243, 203, 187, 91, 182, 65, 130, 41, 82, 164, 101, 202, 185, 95, 190,
937
        81, 162, 105, 210, 137, 63, 126, 252, 213, 135, 35, 70, 140, 53, 106,
938
        212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, 217, 159, 19, 38, 76,
939
        152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, 117, 234, 249, 223,
940
        147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, 189, 87, 174, 113,
941
        226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, 214, 129,
942
        47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, 127,
943
        254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206,
944
        177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161,
945
        111, 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132,
946
        37, 74, 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248,
947
        221, 151, 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75,
948
        150, 1);
949
    static private function champGaloisMult($a, $b){  // MULTIPLICATION IN GALOIS FIELD GF(2^8)
950
        if(!$a || !$b) return 0;
951
        return self::$aLogTab[(self::$logTab[$a] + self::$logTab[$b]) % 255];
952
    }
953
    static private function champGaloisDoub($a, $b){  // THE OPERATION a * 2^b IN GALOIS FIELD GF(2^8)
954
        if (!$a) return 0;
955
        if (!$b) return $a;
956
        return self::$aLogTab[(self::$logTab[$a] + $b) % 255];
957
    }
958
    static private function champGaloisSum($a, $b){ // SUM IN GALOIS FIELD GF(2^8)
959
        return $a ^ $b;
960
    }
961
    static private function selectIndex($dataCodeWordsCount, $rectangular){ // CHOOSE THE GOOD INDEX FOR TABLES
962
        if (($dataCodeWordsCount<1 || $dataCodeWordsCount>1558) && !$rectangular) return -1;
963
        if (($dataCodeWordsCount<1 || $dataCodeWordsCount>49) && $rectangular)  return -1;
964
 
965
        $n = $rectangular ? 24 : 0;
966
 
967
        while (self::$dataCWCount[$n] < $dataCodeWordsCount) $n++;
968
        return $n;
969
    }
970
    static private function encodeDataCodeWordsASCII($text) {
971
        $dataCodeWords = array();
972
        $n = 0;
973
        $len = strlen($text);
974
        for ($i=0; $i<$len; $i++){
975
            $c = ord($text[$i]);
976
            if ($c > 127) {
977
                $dataCodeWords[$n] = 235;
978
                $c -= 127;
979
                $n++;
980
            } else if (($c>=48 && $c<=57) && ($i+1<$len) && (preg_match('`[0-9]`', $text[$i+1]))) {
981
                $c = (($c - 48) * 10) + intval($text[$i+1]);
982
                $c += 130;
983
                $i++;
984
            } else $c++;
985
            $dataCodeWords[$n] = $c;
986
            $n++;
987
        }
988
        return $dataCodeWords;
989
    }
990
    static private function addPadCW(&$tab, $from, $to){
991
        if ($from >= $to) return ;
992
        $tab[$from] = 129;
993
        for ($i=$from+1; $i<$to; $i++){
994
            $r = ((149 * ($i+1)) % 253) + 1;
995
            $tab[$i] = (129 + $r) % 254;
996
        }
997
    }
998
    static private function calculSolFactorTable($solomonCWCount){ // CALCULATE THE REED SOLOMON FACTORS
999
        $g = array_fill(0, $solomonCWCount+1, 1);
1000
        for($i = 1; $i <= $solomonCWCount; $i++) {
1001
            for($j = $i - 1; $j >= 0; $j--) {
1002
                $g[$j] = self::champGaloisDoub($g[$j], $i);
1003
                if($j > 0) $g[$j] = self::champGaloisSum($g[$j], $g[$j-1]);
1004
            }
1005
        }
1006
        return $g;
1007
    }
1008
    static private function addReedSolomonCW($nSolomonCW, $coeffTab, $nDataCW, &$dataTab, $blocks){ // Add the Reed Solomon codewords
1009
        $errorBlocks = $nSolomonCW / $blocks;
1010
        $correctionCW = array();
1011
 
1012
        for($k = 0; $k < $blocks; $k++) {
1013
            for ($i=0; $i < $errorBlocks; $i++) $correctionCW[$i] = 0;
1014
 
1015
            for ($i=$k; $i<$nDataCW; $i+=$blocks){
1016
                $temp = self::champGaloisSum($dataTab[$i], $correctionCW[$errorBlocks-1]);
1017
                for ($j=$errorBlocks-1; $j>=0; $j--){
1018
                    if ( !$temp ) {
1019
                        $correctionCW[$j] = 0;
1020
                    } else {
1021
                        $correctionCW[$j] = self::champGaloisMult($temp, $coeffTab[$j]);
1022
                    }
1023
                    if ($j>0) $correctionCW[$j] = self::champGaloisSum($correctionCW[$j-1], $correctionCW[$j]);
1024
                }
1025
            }
1026
            // Renversement des blocs calcules
1027
            $j = $nDataCW + $k;
1028
            for ($i=$errorBlocks-1; $i>=0; $i--){
1029
                $dataTab[$j] = $correctionCW[$i];
1030
                $j=$j+$blocks;
1031
            }
1032
        }
1033
        return $dataTab;
1034
    }
1035
    static private function getBits($entier){ // Transform integer to tab of bits
1036
        $bits = array();
1037
        for ($i=0; $i<8; $i++){
1038
            $bits[$i] = $entier & (128 >> $i) ? 1 : 0;
1039
        }
1040
        return $bits;
1041
    }
1042
    static private function next($etape, $totalRows, $totalCols, $codeWordsBits, &$datamatrix, &$assigned){ // Place codewords into the matrix
1043
        $chr = 0; // Place of the 8st bit from the first character to [4][0]
1044
        $row = 4;
1045
        $col = 0;
1046
 
1047
        do {
1048
            // Check for a special case of corner
1049
            if(($row == $totalRows) && ($col == 0)){
1050
                self::patternShapeSpecial1($datamatrix, $assigned, $codeWordsBits[$chr], $totalRows, $totalCols);
1051
                $chr++;
1052
            } else if(($etape<3) && ($row == $totalRows-2) && ($col == 0) && ($totalCols%4 != 0)){
1053
                self::patternShapeSpecial2($datamatrix, $assigned, $codeWordsBits[$chr], $totalRows, $totalCols);
1054
                $chr++;
1055
            } else if(($row == $totalRows-2) && ($col == 0) && ($totalCols%8 == 4)){
1056
                self::patternShapeSpecial3($datamatrix, $assigned, $codeWordsBits[$chr], $totalRows, $totalCols);
1057
                $chr++;
1058
            }
1059
            else if(($row == $totalRows+4) && ($col == 2) && ($totalCols%8 == 0)){
1060
                self::patternShapeSpecial4($datamatrix, $assigned, $codeWordsBits[$chr], $totalRows, $totalCols);
1061
                $chr++;
1062
            }
1063
 
1064
            // Go up and right in the datamatrix
1065
            do {
1066
                if(($row < $totalRows) && ($col >= 0) && (!isset($assigned[$row][$col]) || $assigned[$row][$col]!=1)) {
1067
                    self::patternShapeStandard($datamatrix, $assigned, $codeWordsBits[$chr], $row, $col, $totalRows, $totalCols);
1068
                    $chr++;
1069
                }
1070
                $row -= 2;
1071
                $col += 2;
1072
            } while (($row >= 0) && ($col < $totalCols));
1073
            $row += 1;
1074
            $col += 3;
1075
 
1076
            // Go down and left in the datamatrix
1077
            do {
1078
                if(($row >= 0) && ($col < $totalCols) && (!isset($assigned[$row][$col]) || $assigned[$row][$col]!=1)){
1079
                    self::patternShapeStandard($datamatrix, $assigned, $codeWordsBits[$chr], $row, $col, $totalRows, $totalCols);
1080
                    $chr++;
1081
                }
1082
                $row += 2;
1083
                $col -= 2;
1084
            } while (($row < $totalRows) && ($col >=0));
1085
            $row += 3;
1086
            $col += 1;
1087
        } while (($row < $totalRows) || ($col < $totalCols));
1088
    }
1089
    static private function patternShapeStandard(&$datamatrix, &$assigned, $bits, $row, $col, $totalRows, $totalCols){ // Place bits in the matrix (standard or special case)
1090
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[0], $row-2, $col-2, $totalRows, $totalCols);
1091
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[1], $row-2, $col-1, $totalRows, $totalCols);
1092
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[2], $row-1, $col-2, $totalRows, $totalCols);
1093
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[3], $row-1, $col-1, $totalRows, $totalCols);
1094
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[4], $row-1, $col, $totalRows, $totalCols);
1095
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[5], $row, $col-2, $totalRows, $totalCols);
1096
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[6], $row, $col-1, $totalRows, $totalCols);
1097
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[7], $row, $col, $totalRows, $totalCols);
1098
    }
1099
    static private function patternShapeSpecial1(&$datamatrix, &$assigned, $bits, $totalRows, $totalCols ){
1100
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[0], $totalRows-1,  0, $totalRows, $totalCols);
1101
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[1], $totalRows-1,  1, $totalRows, $totalCols);
1102
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[2], $totalRows-1,  2, $totalRows, $totalCols);
1103
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[3], 0, $totalCols-2, $totalRows, $totalCols);
1104
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[4], 0, $totalCols-1, $totalRows, $totalCols);
1105
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[5], 1, $totalCols-1, $totalRows, $totalCols);
1106
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[6], 2, $totalCols-1, $totalRows, $totalCols);
1107
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[7], 3, $totalCols-1, $totalRows, $totalCols);
1108
    }
1109
    static private function patternShapeSpecial2(&$datamatrix, &$assigned, $bits, $totalRows, $totalCols ){
1110
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[0], $totalRows-3,  0, $totalRows, $totalCols);
1111
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[1], $totalRows-2,  0, $totalRows, $totalCols);
1112
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[2], $totalRows-1,  0, $totalRows, $totalCols);
1113
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[3], 0, $totalCols-4, $totalRows, $totalCols);
1114
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[4], 0, $totalCols-3, $totalRows, $totalCols);
1115
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[5], 0, $totalCols-2, $totalRows, $totalCols);
1116
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[6], 0, $totalCols-1, $totalRows, $totalCols);
1117
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[7], 1, $totalCols-1, $totalRows, $totalCols);
1118
    }
1119
    static private function patternShapeSpecial3(&$datamatrix, &$assigned, $bits, $totalRows, $totalCols ){
1120
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[0], $totalRows-3,  0, $totalRows, $totalCols);
1121
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[1], $totalRows-2,  0, $totalRows, $totalCols);
1122
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[2], $totalRows-1,  0, $totalRows, $totalCols);
1123
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[3], 0, $totalCols-2, $totalRows, $totalCols);
1124
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[4], 0, $totalCols-1, $totalRows, $totalCols);
1125
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[5], 1, $totalCols-1, $totalRows, $totalCols);
1126
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[6], 2, $totalCols-1, $totalRows, $totalCols);
1127
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[7], 3, $totalCols-1, $totalRows, $totalCols);
1128
    }
1129
    static private function patternShapeSpecial4(&$datamatrix, &$assigned, $bits, $totalRows, $totalCols ){
1130
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[0], $totalRows-1,  0, $totalRows, $totalCols);
1131
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[1], $totalRows-1, $totalCols-1, $totalRows, $totalCols);
1132
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[2], 0, $totalCols-3, $totalRows, $totalCols);
1133
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[3], 0, $totalCols-2, $totalRows, $totalCols);
1134
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[4], 0, $totalCols-1, $totalRows, $totalCols);
1135
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[5], 1, $totalCols-3, $totalRows, $totalCols);
1136
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[6], 1, $totalCols-2, $totalRows, $totalCols);
1137
        self::placeBitInDatamatrix($datamatrix, $assigned, $bits[7], 1, $totalCols-1, $totalRows, $totalCols);
1138
    }
1139
    static private function placeBitInDatamatrix(&$datamatrix, &$assigned, $bit, $row, $col, $totalRows, $totalCols){ // Put a bit into the matrix
1140
        if ($row < 0) {
1141
            $row += $totalRows;
1142
            $col += 4 - (($totalRows+4)%8);
1143
        }
1144
        if ($col < 0) {
1145
            $col += $totalCols;
1146
            $row += 4 - (($totalCols+4)%8);
1147
        }
1148
        if (!isset($assigned[$row][$col]) || $assigned[$row][$col] != 1) {
1149
            $datamatrix[$row][$col] = $bit;
1150
            $assigned[$row][$col] = 1;
1151
        }
1152
    }
1153
    static private function addFinderPattern($datamatrix, $rowsRegion, $colsRegion, $rowsRegionCW, $colsRegionCW){ // Add the finder pattern
1154
        $totalRowsCW = ($rowsRegionCW+2) * $rowsRegion;
1155
        $totalColsCW = ($colsRegionCW+2) * $colsRegion;
1156
 
1157
        $datamatrixTemp = array();
1158
        $datamatrixTemp[0] = array_fill(0, $totalColsCW+2, 0);
1159
 
1160
        for ($i=0; $i<$totalRowsCW; $i++){
1161
            $datamatrixTemp[$i+1] = array();
1162
            $datamatrixTemp[$i+1][0] = 0;
1163
            $datamatrixTemp[$i+1][$totalColsCW+1] = 0;
1164
            for ($j=0; $j<$totalColsCW; $j++){
1165
                if ($i%($rowsRegionCW+2) == 0){
1166
                    if ($j%2 == 0){
1167
                        $datamatrixTemp[$i+1][$j+1] = 1;
1168
                    } else {
1169
                        $datamatrixTemp[$i+1][$j+1] = 0;
1170
                    }
1171
                } else if ($i%($rowsRegionCW+2) == $rowsRegionCW+1){
1172
                    $datamatrixTemp[$i+1][$j+1] = 1;
1173
                } else if ($j%($colsRegionCW+2) == $colsRegionCW+1){
1174
                    if ($i%2 == 0){
1175
                        $datamatrixTemp[$i+1][$j+1] = 0;
1176
                    } else {
1177
                        $datamatrixTemp[$i+1][$j+1] = 1;
1178
                    }
1179
                } else if ($j%($colsRegionCW+2) == 0){
1180
                    $datamatrixTemp[$i+1][$j+1] = 1;
1181
                } else{
1182
                    $datamatrixTemp[$i+1][$j+1] = 0;
1183
                    $datamatrixTemp[$i+1][$j+1] = $datamatrix[$i-1-(2*(floor($i/($rowsRegionCW+2))))][$j-1-(2*(floor($j/($colsRegionCW+2))))]; // todo : parseInt => ?
1184
                }
1185
            }
1186
        }
1187
        $datamatrixTemp[$totalRowsCW+1] = array();
1188
        for ($j=0; $j<$totalColsCW+2; $j++){
1189
            $datamatrixTemp[$totalRowsCW+1][$j] = 0;
1190
        }
1191
        return $datamatrixTemp;
1192
    }
1193
    static public function getDigit($text, $rectangular){
1194
        $dataCodeWords = self::encodeDataCodeWordsASCII($text); // Code the text in the ASCII mode
1195
        $dataCWCount = count($dataCodeWords);
1196
        $index = self::selectIndex($dataCWCount, $rectangular); // Select the index for the data tables
1197
        $totalDataCWCount = self::$dataCWCount[$index]; // Number of data CW
1198
        $solomonCWCount = self::$solomonCWCount[$index]; // Number of Reed Solomon CW
1199
        $totalCWCount = $totalDataCWCount + $solomonCWCount; // Number of CW
1200
        $rowsTotal = self::$lengthRows[$index]; // Size of symbol
1201
        $colsTotal = self::$lengthCols[$index];
1202
        $rowsRegion = self::$regionRows[$index]; // Number of region
1203
        $colsRegion = self::$regionCols[$index];
1204
        $rowsRegionCW = self::$dataRegionRows[$index];
1205
        $colsRegionCW = self::$dataRegionCols[$index];
1206
        $rowsLengthMatrice = $rowsTotal-2*$rowsRegion; // Size of matrice data
1207
        $colsLengthMatrice = $colsTotal-2*$colsRegion;
1208
        $blocks = self::$interleavedBlocks[$index];  // Number of Reed Solomon blocks
1209
        $errorBlocks = $solomonCWCount / $blocks;
1210
 
1211
        self::addPadCW($dataCodeWords, $dataCWCount, $totalDataCWCount); // Add codewords pads
1212
 
1213
        $g = self::calculSolFactorTable($errorBlocks); // Calculate correction coefficients
1214
 
1215
        self::addReedSolomonCW($solomonCWCount, $g, $totalDataCWCount, $dataCodeWords, $blocks); // Add Reed Solomon codewords
1216
 
1217
        $codeWordsBits = array(); // Calculte bits from codewords
1218
        for ($i=0; $i<$totalCWCount; $i++){
1219
            $codeWordsBits[$i] = self::getBits($dataCodeWords[$i]);
1220
        }
1221
 
1222
        $datamatrix = array_fill(0, $colsLengthMatrice, array());
1223
        $assigned = array_fill(0, $colsLengthMatrice, array());
1224
 
1225
        // Add the bottom-right corner if needed
1226
        if ( (($rowsLengthMatrice * $colsLengthMatrice) % 8) == 4) {
1227
            $datamatrix[$rowsLengthMatrice-2][$colsLengthMatrice-2] = 1;
1228
            $datamatrix[$rowsLengthMatrice-1][$colsLengthMatrice-1] = 1;
1229
            $datamatrix[$rowsLengthMatrice-1][$colsLengthMatrice-2] = 0;
1230
            $datamatrix[$rowsLengthMatrice-2][$colsLengthMatrice-1] = 0;
1231
            $assigned[$rowsLengthMatrice-2][$colsLengthMatrice-2] = 1;
1232
            $assigned[$rowsLengthMatrice-1][$colsLengthMatrice-1] = 1;
1233
            $assigned[$rowsLengthMatrice-1][$colsLengthMatrice-2] = 1;
1234
            $assigned[$rowsLengthMatrice-2][$colsLengthMatrice-1] = 1;
1235
        }
1236
 
1237
        // Put the codewords into the matrix
1238
        self::next(0,$rowsLengthMatrice,$colsLengthMatrice, $codeWordsBits, $datamatrix, $assigned);
1239
 
1240
        // Add the finder pattern
1241
        $datamatrix = self::addFinderPattern($datamatrix, $rowsRegion, $colsRegion, $rowsRegionCW, $colsRegionCW);
1242
 
1243
        return $datamatrix;
1244
    }
1245
 
1246
    static public function getLenghtColumn($text)
1247
    {
1248
        $dataCodeWords = self::encodeDataCodeWordsASCII($text);
1249
        $dataCWCount = count($dataCodeWords);
1250
        $index = self::selectIndex($dataCWCount, false);
1251
 
1252
        return self::$lengthCols[$index];
1253
    }
1254
}
1255
?>