source-class-Com.Tecnick.Pdf.Image.Import.Png

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
  1: <?php
  2: /**
  3:  * Png.php
  4:  *
  5:  * @since       2011-05-23
  6:  * @category    Library
  7:  * @package     PdfImage
  8:  * @author      Nicola Asuni <info@tecnick.com>
  9:  * @copyright   2011-2015 Nicola Asuni - Tecnick.com LTD
 10:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 11:  * @link        https://github.com/tecnickcom/tc-lib-pdf-image
 12:  *
 13:  * This file is part of tc-lib-pdf-image software library.
 14:  */
 15: 
 16: namespace Com\Tecnick\Pdf\Image\Import;
 17: 
 18: use \Com\Tecnick\File\File;
 19: use \Com\Tecnick\File\Byte;
 20: use \Com\Tecnick\Pdf\Image\Exception as ImageException;
 21: 
 22: /**
 23:  * Com\Tecnick\Pdf\Image\Import\Png
 24:  *
 25:  * @since       2011-05-23
 26:  * @category    Library
 27:  * @package     PdfImage
 28:  * @author      Nicola Asuni <info@tecnick.com>
 29:  * @copyright   2011-2016 Nicola Asuni - Tecnick.com LTD
 30:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 31:  * @link        https://github.com/tecnickcom/tc-lib-pdf-image
 32:  */
 33: class Png
 34: {
 35:     /**
 36:      * Extract data from a PNG image
 37:      *
 38:      * @param string $data Image raw data
 39:      *
 40:      * @return array Image raw data array
 41:      */
 42:     public function getData($data)
 43:     {
 44:         $data['filter'] = 'FlateDecode';
 45:         $byte = new Byte($data['raw']);
 46: 
 47:         $offset = 0;
 48:         // check signature
 49:         if (substr($data['raw'], $offset, 8) != chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
 50:             // @codeCoverageIgnoreStart
 51:             throw new ImageException('Not a PNG image');
 52:             // @codeCoverageIgnoreEnd
 53:         }
 54:         $offset += 8;
 55:         $offset += 4;
 56: 
 57:         $data = $this->getIhdrChunk($data, $offset);
 58: 
 59:         // check compression, filter and interlacing settings
 60:         if (($byte->getByte($offset++) != 0)
 61:             || ($byte->getByte($offset++) != 0)
 62:             || ($byte->getByte($offset++) != 0)
 63:         ) {
 64:             if (!empty($data['recoded'])) {
 65:                 // this image has been already re-encoded
 66:                 // @codeCoverageIgnoreStart
 67:                 throw new ImageException('Unsupported feature');
 68:                 // @codeCoverageIgnoreEnd
 69:             }
 70:             // re-encode PNG
 71:             $data['recode'] = true;
 72:             return $data;
 73:         }
 74: 
 75:         if (strpos($data['colspace'], '+Alpha') !== false) {
 76:             // alpha channel: split images (plain + alpha)
 77:             $data['splitalpha'] = true;
 78:             return $data;
 79:         }
 80: 
 81:         $data['parms'] = '/DecodeParms <<'
 82:             .' /Predictor 15'
 83:             .' /Colors '.$data['channels']
 84:             .' /BitsPerComponent '.$data['bits']
 85:             .' /Columns '.$data['width']
 86:             .' >>';
 87: 
 88:         $offset += 4;
 89:         return $this->getChunks($data, $offset);
 90:     }
 91: 
 92:     /**
 93:      * Extract the IHDR chunk data
 94:      *
 95:      * The header chunk (IHDR) contains basic information about the image data and must appear as the first chunk,
 96:      * and there must only be one header chunk in a PNG data stream.
 97:      * @param string $data   Image raw data
 98:      * @param int    $offset Current byte offset
 99:      *
100:      * @return array Image raw data array
101:      */
102:     protected function getIhdrChunk($data, &$offset)
103:     {
104:         $byte = new Byte($data['raw']);
105:         if (substr($data['raw'], $offset, 4) != 'IHDR') {
106:             // @codeCoverageIgnoreStart
107:             throw new ImageException('Invalid PNG image');
108:             // @codeCoverageIgnoreEnd
109:         }
110:         $offset += 4;
111:         $data['width'] = $byte->getULong($offset);
112:         $offset += 4;
113:         $data['height'] = $byte->getULong($offset);
114:         $offset += 4;
115:         $data['bits'] = $byte->getByte($offset);
116:         $offset += 1;
117:         $chc = $byte->getByte($offset); // channels code
118:         $offset += 1;
119:         $data['channels'] = (($chc == 2) ? 3 : 1);
120:         $chcmap = array(
121:             0 => 'DeviceGray',
122:             2 => 'DeviceRGB',
123:             3 => 'Indexed',
124:             4 => 'DeviceGray+Alpha',
125:             6 => 'DeviceRGB+Alpha',
126:         );
127:         if (isset($chcmap[$chc])) {
128:             $data['colspace'] = $chcmap[$chc];
129:         } else {
130:             // @codeCoverageIgnoreStart
131:             throw new ImageException('Unknown color mode');
132:             // @codeCoverageIgnoreEnd
133:         }
134:         return $data;
135:     }
136: 
137:     /**
138:      * Extract chunks data from a PNG image
139:      *
140:      * @param string $data   Image raw data
141:      * @param int    $offset Current byte offset
142:      *
143:      * @return array Image raw data array
144:      */
145:     protected function getChunks($data, $offset)
146:     {
147:         $byte = new Byte($data['raw']);
148:         while (($len = $byte->getULong($offset)) >= 0) {
149:             $offset += 4;
150:             $type = substr($data['raw'], $offset, 4);
151:             $offset += 4;
152:             if ($type == 'PLTE') {
153:                 $data = $this->getPlteChunk($data, $offset, $len);
154:             } elseif ($type == 'tRNS') {
155:                 $data = $this->getTrnsChunk($data, $offset, $len);
156:             } elseif ($type == 'IDAT') {
157:                 $data = $this->getIdatChunk($data, $offset, $len);
158:             } elseif ($type == 'iCCP') {
159:                 $data = $this->getIccpChunk($byte, $data, $offset, $len);
160:             } elseif ($type == 'IEND') {
161:                 // The image trailer chunk (IEND) must be the final chunk
162:                 // and marks the end of the PNG file or data stream.
163:                 break;
164:             } else {
165:                 $offset += $len;
166:                 $offset += 4;
167:             }
168:         }
169:         if (($data['colspace'] == 'Indexed') && (empty($data['pal']))) {
170:             // @codeCoverageIgnoreStart
171:             throw new ImageException('The color palette is missing');
172:             // @codeCoverageIgnoreEnd
173:         }
174:         return $data;
175:     }
176: 
177:     /**
178:      * Extract the PLTE chunk data
179:      *
180:      * The palette chunk (PLTE) stores the colormap data associated with the image data.
181:      * This chunk is presentonly if the image data uses a color palette and must appear before the image data chunk.
182:      *
183:      * @param string $data   Image raw data
184:      * @param int    $offset Current byte offset
185:      * @param int    $len    NUmber of bytes in this chunk
186:      *
187:      * @return array Image raw data array
188:      */
189:     protected function getPlteChunk($data, &$offset, $len)
190:     {
191:         $data['pal'] = substr($data['raw'], $offset, $len);
192:         $offset += $len;
193:         $offset += 4;
194:         return $data;
195:     }
196: 
197:     /**
198:      * Extract the tRNS chunk data
199:      *
200:      * @param string $data   Image raw data
201:      * @param int    $offset Current byte offset
202:      * @param int    $len    NUmber of bytes in this chunk
203:      *
204:      * @return array Image raw data array
205:      */
206:     protected function getTrnsChunk($data, &$offset, $len)
207:     {
208:         // read transparency info
209:         $trns = substr($data['raw'], $offset, $len);
210:         $offset += $len;
211:         if ($data['colspace'] == 'DeviceGray') {
212:             // DeviceGray
213:             $data['trns'][] = ord($trns[1]);
214:         } elseif ($data['colspace'] == 'DeviceRGB') {
215:             // DeviceRGB
216:             $data['trns'][] = ord($trns[1]);
217:             $data['trns'][] = ord($trns[3]);
218:             $data['trns'][] = ord($trns[5]);
219:         } else {
220:             // Indexed
221:             $data['trns'] = array_map('ord', str_split($trns));
222:         }
223:         $offset += 4;
224:         return $data;
225:     }
226: 
227:     /**
228:      * Extract the IDAT chunk data
229:      *
230:      * The image data chunk (IDAT) stores the actual image data,
231:      * and multiple image data chunks may occur in a data stream and must be stored in contiguous order.
232:      *
233:      * @param string $data   Image raw data
234:      * @param int    $offset Current byte offset
235:      * @param int    $len    NUmber of bytes in this chunk
236:      *
237:      * @return array Image raw data array
238:      */
239:     protected function getIdatChunk($data, &$offset, $len)
240:     {
241:         $data['data'] .= substr($data['raw'], $offset, $len);
242:         $offset += $len;
243:         $offset += 4;
244:         return $data;
245:     }
246: 
247:     /**
248:      * Extract the iCCP chunk data
249:      *
250:      * @param Byte   $byte   Byte class object
251:      * @param string $data   Image raw data
252:      * @param int    $offset Current byte offset
253:      * @param int    $len    NUmber of bytes in this chunk
254:      *
255:      * @return array Image raw data array
256:      */
257:     protected function getIccpChunk($byte, $data, &$offset, $len)
258:     {
259:         // skip profile name
260:         $pos = 0;
261:         while (($byte->getByte($offset++) != 0) && ($pos < 80)) {
262:             ++$pos;
263:         }
264:         // get compression method
265:         if ($byte->getByte($offset++) != 0) {
266:             // @codeCoverageIgnoreStart
267:             throw new ImageException('Unknown filter method');
268:             // @codeCoverageIgnoreEnd
269:         }
270:         // read ICC Color Profile
271:         $len -= ($pos + 2);
272:         $data['icc'] = gzuncompress(substr($data['raw'], $offset, $len));
273:         $offset += $len;
274:         $offset += 4;
275:         return $data;
276:     }
277: }
278: 
 

© 2004-2017 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy