/**
  * Object constructor
  *
  * @param string $imageFileName
  * @throws Zend_Pdf_Exception
  */
 public function __construct($imageFileName)
 {
     if (!function_exists('gd_info')) {
         throw new Zend_Pdf_Exception('Image extension is not installed.');
     }
     $gd_options = gd_info();
     if (!$gd_options['JPG Support']) {
         throw new Zend_Pdf_Exception('JPG support is not configured properly.');
     }
     if (($imageInfo = getimagesize($imageFileName)) === false) {
         throw new Zend_Pdf_Exception('Corrupted image or image doesn\'t exist.');
     }
     if ($imageInfo[2] != IMAGETYPE_JPEG && $imageInfo[2] != IMAGETYPE_JPEG2000) {
         throw new Zend_Pdf_Exception('ImageType is not JPG');
     }
     parent::__construct();
     switch ($imageInfo['channels']) {
         case 3:
             $colorSpace = 'DeviceRGB';
             break;
         case 4:
             $colorSpace = 'DeviceCMYK';
             break;
         default:
             $colorSpace = 'DeviceGray';
             break;
     }
     $imageDictionary = $this->_resource->dictionary;
     $imageDictionary->Width = new Zend_Pdf_Element_Numeric($imageInfo[0]);
     $imageDictionary->Height = new Zend_Pdf_Element_Numeric($imageInfo[1]);
     $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($colorSpace);
     $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($imageInfo['bits']);
     if ($imageInfo[2] == IMAGETYPE_JPEG) {
         $imageDictionary->Filter = new Zend_Pdf_Element_Name('DCTDecode');
     } else {
         if ($imageInfo[2] == IMAGETYPE_JPEG2000) {
             $imageDictionary->Filter = new Zend_Pdf_Element_Name('JPXDecode');
         }
     }
     if (($imageFile = @fopen($imageFileName, 'rb')) === false) {
         throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading.");
     }
     $byteCount = filesize($imageFileName);
     $this->_resource->value = '';
     while ($byteCount > 0 && ($nextBlock = fread($imageFile, $byteCount)) != false) {
         $this->_resource->value .= $nextBlock;
         $byteCount -= strlen($nextBlock);
     }
     fclose($imageFile);
     $this->_resource->skipFilters();
     $this->_width = $imageInfo[0];
     $this->_height = $imageInfo[1];
     $this->_imageProperties = array();
     $this->_imageProperties['bitDepth'] = $imageInfo['bits'];
     $this->_imageProperties['jpegImageType'] = $imageInfo[2];
     $this->_imageProperties['jpegColorType'] = $imageInfo['channels'];
 }
Exemple #2
0
 /**
  * Object constructor
  *
  * @param string $imageFileName
  * @throws Zend_Pdf_Exception
  */
 public function __construct($imageFileName)
 {
     if (($imageInfo = getimagesize($imageFileName)) === false) {
         throw new Zend_Pdf_Exception('Corrupted image or image doesn\'t exist.');
     }
     if ($imageInfo[2] != IMAGETYPE_TIFF_II && $imageInfo[2] != IMAGETYPE_TIFF_MM) {
         throw new Zend_Pdf_Exception('ImageType is not TIFF');
     }
     parent::__construct();
     /* This needs to be fixed
         switch ($imageInfo['channels']) {
             case 3:
                 $colorSpace = 'DeviceRGB';
                 break;
             case 4:
                 $colorSpace = 'DeviceCMYK';
                 break;
             default:
                 $colorSpace = 'DeviceGray';
                 break;
         }
        */
     /*
     This is a temporary hack - this needs to be read from the tiff file format.
     IMAGICK pecl extension contains imagick_getcolorspace but introducing another
     extension dependency is probably bad.
     */
     $colorSpace = 'DeviceRGB';
     $imageDictionary = $this->_resource->dictionary;
     $imageDictionary->Width = new Zend_Pdf_Element_Numeric($imageInfo[0]);
     $imageDictionary->Height = new Zend_Pdf_Element_Numeric($imageInfo[1]);
     $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($colorSpace);
     //      $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($imageInfo['bits']);
     //This is also a temporary hack - Corresponds imagick_getimagedepth
     $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric(8);
     if (($imageFile = @fopen($imageFileName, 'rb')) === false) {
         throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading.");
     }
     $byteCount = filesize($imageFileName);
     $this->_resource->value = '';
     while ($byteCount > 0 && ($nextBlock = fread($imageFile, $byteCount)) != false) {
         $this->_resource->value .= $nextBlock;
         $byteCount -= strlen($nextBlock);
     }
     fclose($imageFile);
     $this->_resource->skipFilters();
 }
Exemple #3
0
 /**
  * Object constructor
  *
  * @param string $imageFileName
  * @throws Zend_Pdf_Exception
  * @todo Add compression conversions to support compression strategys other than PNG_COMPRESSION_DEFAULT_STRATEGY.
  * @todo Add pre-compression filtering.
  * @todo Add interlaced image handling.
  * @todo Add support for 16-bit images. Requires PDF version bump to 1.5 at least.
  * @todo Add processing for all PNG chunks defined in the spec. gAMA etc.
  * @todo Fix tRNS chunk support for Indexed Images to a SMask.
  */
 public function __construct($imageFileName)
 {
     if (($imageFile = @fopen($imageFileName, 'rb')) === false) {
         throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading.");
     }
     parent::__construct();
     //Check if the file is a PNG
     fseek($imageFile, 1, SEEK_CUR);
     //First signature byte (%)
     if ('PNG' != fread($imageFile, 3)) {
         throw new Zend_Pdf_Exception('Image is not a PNG');
     }
     fseek($imageFile, 12, SEEK_CUR);
     //Signature bytes (Includes the IHDR chunk) IHDR processed linerarly because it doesnt contain a variable chunk length
     $wtmp = unpack('Ni', fread($imageFile, 4));
     //Unpack a 4-Byte Long
     $width = $wtmp['i'];
     $htmp = unpack('Ni', fread($imageFile, 4));
     $height = $htmp['i'];
     $bits = ord(fread($imageFile, 1));
     //Higher than 8 bit depths are only supported in later versions of PDF.
     $color = ord(fread($imageFile, 1));
     $compression = ord(fread($imageFile, 1));
     $prefilter = ord(fread($imageFile, 1));
     if (($interlacing = ord(fread($imageFile, 1))) != Zend_Pdf_Image_Png::PNG_INTERLACING_DISABLED) {
         throw new Zend_Pdf_Exception("Only non-interlaced images are currently supported.");
     }
     $this->_width = $width;
     $this->_height = $height;
     $this->_imageProperties = array();
     $this->_imageProperties['bitDepth'] = $bits;
     $this->_imageProperties['pngColorType'] = $color;
     $this->_imageProperties['pngFilterType'] = $prefilter;
     $this->_imageProperties['pngCompressionType'] = $compression;
     $this->_imageProperties['pngInterlacingType'] = $interlacing;
     fseek($imageFile, 4, SEEK_CUR);
     //4 Byte Ending Sequence
     $imageData = '';
     /*
      * The following loop processes PNG chunks. 4 Byte Longs are packed first give the chunk length
      * followed by the chunk signature, a four byte code. IDAT and IEND are manditory in any PNG.
      */
     while (($chunkLengthBytes = fread($imageFile, 4)) !== false) {
         $chunkLengthtmp = unpack('Ni', $chunkLengthBytes);
         $chunkLength = $chunkLengthtmp['i'];
         $chunkType = fread($imageFile, 4);
         switch ($chunkType) {
             case 'IDAT':
                 //Image Data
                 /*
                  * Reads the actual image data from the PNG file. Since we know at this point that the compression
                  * strategy is the default strategy, we also know that this data is Zip compressed. We will either copy
                  * the data directly to the PDF and provide the correct FlateDecode predictor, or decompress the data
                  * decode the filters and output the data as a raw pixel map.
                  */
                 $imageData .= fread($imageFile, $chunkLength);
                 fseek($imageFile, 4, SEEK_CUR);
                 break;
             case 'PLTE':
                 //Palette
                 $paletteData = fread($imageFile, $chunkLength);
                 fseek($imageFile, 4, SEEK_CUR);
                 break;
             case 'tRNS':
                 //Basic (non-alpha channel) transparency.
                 $trnsData = fread($imageFile, $chunkLength);
                 switch ($color) {
                     case Zend_Pdf_Image_Png::PNG_CHANNEL_GRAY:
                         $baseColor = ord(substr($trnsData, 1, 1));
                         $transparencyData = array(new Zend_Pdf_Element_Numeric($baseColor), new Zend_Pdf_Element_Numeric($baseColor));
                         break;
                     case Zend_Pdf_Image_Png::PNG_CHANNEL_RGB:
                         $red = ord(substr($trnsData, 1, 1));
                         $green = ord(substr($trnsData, 3, 1));
                         $blue = ord(substr($trnsData, 5, 1));
                         $transparencyData = array(new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($blue), new Zend_Pdf_Element_Numeric($blue));
                         break;
                     case Zend_Pdf_Image_Png::PNG_CHANNEL_INDEXED:
                         //Find the first transparent color in the index, we will mask that. (This is a bit of a hack. This should be a SMask and mask all entries values).
                         if (($trnsIdx = strpos($trnsData, chr(0))) !== false) {
                             $transparencyData = array(new Zend_Pdf_Element_Numeric($trnsIdx), new Zend_Pdf_Element_Numeric($trnsIdx));
                         }
                         break;
                     case Zend_Pdf_Image_Png::PNG_CHANNEL_GRAY_ALPHA:
                         // Fall through to the next case
                     // Fall through to the next case
                     case Zend_Pdf_Image_Png::PNG_CHANNEL_RGB_ALPHA:
                         throw new Zend_Pdf_Exception("tRNS chunk illegal for Alpha Channel Images");
                         break;
                 }
                 fseek($imageFile, 4, SEEK_CUR);
                 //4 Byte Ending Sequence
                 break;
             case 'IEND':
                 break 2;
                 //End the loop too
             //End the loop too
             default:
                 fseek($imageFile, $chunkLength + 4, SEEK_CUR);
                 //Skip the section
                 break;
         }
     }
     fclose($imageFile);
     $compressed = true;
     $imageDataTmp = '';
     $smaskData = '';
     switch ($color) {
         case Zend_Pdf_Image_Png::PNG_CHANNEL_RGB:
             $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB');
             break;
         case Zend_Pdf_Image_Png::PNG_CHANNEL_GRAY:
             $colorSpace = new Zend_Pdf_Element_Name('DeviceGray');
             break;
         case Zend_Pdf_Image_Png::PNG_CHANNEL_INDEXED:
             if (empty($paletteData)) {
                 throw new Zend_Pdf_Exception("PNG Corruption: No palette data read for indexed type PNG.");
             }
             $colorSpace = new Zend_Pdf_Element_Array();
             $colorSpace->items[] = new Zend_Pdf_Element_Name('Indexed');
             $colorSpace->items[] = new Zend_Pdf_Element_Name('DeviceRGB');
             $colorSpace->items[] = new Zend_Pdf_Element_Numeric(strlen($paletteData) / 3 - 1);
             $paletteObject = $this->_objectFactory->newObject(new Zend_Pdf_Element_String_Binary($paletteData));
             $colorSpace->items[] = $paletteObject;
             break;
         case Zend_Pdf_Image_Png::PNG_CHANNEL_GRAY_ALPHA:
             /*
              * To decode PNG's with alpha data we must create two images from one. One image will contain the Gray data
              * the other will contain the Gray transparency overlay data. The former will become the object data and the latter
              * will become the Shadow Mask (SMask).
              */
             if ($bits > 8) {
                 throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported");
             }
             $colorSpace = new Zend_Pdf_Element_Name('DeviceGray');
             $decodingObjFactory = new Zend_Pdf_ElementFactory(1);
             $decodingStream = $decodingObjFactory->newStreamObject($imageData);
             $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
             $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary();
             $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15);
             $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width);
             $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(2);
             //GreyAlpha
             $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits);
             $decodingStream->skipFilters();
             $pngDataRawDecoded = $decodingStream->value;
             //Iterate every pixel and copy out gray data and alpha channel (this will be slow)
             for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) {
                 $imageDataTmp .= $pngDataRawDecoded[$pixel * 2];
                 $smaskData .= $pngDataRawDecoded[$pixel * 2 + 1];
             }
             $compressed = false;
             $imageData = $imageDataTmp;
             //Overwrite image data with the gray channel without alpha
             break;
         case Zend_Pdf_Image_Png::PNG_CHANNEL_RGB_ALPHA:
             /*
              * To decode PNG's with alpha data we must create two images from one. One image will contain the RGB data
              * the other will contain the Gray transparency overlay data. The former will become the object data and the latter
              * will become the Shadow Mask (SMask).
              */
             if ($bits > 8) {
                 throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported");
             }
             $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB');
             $decodingObjFactory = new Zend_Pdf_ElementFactory(1);
             $decodingStream = $decodingObjFactory->newStreamObject($imageData);
             $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
             $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary();
             $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15);
             $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width);
             $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(4);
             //RGBA
             $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits);
             $decodingStream->skipFilters();
             $pngDataRawDecoded = $decodingStream->value;
             //Iterate every pixel and copy out rgb data and alpha channel (this will be slow)
             for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) {
                 $imageDataTmp .= $pngDataRawDecoded[$pixel * 4 + 0] . $pngDataRawDecoded[$pixel * 4 + 1] . $pngDataRawDecoded[$pixel * 4 + 2];
                 $smaskData .= $pngDataRawDecoded[$pixel * 4 + 3];
             }
             $compressed = false;
             $imageData = $imageDataTmp;
             //Overwrite image data with the RGB channel without alpha
             break;
         default:
             throw new Zend_Pdf_Exception("PNG Corruption: Invalid color space.");
     }
     if (empty($imageData)) {
         throw new Zend_Pdf_Exception("Corrupt PNG Image. Mandatory IDAT chunk not found.");
     }
     $imageDictionary = $this->_resource->dictionary;
     if (!empty($smaskData)) {
         /*
          * Includes the Alpha transparency data as a Gray Image, then assigns the image as the Shadow Mask for the main image data.
          */
         $smaskStream = $this->_objectFactory->newStreamObject($smaskData);
         $smaskStream->dictionary->Type = new Zend_Pdf_Element_Name('XObject');
         $smaskStream->dictionary->Subtype = new Zend_Pdf_Element_Name('Image');
         $smaskStream->dictionary->Width = new Zend_Pdf_Element_Numeric($width);
         $smaskStream->dictionary->Height = new Zend_Pdf_Element_Numeric($height);
         $smaskStream->dictionary->ColorSpace = new Zend_Pdf_Element_Name('DeviceGray');
         $smaskStream->dictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits);
         $imageDictionary->SMask = $smaskStream;
         // Encode stream with FlateDecode filter
         $smaskStreamDecodeParms = array();
         $smaskStreamDecodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15);
         $smaskStreamDecodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width);
         $smaskStreamDecodeParms['Colors'] = new Zend_Pdf_Element_Numeric(1);
         $smaskStreamDecodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric(8);
         $smaskStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($smaskStreamDecodeParms);
         $smaskStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
     }
     if (!empty($transparencyData)) {
         //This is experimental and not properly tested.
         $imageDictionary->Mask = new Zend_Pdf_Element_Array($transparencyData);
     }
     $imageDictionary->Width = new Zend_Pdf_Element_Numeric($width);
     $imageDictionary->Height = new Zend_Pdf_Element_Numeric($height);
     $imageDictionary->ColorSpace = $colorSpace;
     $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits);
     $imageDictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
     $decodeParms = array();
     $decodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15);
     // Optimal prediction
     $decodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width);
     $decodeParms['Colors'] = new Zend_Pdf_Element_Numeric($color == Zend_Pdf_Image_Png::PNG_CHANNEL_RGB || $color == Zend_Pdf_Image_Png::PNG_CHANNEL_RGB_ALPHA ? 3 : 1);
     $decodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric($bits);
     $imageDictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($decodeParms);
     //Include only the image IDAT section data.
     $this->_resource->value = $imageData;
     //Skip double compression
     if ($compressed) {
         $this->_resource->skipFilters();
     }
 }
Exemple #4
0
 /**
  * Object constructor
  *
  * @param string $imageFileName
  * @throws Zend_Pdf_Exception
  */
 public function __construct($imageFileName)
 {
     if (($imageFile = @fopen($imageFileName, 'rb')) === false) {
         throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading.");
     }
     parent::__construct();
     //Check if the file is a PNG
     fseek($imageFile, 1, SEEK_CUR);
     //First signature byte (%)
     if ('PNG' != fread($imageFile, 3)) {
         throw new Zend_Pdf_Exception('Image is not a PNG');
     }
     fseek($imageFile, 12, SEEK_CUR);
     //Signature bytes (Includes the IHDR chunk) IHDR processed linerarly because it doesnt contain a variable chunk length
     $wtmp = unpack('Ni', fread($imageFile, 4));
     //Unpack a 4-Byte Long
     $width = $wtmp['i'];
     $htmp = unpack('Ni', fread($imageFile, 4));
     $height = $htmp['i'];
     $bits = ord(fread($imageFile, 1));
     //Higher than 8 bit depths are only supported in later versions of PDF.
     $color = ord(fread($imageFile, 1));
     if (ord(fread($imageFile, 1)) != Zend_Pdf_Image_PNG::PNG_COMPRESSION_DEFAULT_STRATEGY) {
         //TODO: Add compression conversions
         throw new Zend_Pdf_Exception("Only the default compression strategy is currently supported.");
     }
     if (ord(fread($imageFile, 1)) != Zend_Pdf_Image_PNG::PNG_FILTER_NONE) {
         //TODO: Support PNG Filtering
         throw new Zend_Pdf_Exception("Filtering methods are not currently supported. ");
     }
     if (ord(fread($imageFile, 1)) != Zend_Pdf_Image_PNG::PNG_INTERLACING_DISABLED) {
         //TODO: Support Interlacing
         throw new Zend_Pdf_Exception("Only non-interlaced images are currently supported.");
     }
     fseek($imageFile, 4, SEEK_CUR);
     //4 Byte Ending Sequence
     $imageData = '';
     /*
      * The following loop processes PNG chunks. 4 Byte Longs are packed first give the chunk length
      * followed by the chunk signature, a four byte code. IDAT and IEND are manditory in any PNG.
      */
     while ($chunkLengthBytes = fread($imageFile, 4)) {
         $chunkLengthtmp = unpack('Ni', $chunkLengthBytes);
         $chunkLength = $chunkLengthtmp['i'];
         $chunkType = fread($imageFile, 4);
         switch ($chunkType) {
             //TODO: Support all PNG chunks
             case 'IDAT':
                 //Image Data
                 $imageData .= fread($imageFile, $chunkLength);
                 fseek($imageFile, 4, SEEK_CUR);
                 break;
             case 'PLTE':
                 //Palette
                 if ($color != Zend_Pdf_Image_PNG::PNG_CHANNEL_INDEXED) {
                     throw new Zend_Pdf_Exception("Only indexed color PNG's can contain palette entries.");
                 }
                 $paletteData = fread($imageFile, $chunkLength);
                 fseek($imageFile, 4, SEEK_CUR);
                 break;
             case 'tRNS':
                 //Basic (non-alpha channel) transparency. (untested)
                 switch ($color) {
                     case Zend_Pdf_Image_PNG::PNG_CHANNEL_GRAY:
                         $baseColor = unpack('n', fread($imageFile, 2));
                         $transparencyData = array($baseColor['n']);
                         fseek($imageFile, $chunkLength - 2, SEEK_CUR);
                         break;
                     case Zend_Pdf_Image_PNG::PNG_CHANNEL_RGB:
                         $red = unpack('n', fread($imageFile, 2));
                         $green = unpack('n', fread($imageFile, 2));
                         $blue = unpack('n', fread($imageFile, 2));
                         $transparencyData = array($red['n'], $green['n'], $blue['n']);
                         fseek($imageFile, $chunkLength - 6, SEEK_CUR);
                         break;
                     case Zend_Pdf_Image_PNG::PNG_CHANNEL_INDEXED:
                         //TODO: Read "For color type 3 (indexed color), the tRNS chunk contains a series of one-byte alpha values, corresponding to entries in the PLTE chunk"
                         fseek($imageFile, $chunkLength, SEEK_CUR);
                         throw new Zend_Pdf_Exception("tRNS chunk not yet supported for INDEXED color images..");
                         break;
                     case Zend_Pdf_Image_PNG::PNG_CHANNEL_GRAY_ALPHA:
                         // Fall through to the next case
                     // Fall through to the next case
                     case Zend_Pdf_Image_PNG::PNG_CHANNEL_RGB_ALPHA:
                         fseek($imageFile, $chunkLength, SEEK_CUR);
                         throw new Zend_Pdf_Exception("tRNS chunk illegal for Alpha Channel Images");
                         break;
                 }
                 fseek($imageFile, 4, SEEK_CUR);
                 //4 Byte Ending Sequence
                 break;
             case 'IEND':
                 break 2;
                 //End the loop too
             //End the loop too
             default:
                 fseek($imageFile, $chunkLength + 4, SEEK_CUR);
                 //Skip the section
                 break;
         }
     }
     switch ($color) {
         case Zend_Pdf_Image_PNG::PNG_CHANNEL_RGB:
             $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB');
             break;
         case Zend_Pdf_Image_PNG::PNG_CHANNEL_GRAY:
             $colorSpace = new Zend_Pdf_Element_Name('DeviceGray');
             break;
         case Zend_Pdf_Image_PNG::PNG_CHANNEL_INDEXED:
             $colorSpace = new Zend_Pdf_Element_Array();
             $colorSpace->items[] = new Zend_Pdf_Element_Name('Indexed');
             $colorSpace->items[] = new Zend_Pdf_Element_Name('DeviceRGB');
             $colorSpace->items[] = new Zend_Pdf_Element_Numeric(strlen($paletteData) / 3 - 1);
             $paletteObject = $this->_objectFactory->newObject(new Zend_Pdf_Element_String_Binary($paletteData));
             $colorSpace->items[] = $paletteObject;
             break;
         case Zend_Pdf_Image_PNG::PNG_CHANNEL_GRAY_ALPHA:
             /* Same problem as RGB+Alpha */
             throw new Zend_Pdf_Exception("PNGs with GRAYSCALE + Alpha are not yet supported");
             break;
         case Zend_Pdf_Image_PNG::PNG_CHANNEL_RGB_ALPHA:
             /*
              * Looked into this, im not sure how exactly, but to do this conversion; we
              * must remove the alpha channel from the data stream, and place it into a SMask
              * format with its own stream.
              *
              * This is probably the most common and therefore important mode to get working.
              */
             $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB');
             throw new Zend_Pdf_Exception("4 Channel RGB+Alpha Images Are Not Supported Yet. ");
             break;
         default:
             throw new Zend_Pdf_Exception("PNG Corruption: Invalid color space.");
     }
     if (empty($imageData)) {
         throw new Zend_Pdf_Exception("Corrupt PNG Image. Manditory IDAT chunk not found.");
     }
     fclose($imageFile);
     /* This array adds the Predictor which must be > 10 (15=optimal) for PNG parsing */
     $decodeParms = array();
     $decodeParms['Predictor'] = new Zend_Pdf_Element_Numeric('15');
     $decodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width);
     $decodeParms['Colors'] = new Zend_Pdf_Element_Numeric($color == 2 ? 3 : 1);
     $decodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric($bits);
     $imageDictionary = $this->_resource->dictionary;
     $imageDictionary->Width = new Zend_Pdf_Element_Numeric($width);
     $imageDictionary->Height = new Zend_Pdf_Element_Numeric($height);
     $imageDictionary->ColorSpace = $colorSpace;
     $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits);
     $imageDictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
     $imageDictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($decodeParms);
     if (!empty($smaskData)) {
         $smaskStream = $this->_objectFactory->newStreamObject($smaskData);
         $smaskStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
         $imageDictionary->SMask = $smaskStream;
     }
     if (!empty($transparencyData)) {
         $imageDictionary->Mask = new Zend_Pdf_Element_Array($transparencyData);
     }
     //Include only the image IDAT section data.
     $this->_resource->value = $imageData;
     //Skip double compression
     $this->_resource->skipFilters();
 }
 /**
  * Object constructor
  *
  * @param string $imageFileName
  * @throws Zend_Pdf_Exception
  */
 public function __construct($imageFileName)
 {
     if (($imageFile = @fopen($imageFileName, 'rb')) === false) {
         throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading.");
     }
     $byteOrderIndicator = fread($imageFile, 2);
     if ($byteOrderIndicator == 'II') {
         $this->_endianType = Zend_Pdf_Image_TIFF::TIFF_ENDIAN_LITTLE;
     } else {
         if ($byteOrderIndicator == 'MM') {
             $this->_endianType = Zend_Pdf_Image_TIFF::TIFF_ENDIAN_BIG;
         } else {
             throw new Zend_Pdf_Exception("Not a tiff file or Tiff corrupt. No byte order indication found");
         }
     }
     $version = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, fread($imageFile, 2));
     if ($version != 42) {
         throw new Zend_Pdf_Exception("Not a tiff file or Tiff corrupt. Incorrect version number.");
     }
     $ifdOffset = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_LONG, fread($imageFile, 4));
     $fileStats = fstat($imageFile);
     $this->_fileSize = $fileStats['size'];
     /*
      * Tiff files are stored as a series of Image File Directories (IFD) each direcctory 
      * has a specific number of entries each 12 bytes in length. At the end of the directories
      * is four bytes pointing to the offset of the next IFD.
      */
     while ($ifdOffset > 0) {
         if (fseek($imageFile, $ifdOffset, SEEK_SET) == -1 || $ifdOffset + 2 >= $this->_fileSize) {
             throw new Zend_Pdf_Exception("Could not seek to the image file directory as indexed by the file. Likely cause is TIFF corruption. Offset: " . $ifdOffset);
         }
         $numDirEntries = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, fread($imageFile, 2));
         /*
          * Since we now know how many entries are in this (IFD) we can extract the data.
          * The format of a TIFF directory entry is:
          * 
          * 2 bytes (short) tag code; See TIFF_TAG constants at the top for supported values. (There are many more in the spec)
          * 2 bytes (short) field type
          * 4 bytes (long) number of values, or value count.
          * 4 bytes (mixed) data if the data will fit into 4 bytes or an offset if the data is too large.
          */
         for ($dirEntryIdx = 1; $dirEntryIdx <= $numDirEntries; $dirEntryIdx++) {
             $tag = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, fread($imageFile, 2));
             $fieldType = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, fread($imageFile, 2));
             $valueCount = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_LONG, fread($imageFile, 4));
             switch ($fieldType) {
                 case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_BYTE:
                     $fieldLength = $valueCount;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_ASCII:
                     $fieldLength = $valueCount;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_SHORT:
                     $fieldLength = $valueCount * 2;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_LONG:
                     $fieldLength = $valueCount * 4;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_RATIONAL:
                     $fieldLength = $valueCount * 8;
                     break;
                 default:
                     $fieldLength = $valueCount;
             }
             $offsetBytes = fread($imageFile, 4);
             if ($fieldLength <= 4) {
                 switch ($fieldType) {
                     case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_BYTE:
                         $value = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_BYTE, $offsetBytes);
                         break;
                     case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_ASCII:
                         //Fall through to next case
                     //Fall through to next case
                     case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_LONG:
                         $value = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_LONG, $offsetBytes);
                         break;
                     case Zend_Pdf_Image_TIFF::TIFF_FIELD_TYPE_SHORT:
                         //Fall through to next case
                     //Fall through to next case
                     default:
                         $value = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, $offsetBytes);
                 }
             } else {
                 $refOffset = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_LONG, $offsetBytes);
             }
             /*
              * Linear tag processing is probably not the best way to do this. I've processed the tags according to the
              * Tiff 6 specification and make some assumptions about when tags will be < 4 bytes and fit into $value and when
              * they will be > 4 bytes and require seek/extraction of the offset. Same goes for extracting arrays of data, like
              * the data offsets and length. This should be fixed in the future.
              */
             switch ($tag) {
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_IMAGE_WIDTH:
                     $this->_width = $value;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_IMAGE_LENGTH:
                     $this->_height = $value;
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_BITS_PER_SAMPLE:
                     if ($valueCount > 1) {
                         $fp = ftell($imageFile);
                         fseek($imageFile, $refOffset, SEEK_SET);
                         $this->_bitsPerSample = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_SHORT, fread($imageFile, 2));
                         fseek($imageFile, $fp, SEEK_SET);
                     } else {
                         $this->_bitsPerSample = $value;
                     }
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_COMPRESSION:
                     $this->_compression = $value;
                     switch ($value) {
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_UNCOMPRESSED:
                             $this->_filter = 'None';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_CCITT1D:
                             //Fall through to next case
                         //Fall through to next case
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_GROUP_3_FAX:
                             //Fall through to next case
                         //Fall through to next case
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_GROUP_4_FAX:
                             $this->_filter = 'CCITTFaxDecode';
                             throw new Zend_Pdf_Exception("CCITTFaxDecode Compression Mode Not Currently Supported");
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_LZW:
                             $this->_filter = 'LZWDecode';
                             throw new Zend_Pdf_Exception("LZWDecode Compression Mode Not Currently Supported");
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_JPEG:
                             $this->_filter = 'DCTDecode';
                             //Should work, doesnt...
                             throw new Zend_Pdf_Exception("JPEG Compression Mode Not Currently Supported");
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_FLATE:
                             //fall through to next case
                         //fall through to next case
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_FLATE_OBSOLETE_CODE:
                             $this->_filter = 'FlateDecode';
                             throw new Zend_Pdf_Exception("ZIP/Flate Compression Mode Not Currently Supported");
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_COMPRESSION_PACKBITS:
                             $this->_filter = 'RunLengthDecode';
                             break;
                     }
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_PHOTOMETRIC_INTERPRETATION:
                     $this->_colorCode = $value;
                     $this->_whiteIsZero = false;
                     $this->_blackIsZero = false;
                     switch ($value) {
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO:
                             $this->_whiteIsZero = true;
                             $this->_colorSpace = 'DeviceGray';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO:
                             $this->_blackIsZero = true;
                             $this->_colorSpace = 'DeviceGray';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_YCBCR:
                             //fall through to next case
                         //fall through to next case
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_RGB:
                             $this->_colorSpace = 'DeviceRGB';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_RGB_INDEXED:
                             $this->_colorSpace = 'Indexed';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_CMYK:
                             $this->_colorSpace = 'DeviceCMYK';
                             break;
                         case Zend_Pdf_Image_TIFF::TIFF_PHOTOMETRIC_INTERPRETATION_CIELAB:
                             $this->_colorSpace = 'Lab';
                             break;
                         default:
                             throw new Zend_Pdf_Exception('TIFF: Unknown or Unsupported Color Type: ' . $value);
                     }
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_STRIP_OFFSETS:
                     if ($valueCount > 1) {
                         $format = $this->_endianType == Zend_Pdf_Image_TIFF::TIFF_ENDIAN_LITTLE ? 'V*' : 'N*';
                         $fp = ftell($imageFile);
                         fseek($imageFile, $refOffset, SEEK_SET);
                         $stripOffsetsBytes = fread($imageFile, $fieldLength);
                         $this->_imageDataOffset = unpack($format, $stripOffsetsBytes);
                         fseek($imageFile, $fp, SEEK_SET);
                     } else {
                         $this->_imageDataOffset = $value;
                     }
                     break;
                 case Zend_Pdf_Image_TIFF::TIFF_TAG_STRIP_BYTE_COUNTS:
                     if ($valueCount > 1) {
                         $format = $this->_endianType == Zend_Pdf_Image_TIFF::TIFF_ENDIAN_LITTLE ? 'V*' : 'N*';
                         $fp = ftell($imageFile);
                         fseek($imageFile, $refOffset, SEEK_SET);
                         $stripByteCountsBytes = fread($imageFile, $fieldLength);
                         $this->_imageDataLength = unpack($format, $stripByteCountsBytes);
                         fseek($imageFile, $fp, SEEK_SET);
                     } else {
                         $this->_imageDataLength = $value;
                     }
                     break;
                 default:
                     //For debugging. It should be harmless to ignore unknown tags, though there is some good info in them.
                     //echo "Unknown tag detected: ". $tag . " value: ". $value;
             }
         }
         $ifdOffset = $this->unpackBytes(Zend_Pdf_Image_TIFF::UNPACK_TYPE_LONG, fread($imageFile, 4));
     }
     if (!isset($this->_imageDataOffset) || !isset($this->_imageDataLength)) {
         throw new Zend_Pdf_Exception("TIFF: The image processed did not contain image data as expected.");
     }
     $imageDataBytes = '';
     if (is_array($this->_imageDataOffset)) {
         if (!is_array($this->_imageDataLength)) {
             throw new Zend_Pdf_Exception("TIFF: The image contained multiple data offsets but not multiple data lengths. Tiff may be corrupt.");
         }
         foreach ($this->_imageDataOffset as $idx => $offset) {
             fseek($imageFile, $this->_imageDataOffset[$idx], SEEK_SET);
             $imageDataBytes .= fread($imageFile, $this->_imageDataLength[$idx]);
         }
     } else {
         fseek($imageFile, $this->_imageDataOffset, SEEK_SET);
         $imageDataBytes = fread($imageFile, $this->_imageDataLength);
     }
     if ($imageDataBytes === '') {
         throw new Zend_Pdf_Exception("TIFF: No data. Image Corruption");
     }
     fclose($imageFile);
     parent::__construct();
     $imageDictionary = $this->_resource->dictionary;
     if (!isset($this->_width) || !isset($this->_width)) {
         throw new Zend_Pdf_Exception("Problem reading tiff file. Tiff is probably corrupt.");
     }
     $this->_imageProperties = array();
     $this->_imageProperties['bitDepth'] = $this->_bitsPerSample;
     $this->_imageProperties['fileSize'] = $this->_fileSize;
     $this->_imageProperties['TIFFendianType'] = $this->_endianType;
     $this->_imageProperties['TIFFcompressionType'] = $this->_compression;
     $this->_imageProperties['TIFFwhiteIsZero'] = $this->_whiteIsZero;
     $this->_imageProperties['TIFFblackIsZero'] = $this->_blackIsZero;
     $this->_imageProperties['TIFFcolorCode'] = $this->_colorCode;
     $this->_imageProperties['TIFFimageDataOffset'] = $this->_imageDataOffset;
     $this->_imageProperties['TIFFimageDataLength'] = $this->_imageDataLength;
     $this->_imageProperties['PDFfilter'] = $this->_filter;
     $this->_imageProperties['PDFcolorSpace'] = $this->_colorSpace;
     $imageDictionary->Width = new Zend_Pdf_Element_Numeric($this->_width);
     if ($this->_whiteIsZero === true) {
         $imageDictionary->Decode = new Zend_Pdf_Element_Array(array(new Zend_Pdf_Element_Numeric(1), new Zend_Pdf_Element_Numeric(0)));
     }
     $imageDictionary->Height = new Zend_Pdf_Element_Numeric($this->_height);
     $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($this->_colorSpace);
     $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($this->_bitsPerSample);
     if (isset($this->_filter) && $this->_filter != 'None') {
         $imageDictionary->Filter = new Zend_Pdf_Element_Name($this->_filter);
     }
     $this->_resource->value = $imageDataBytes;
     $this->_resource->skipFilters();
 }