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

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:  * Import.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;
 17: 
 18: use \Com\Tecnick\File\File;
 19: use \Com\Tecnick\File\Byte;
 20: use \Com\Tecnick\Pdf\Image\Import\Jpeg;
 21: use \Com\Tecnick\Pdf\Image\Import\Png;
 22: use \Com\Tecnick\Pdf\Image\Exception as ImageException;
 23: 
 24: /**
 25:  * Com\Tecnick\Pdf\Image\Import
 26:  *
 27:  * @since       2011-05-23
 28:  * @category    Library
 29:  * @package     PdfImage
 30:  * @author      Nicola Asuni <info@tecnick.com>
 31:  * @copyright   2011-2016 Nicola Asuni - Tecnick.com LTD
 32:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 33:  * @link        https://github.com/tecnickcom/tc-lib-pdf-image
 34:  */
 35: class Import extends \Com\Tecnick\Pdf\Image\Output
 36: {
 37:     /**
 38:      * Image index.
 39:      * Count the number of added images.
 40:      *
 41:      * @var int
 42:      */
 43:     protected $iid = 0;
 44:     
 45:     /**
 46:      * Stack of added images.
 47:      *
 48:      * @var array
 49:      */
 50:     protected $image = array();
 51: 
 52:     /**
 53:      * Cache used to store imported image data.
 54:      * The same image data can be reused multiple times.
 55:      *
 56:      * @var array
 57:      */
 58:     protected $cache = array();
 59: 
 60:     /**
 61:      * Native image types and associated importing class
 62:      * (image types for which we have an import method)
 63:      *
 64:      * @var array
 65:      */
 66:     private static $native = array(
 67:         IMAGETYPE_PNG  => 'Png',
 68:         IMAGETYPE_JPEG => 'Jpeg',
 69:     );
 70: 
 71:     /**
 72:      * Lossless image types
 73:      *
 74:      * @var array
 75:      */
 76:     protected static $lossless = array(
 77:         IMAGETYPE_GIF,
 78:         IMAGETYPE_PNG,
 79:         IMAGETYPE_PSD,
 80:         IMAGETYPE_BMP,
 81:         IMAGETYPE_WBMP,
 82:         IMAGETYPE_XBM,
 83:         IMAGETYPE_TIFF_II,
 84:         IMAGETYPE_TIFF_MM,
 85:         IMAGETYPE_IFF,
 86:         IMAGETYPE_SWC,
 87:         IMAGETYPE_ICO,
 88:     );
 89: 
 90:     /**
 91:      * Map number of channels with color space name
 92:      *
 93:      * @var array
 94:      */
 95:     protected static $colspacemap = array(
 96:         1 => 'DeviceGray',
 97:         3 => 'DeviceRGB',
 98:         4 => 'DeviceCMYK',
 99:     );
100: 
101:     /**
102:      * Add a new image
103:      *
104:      * @param string $image    Image file name, URL or a '@' character followed by the image data string.
105:      *                         To link an image without embedding it on the document, set an asterisk character
106:      *                         before the URL (i.e.: '*http://www.example.com/image.jpg').
107:      * @param int    $width    New width in pixels or null to keep the original value
108:      * @param int    $height   New height in pixels or null to keep the original value
109:      * @param bool   $ismask   True if the image is a transparency mask
110:      * @param int    $quality  Quality for JPEG files (0 = max compression; 100 = best quality, bigger file).
111:      * @param bool   $defprint Indicate if the image is the default for printing when used as alternative image.
112:      * @param bool   $hidden   True to not display this image (used for alternate images).
113:      * @param array  $altimgs  Arrays of alternate image keys.
114:      *
115:      * @return int Image ID
116:      */
117:     public function add(
118:         $image,
119:         $width = null,
120:         $height = null,
121:         $ismask = false,
122:         $quality = 100,
123:         $defprint = false,
124:         $altimgs = array()
125:     ) {
126:         $data = $this->import($image, $width, $height, $ismask, $quality, $defprint);
127:         ++$this->iid;
128:         $this->image[$this->iid] = array(
129:             'iid'      => $this->iid,
130:             'key'      => $data['key'],
131:             'width'    => $data['width'],
132:             'height'   => $data['height'],
133:             'defprint' => $defprint,
134:             'altimgs'  => $altimgs,
135:         );
136:         return $this->iid;
137:     }
138: 
139:     /**
140:      * Get the Image key used for caching
141:      *
142:      * @param string $image   Image file name or content
143:      * @param int    $width   Width in pixels
144:      * @param int    $height  Height in pixels
145:      * @param int    $quality Quality for JPEG files
146:      *
147:      * @return string
148:      */
149:     public function getKey($image, $width = 0, $height = 0, $quality = 100)
150:     {
151:         return strtr(
152:             rtrim(
153:                 base64_encode(
154:                     pack('H*', md5($image.$width.$height.$quality))
155:                 ),
156:                 '='
157:             ),
158:             '+/',
159:             '-_'
160:         );
161:     }
162: 
163:     /**
164:      * Get an imported image by key
165:      *
166:      * @param string $key Image key
167:      *
168:      * @return array Image raw data array
169:      */
170:     public function getImageDataByKey($key)
171:     {
172:         if (empty($this->cache[$key])) {
173:             throw new ImageException('Unknown key');
174:         }
175:         return $this->cache[$key];
176:     }
177: 
178:     /**
179:      * Import the original image raw data
180:      *
181:      * @param string $image    Image file name, URL or a '@' character followed by the image data string.
182:      *                         To link an image without embedding it on the document, set an asterisk character
183:      *                         before the URL (i.e.: '*http://www.example.com/image.jpg').
184:      * @param int    $width    New width in pixels or null to keep the original value
185:      * @param int    $height   New height in pixels or null to keep the original value
186:      * @param bool   $ismask   True if the image is a transparency mask
187:      * @param int    $quality  Quality for JPEG files (0 = max compression; 100 = best quality, bigger file).
188:      *
189:      * @return array Image raw data array
190:      */
191:     protected function import($image, $width = null, $height = null, $ismask = false, $quality = 100)
192:     {
193:         $quality = max(0, min(100, $quality));
194:         $imgkey = $this->getKey($image, intval($width), intval($height), $quality);
195: 
196:         if (isset($this->cache[$imgkey])) {
197:             return $this->cache[$imgkey];
198:         }
199: 
200:         $data = $this->getRawData($image);
201:         $data['key'] = $imgkey;
202: 
203:         if ($width === null) {
204:             $width = $data['width'];
205:         }
206:         $width = max(0, intval($width));
207:         if ($height === null) {
208:             $height = $data['height'];
209:         }
210:         $height = max(0, intval($height));
211: 
212:         if ((!$data['native']) || ($width != $data['width']) || ($height != $data['height'])) {
213:             $data = $this->getResizedRawData($data, $width, $height, true, $quality);
214:         }
215: 
216:         $data = $this->getData($data, $width, $height, $quality);
217: 
218:         if ($ismask) {
219:             $data['mask'] = $data;
220:         } elseif (!empty($data['splitalpha'])) {
221:             // create 2 separate images: plain + mask
222:             $data['plain'] = $this->getResizedRawData($data, $width, $height, false, $quality);
223:             $data['plain'] = $this->getData($data['plain'], $width, $height, $quality);
224:             $data['mask'] = $this->getAlphaChannelRawData($data);
225:             $data['mask'] = $this->getData($data['mask'], $width, $height, $quality);
226:         }
227: 
228:         // store data in cache
229:         $this->cache[$imgkey] = $data;
230: 
231:         return $data;
232:     }
233: 
234:     /**
235:      * Extract the relevant data from the image
236:      *
237:      * @param string $data Image raw data
238:      * @param int    $width   Width in pixels
239:      * @param int    $height  Height in pixels
240:      * @param int    $quality Quality for JPEG files
241:      *
242:      * @return string
243:      */
244:     protected function getData($data, $width, $height, $quality)
245:     {
246:         if (!$data['native']) {
247:             throw new ImageException('Unable to import image');
248:         }
249:         $class = '\\Com\\Tecnick\\Pdf\\Image\\Import\\'.self::$native[$data['type']];
250:         $imp = new $class();
251:         $data = $imp->getData($data);
252: 
253:         if (!empty($data['recode'])) {
254:             // re-encode the image as it was not possible to decode it
255:             $data = $this->getResizedRawData($data, $width, $height, true, $quality);
256:             $data = $imp->getData($data);
257:         }
258:         return $data;
259:     }
260: 
261:     /**
262:      * Get the original image raw data
263:      *
264:      * @param string $image Image file name, URL or a '@' character followed by the image data string.
265:      *                      To link an image without embedding it on the document, set an asterisk character
266:      *                      before the URL (i.e.: '*http://www.example.com/image.jpg').
267:      *
268:      * @return array Image data array
269:      */
270:     protected function getRawData($image)
271:     {
272:         // default data to return
273:         $data = array(
274:             'key'      => '',            // image key
275:             'defprint' => false,         // default printing image when used as alternate
276:             'raw'      => '',            // raw image data
277:             'file'     => '',            // source file name or URL
278:             'exturl'   => false,         // true if the image is an exernal URL that should not be embedded
279:             'width'    => 0,             // image width in pixels
280:             'height'   => 0,             // image height in pixels
281:             'type'     => 0,             // image type constant: IMAGETYPE_XXX
282:             'native'   => false,         // true if the image is PNG or JPEG
283:             'mapto'    => IMAGETYPE_PNG, // type to convert to
284:             'bits'     => 8,             // number of bits per channel
285:             'channels' => 3,             // number of channels
286:             'colspace' => 'DeviceRGB',   // color space
287:             'icc'      => '',            // ICC profile
288:             'filter'   => 'FlateDecode', // decoding filter
289:             'parms'    => '',            // additional PDF decoding parameters
290:             'pal'      => '',            // colour palette
291:             'trns'     => array(),       // colour key masking
292:             'data'     => '',            // PDF image data
293:             'ismask'   => false,         // true if the image is a transparency mask
294:         );
295: 
296:         if (empty($image)) {
297:             throw new ImageException('Empty image');
298:         }
299: 
300:         if ($image[0] === '@') { // image from string
301:             $data['raw'] = substr($image, 1);
302:         } else {
303:             if ($image[0] === '*') { // not-embedded external URL
304:                 $data['exturl'] = true;
305:                 $image = substr($image, 1);
306:             }
307:             $data['file'] = $image;
308:             $fobj = new File();
309:             $data['raw'] = $fobj->getFileData($image);
310:         }
311: 
312:         return $this->getMetaData($data);
313:     }
314: 
315:     /**
316:      * Get the image meta data
317:      *
318:      * @param string $data Image raw data
319:      *
320:      * @return array Image raw data array
321:      */
322:     protected function getMetaData($data)
323:     {
324:         try {
325:             $meta = getimagesizefromstring($data['raw']);
326:         } catch (\Exception $exc) {
327:             throw new ImageException('Invalid image format: '.$exc);
328:         }
329:         $data['width'] = $meta[0];
330:         $data['height'] = $meta[1];
331:         $data['type'] = $meta[2];
332:         $data['native'] = isset(self::$native[$data['type']]);
333:         $data['mapto'] = (in_array($data['type'], self::$lossless) ? IMAGETYPE_PNG : IMAGETYPE_JPEG);
334:         if (isset($meta['bits'])) {
335:             $data['bits'] = intval($meta['bits']);
336:         }
337:         if (isset($meta['channels'])) {
338:             $data['channels'] = intval($meta['channels']);
339:         }
340:         if (isset(self::$colspacemap[$data['channels']])) {
341:             $data['colspace'] = self::$colspacemap[$data['channels']];
342:         }
343:         return $data;
344:     }
345: 
346:     /**
347:      * Get the resized image raw data
348:      * (always convert the image type to a native format: PNG or JPEG)
349:      *
350:      * @param string $data    Image raw data as returned by getImageRawData
351:      * @param int    $width   New width in pixels
352:      * @param int    $height  New height in pixels
353:      * @param bool   $alpha   If true save the alpha channel information, if false merge the alpha channel (PNG mode)
354:      * @param int    $quality Quality for JPEG files (0 = max compression; 100 = best quality, bigger file).
355:      *
356:      * @return array Image raw data array
357:      */
358:     protected function getResizedRawData($data, $width, $height, $alpha = true, $quality = 100)
359:     {
360:         $img = imagecreatefromstring($data['raw']);
361:         $newimg = imagecreatetruecolor($width, $height);
362:         imageinterlace($newimg, 0);
363:         imagealphablending($newimg, !$alpha);
364:         imagesavealpha($newimg, $alpha);
365:         imagecopyresampled($newimg, $img, 0, 0, 0, 0, $width, $height, $data['width'], $data['height']);
366:         ob_start();
367:         if ($data['mapto'] == IMAGETYPE_PNG) {
368:             if ((($tid = imagecolortransparent($img)) >= 0)
369:                 && (($palsize = imagecolorstotal($img)) > 0)
370:                 && ($tid < $palsize)
371:             ) {
372:                 // set transparency for Indexed image
373:                 $tcol = imagecolorsforindex($img, $tid);
374:                 $tid = imagecolorallocate($newimg, $tcol['red'], $tcol['green'], $tcol['blue']);
375:                 imagefill($newimg, 0, 0, $tid);
376:                 imagecolortransparent($newimg, $tid);
377:             }
378:             imagepng($newimg, null, 9, PNG_ALL_FILTERS);
379:         } else {
380:             imagejpeg($newimg, null, $quality);
381:         }
382:         $data['raw'] = ob_get_clean();
383:         $data['exturl'] = false;
384:         $data['recoded'] = true;
385:         return $this->getMetaData($data);
386:     }
387: 
388:     /**
389:      * Extract the alpha channel as separate image to be used as a mask
390:      *
391:      * @param string $data Image raw data as returned by getImageRawData
392:      *
393:      * @return array Image raw data array
394:      */
395:     protected function getAlphaChannelRawData($data)
396:     {
397:         $img = imagecreatefromstring($data['raw']);
398:         $newimg = imagecreate($data['width'], $data['height']);
399:         imageinterlace($newimg, 0);
400:         // generate gray scale palette (0 -> 255)
401:         for ($col = 0; $col < 256; ++$col) {
402:             ImageColorAllocate($newimg, $col, $col, $col);
403:         }
404:         // extract alpha channel
405:         for ($xpx = 0; $xpx < $data['width']; ++$xpx) {
406:             for ($ypx = 0; $ypx < $data['height']; ++$ypx) {
407:                 $colindex = imagecolorat($img, $xpx, $ypx);
408:                 // get and correct gamma color
409:                 $color = imagecolorsforindex($img, $colindex);
410:                 // GD alpha is only 7 bit (0 -> 127); 2.2 is the gamma value
411:                 $alpha = (pow(((127 - $color['alpha']) / 127), 2.2) * 255);
412:                 imagesetpixel($newimg, $xpx, $ypx, $alpha);
413:             }
414:         }
415:         ob_start();
416:         imagepng($newimg, null, 9, PNG_ALL_FILTERS);
417:         $data['raw'] = ob_get_clean();
418:         $data['colspace'] = 'DeviceGray';
419:         $data['exturl'] = false;
420:         $data['recoded'] = true;
421:         return $this->getMetaData($data);
422:     }
423: }
424: 
 

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