BCGDrawPNG::SHR()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
namespace tinymeng\code\Gateways\barcode\drawer;
3
4
/**
5
 *--------------------------------------------------------------------
6
 *
7
 * Image Class to draw PNG images with possibility to set DPI
8
 *
9
 *--------------------------------------------------------------------
10
 * Copyright (C) Jean-Sebastien Goupil
11
 * http://www.barcodephp.com
12
 */
13
if (!function_exists('file_put_contents')) {
14
    function file_put_contents($filename, $data) {
15
        $f = @fopen($filename, 'w');
16
        if (!$f) {
0 ignored issues
show
introduced by
$f is of type false|resource, thus it always evaluated to false.
Loading history...
17
            return false;
18
        } else {
19
            $bytes = fwrite($f, $data);
20
            fclose($f);
21
            return $bytes;
22
        }
23
    }
24
}
25
26
class BCGDrawPNG extends BCGDraw {
27
    private $dpi;
28
    
29
    /**
30
     * Constructor.
31
     *
32
     * @param resource $im
33
     */
34
    public function __construct($im) {
35
        parent::__construct($im);
36
    }
37
38
    /**
39
     * Sets the DPI.
40
     *
41
     * @param int $dpi
42
     */
43
    public function setDPI($dpi) {
44
        if (is_numeric($dpi)) {
0 ignored issues
show
introduced by
The condition is_numeric($dpi) is always true.
Loading history...
45
            $this->dpi = max(1, $dpi);
46
        } else {
47
            $this->dpi = null;
48
        }
49
    }
50
51
    /**
52
     * Draws the PNG on the screen or in a file.
53
     */
54
    public function draw() {
55
        ob_start();
56
        imagepng($this->im);
57
        $bin = ob_get_contents();
58
        ob_end_clean();
59
60
        $this->setInternalProperties($bin);
61
62
        if (empty($this->filename)) {
63
            echo $bin;
64
        } else {
65
            file_put_contents($this->filename, $bin);
66
        }
67
    }
68
69
    private function setInternalProperties(&$bin) {
70
        // Scan all the ChunkType
71
        if (strcmp(substr($bin, 0, 8), pack('H*', '89504E470D0A1A0A')) === 0) {
72
            $chunks = $this->detectChunks($bin);
73
74
            $this->internalSetDPI($bin, $chunks);
75
            $this->internalSetC($bin, $chunks);
76
        }
77
    }
78
79
    private function detectChunks($bin) {
80
        $data = substr($bin, 8);
81
        $chunks = array();
82
        $c = strlen($data);
83
        
84
        $offset = 0;
85
        while ($offset < $c) {
86
            $packed = unpack('Nsize/a4chunk', $data);
87
            $size = $packed['size'];
88
            $chunk = $packed['chunk'];
89
90
            $chunks[] = array('offset' => $offset + 8, 'size' => $size, 'chunk' => $chunk);
91
            $jump = $size + 12;
92
            $offset += $jump;
93
            $data = substr($data, $jump);
94
        }
95
        
96
        return $chunks;
97
    }
98
99
    private function internalSetDPI(&$bin, &$chunks) {
100
        if ($this->dpi !== null) {
101
            $meters = (int)($this->dpi * 39.37007874);
102
103
            $found = -1;
104
            $c = count($chunks);
105
            for($i = 0; $i < $c; $i++) {
106
                // We already have a pHYs
107
                if($chunks[$i]['chunk'] === 'pHYs') {
108
                    $found = $i;
109
                    break;
110
                }
111
            }
112
113
            $data = 'pHYs' . pack('NNC', $meters, $meters, 0x01);
114
            $crc = self::crc($data, 13);
115
            $cr = pack('Na13N', 9, $data, $crc);
116
117
            // We didn't have a pHYs
118
            if($found == -1) {
119
                // Don't do anything if we have a bad PNG
120
                if($c >= 2 && $chunks[0]['chunk'] === 'IHDR') {
121
                    array_splice($chunks, 1, 0, array(array('offset' => 33, 'size' => 9, 'chunk' => 'pHYs')));
122
123
                    // Push the data
124
                    for($i = 2; $i < $c; $i++) {
125
                        $chunks[$i]['offset'] += 21;
126
                    }
127
128
                    $firstPart = substr($bin, 0, 33);
129
                    $secondPart = substr($bin, 33);
130
                    $bin = $firstPart;
131
                    $bin .= $cr;
132
                    $bin .= $secondPart;
133
                }
134
            } else {
135
                $bin = substr_replace($bin, $cr, $chunks[$i]['offset'], 21);
136
            }
137
        }
138
    }
139
140
    private function internalSetC(&$bin, &$chunks) {
141
        if (count($chunks) >= 2 && $chunks[0]['chunk'] === 'IHDR') {
142
            $firstPart = substr($bin, 0, 33);
143
            $secondPart = substr($bin, 33);
144
            $cr = pack('H*', '0000004C74455874436F707972696768740047656E657261746564207769746820426172636F64652047656E657261746F7220666F722050485020687474703A2F2F7777772E626172636F64657068702E636F6D597F70B8');
145
            $bin = $firstPart;
146
            $bin .= $cr;
147
            $bin .= $secondPart;
148
        }
149
        
150
        // Chunks is dirty!! But we are done.
151
    }
152
153
    private static $crc_table = array();
154
    private static $crc_table_computed = false;
155
156
    private static function make_crc_table() {
157
        for ($n = 0; $n < 256; $n++) {
158
            $c = $n;
159
            for ($k = 0; $k < 8; $k++) {
160
                if (($c & 1) == 1) {
161
                    $c = 0xedb88320 ^ (self::SHR($c, 1));
162
                } else {
163
                    $c = self::SHR($c, 1);
164
                }
165
            }
166
            self::$crc_table[$n] = $c;
167
        }
168
169
        self::$crc_table_computed = true;
170
    }
171
172
    private static function SHR($x, $n) {
173
        $mask = 0x40000000;
174
175
        if ($x < 0) {
176
            $x &= 0x7FFFFFFF;
177
            $mask = $mask >> ($n - 1);
178
            return ($x >> $n) | $mask;
179
        }
180
181
        return (int)$x >> (int)$n;
182
    }
183
184
    private static function update_crc($crc, $buf, $len) {
185
        $c = $crc;
186
187
        if (!self::$crc_table_computed) {
188
            self::make_crc_table();
189
        }
190
191
        for ($n = 0; $n < $len; $n++) {
192
            $c = self::$crc_table[($c ^ ord($buf[$n])) & 0xff] ^ (self::SHR($c, 8));
193
        }
194
195
        return $c;
196
    }
197
198
    private static function crc($data, $len) {
199
        return self::update_crc(-1, $data, $len) ^ -1;
200
    }
201
}
202
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
203