PHPSEEKER.ORG

A free resort for PHP Developers

Validate JPG and PSD CMYK colors

Learn how to generate PDF documents using Adobe Framework and PHP

Validate JPG and PSD CMYK colors

Postby toshio » Wed Apr 07, 2010 7:20 am

Here is a function to validate CMYK colors for JPG and PSD files.
It requires the class classPhpPsdReader.php written by Tim de Koning to work (read comments on code)


Code: Select all
<?php
/*
*   @distribution: GPL
*   @return: returns a boolean if JPG or PNG is CMYK
*   @original class written and supported by Tim de Koning
*   @includes: classPhpPsdReader.php
*   @usage:
*      use it to validation: ex.: if(is_CMYK("myfile.jpg")){ ... }
*   @notes:
*      There is no such thing as CYMK is JPG. It's a hack. Although a common hack, not a widely supported hack.
*      TIFF and PDS files can be CMYK legitimately although JPG work also if well resized (300++dpi).
*
*/

function is_CMYK($filename)
{
  $matches=split('\.',$filename);
    foreach ($matches as $key=>$value)
    {
      $extension=$value; //if there is more than one period, this will find the actual extension.
    }
  switch ($extension)
  {
    case 'psd':
      include('classPhpPsdReader.php');
      $psd = new PhpPsdReader($filename);
      if($psd->infoArray['colorMode']==4)
      {
       return TRUE;
      }
      break;
    case 'jpg':
    $size = getimagesize($filename);
    //echo ("get image size found $size[channels] channels");
    if($size[channels]==4)
    {
     return TRUE;
    }
    default:
    return FALSE;
    break;
  }
  return FALSE;
}
?>


Tim de Koning's classPhpPsdReader.php
Code: Select all
<?
/* This file is released under the GPL, any version you like
*
*   PHP PSD reader class, v1.3
*
*   By Tim de Koning
*
*   Kingsquare Information Services, 22 jan 2007
*
*   example use:
*   ------------
*   <?php
*   include_once('file:///C|/DOCUME~1/ADMINI~1/CONFIG~1/Temp/classPhpPsdReader.php')
*   header("Content-type: image/jpeg");
*   print imagejpeg(imagecreatefrompsd('test.psd'));
*   ?>
*
*
*   More info, bugs or requests, contact info@kingsquare.nl
*
*   Latest version and demo: http://www.kingsquare.nl/phppsdreader
*
*   TODO
*   ----
*   - read color values for "multichannel data" PSD files
*   - find and implement (hunter)lab to RGB algorithm
*   - fix 32 bit colors... has something to do with gamma and exposure available since CS2, but dunno how to read them...
*/


class PhpPsdReader {
   var $infoArray;
   var $fp;
   var $fileName;
   var $tempFileName;
   var $colorBytesLength;

   function PhpPsdReader($fileName) {
      set_time_limit(0);
      $this->infoArray = array();
      $this->fileName = $fileName;
      $this->fp = fopen($this->fileName,'r');

      if (fread($this->fp,4)=='8BPS') {
         $this->infoArray['version id'] = $this->_getInteger(2);
         fseek($this->fp,6,SEEK_CUR); // 6 bytes of 0's
         $this->infoArray['channels'] = $this->_getInteger(2);
         $this->infoArray['rows'] = $this->_getInteger(4);
         $this->infoArray['columns'] = $this->_getInteger(4);
         $this->infoArray['colorDepth'] = $this->_getInteger(2);
         $this->infoArray['colorMode'] = $this->_getInteger(2);


         /* COLOR MODE DATA SECTION */ //4bytes Length The length of the following color data.
         $this->infoArray['colorModeDataSectionLength'] = $this->_getInteger(4);
         fseek($this->fp,$this->infoArray['colorModeDataSectionLength'],SEEK_CUR); // ignore this snizzle

         /*  IMAGE RESOURCES */
         $this->infoArray['imageResourcesSectionLength'] = $this->_getInteger(4);
         fseek($this->fp,$this->infoArray['imageResourcesSectionLength'],SEEK_CUR); // ignore this snizzle

         /*  LAYER AND MASK */
         $this->infoArray['layerMaskDataSectionLength'] = $this->_getInteger(4);
         fseek($this->fp,$this->infoArray['layerMaskDataSectionLength'],SEEK_CUR); // ignore this snizzle


         /*  IMAGE DATA */
         $this->infoArray['compressionType'] = $this->_getInteger(2);
         $this->infoArray['oneColorChannelPixelBytes'] = $this->infoArray['colorDepth']/8;
         $this->colorBytesLength = $this->infoArray['rows']*$this->infoArray['columns']*$this->infoArray['oneColorChannelPixelBytes'];

         if ($this->infoArray['colorMode']==2) {
            $this->infoArray['error'] = 'images with indexed colours are not supported yet';
            return false;
         }
      } else {
         $this->infoArray['error'] = 'invalid or unsupported psd';
         return false;
      }
   }


   function getImage() {
      // decompress image data if required
      switch($this->infoArray['compressionType']) {
         // case 2:, case 3: zip not supported yet..
         case 1:
            // packed bits
            $this->infoArray['scanLinesByteCounts'] = array();
            for ($i=0; $i<($this->infoArray['rows']*$this->infoArray['channels']); $i++) $this->infoArray['scanLinesByteCounts'][] = $this->_getInteger(2);
            $this->tempFileName = tempnam(realpath('/tmp'),'decompressedImageData');
            $tfp = fopen($this->tempFileName,'wb');
            foreach ($this->infoArray['scanLinesByteCounts'] as $scanLinesByteCount) {
               fwrite($tfp,$this->_getPackedBitsDecoded(fread($this->fp,$scanLinesByteCount)));
            }
            fclose($tfp);
            fclose($this->fp);
            $this->fp = fopen($this->tempFileName,'r');
         default:
            // continue with current file handle;
            break;
      }

      // let's write pixel by pixel....
      $image = imagecreatetruecolor($this->infoArray['columns'],$this->infoArray['rows']);

      for ($rowPointer = 0; ($rowPointer < $this->infoArray['rows']); $rowPointer++) {
         for ($columnPointer = 0; ($columnPointer < $this->infoArray['columns']); $columnPointer++) {
            /*    The color mode of the file. Supported values are: Bitmap=0;
               Grayscale=1; Indexed=2; RGB=3; CMYK=4; Multichannel=7;
               Duotone=8; Lab=9.
            */
            switch ($this->infoArray['colorMode']) {
               case 2: // indexed... info should be able to extract from color mode data section. not implemented yet, so is grayscale
                  exit;
                  break;
               case 0:
                  // bit by bit
                  if ($columnPointer == 0) $bitPointer = 0;
                  if ($bitPointer==0) $currentByteBits = str_pad(base_convert(bin2hex(fread($this->fp,1)), 16, 2),8,'0',STR_PAD_LEFT);
                  $r = $g = $b = (($currentByteBits[$bitPointer]=='1')?0:255);
                  $bitPointer++;
                  if ($bitPointer==8) $bitPointer = 0;
                  break;

               case 1:
               case 8: // 8 is indexed with 1 color..., so grayscale
                  $r = $g = $b = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  break;

               case 4: // CMYK
                  $c = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  $currentPointerPos = ftell($this->fp);
                  fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                  $m = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                  $y = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                  $k = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  fseek($this->fp,$currentPointerPos);
                  $r = round(($c * $k) / (pow(2,$this->infoArray['colorDepth'])-1));
                  $g = round(($m * $k) / (pow(2,$this->infoArray['colorDepth'])-1));
                  $b = round(($y * $k) / (pow(2,$this->infoArray['colorDepth'])-1));

                    break;

                    case 9: // hunter Lab
                       // i still need an understandable lab2rgb convert algorithm... if you have one, please let me know!
                     $l = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                     $currentPointerPos = ftell($this->fp);
                     fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                     $a = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                     fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                     $b =  $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                     fseek($this->fp,$currentPointerPos);

                     $r = $l;
                     $g = $a;
                     $b = $b;

                  break;
               default:
                  $r = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  $currentPointerPos = ftell($this->fp);
                  fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                  $g = $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  fseek($this->fp,$this->colorBytesLength-1,SEEK_CUR);
                  $b =  $this->_getInteger($this->infoArray['oneColorChannelPixelBytes']);
                  fseek($this->fp,$currentPointerPos);
                  break;

            }

            if (($this->infoArray['oneColorChannelPixelBytes']==2)) {
               $r = $r >> 8;
               $g = $g >> 8;
               $b = $b >> 8;
            } elseif (($this->infoArray['oneColorChannelPixelBytes']==4)) {
               $r = $r >> 24;
               $g = $g >> 24;
               $b = $b >> 24;
            }

            $pixelColor = imagecolorallocate($image,$r,$g,$b);
            imagesetpixel($image,$columnPointer,$rowPointer,$pixelColor);
         }
      }
      fclose($this->fp);
      if (isset($this->tempFileName)) unlink($this->tempFileName);
      return $image;
   }

   /**
    *
    * PRIVATE FUNCTIONS
    *
    */

   function _getPackedBitsDecoded($string) {
      /*
      The PackBits algorithm will precede a block of data with a one byte header n, where n is interpreted as follows:
      n Meaning
      0 to 127 Copy the next n + 1 symbols verbatim
      -127 to -1 Repeat the next symbol 1 - n times
      -128 Do nothing

      Decoding:
      Step 1. Read the block header (n).
      Step 2. If the header is an EOF exit.
      Step 3. If n is non-negative, copy the next n + 1 symbols to the output stream and go to step 1.
      Step 4. If n is negative, write 1 - n copies of the next symbol to the output stream and go to step 1.

      */

      $stringPointer = 0;
      $returnString = '';

      while (1) {
         if (isset($string[$stringPointer])) $headerByteValue = $this->_unsignedToSigned(hexdec(bin2hex($string[$stringPointer])),1);
         else return $returnString;
         $stringPointer++;

         if ($headerByteValue >= 0) {
            for ($i=0; $i <= $headerByteValue; $i++) {
               $returnString .= $string[$stringPointer];
               $stringPointer++;
            }
         } else {
            if ($headerByteValue != -128) {
               $copyByte = $string[$stringPointer];
               $stringPointer++;

               for ($i=0; $i < (1-$headerByteValue); $i++) {
                  $returnString .= $copyByte;
               }
            }
         }
      }
   }

   function _unsignedToSigned($int,$byteSize=1) {
      switch($byteSize) {
         case 1:
            if ($int<128) return $int;
            else return -256+$int;
            break;

         case 2:
            if ($int<32768) return $int;
            else return -65536+$int;

         case 4:
            if ($int<2147483648) return $int;
            else return -4294967296+$int;

         default:
            return $int;
      }
   }

   function _hexReverse($hex) {
      $output = '';
      if (strlen($hex)%2) return false;
      for ($pointer = strlen($hex);$pointer>=0;$pointer-=2) $output .= substr($hex,$pointer,2);
      return $output;
   }

   function _getInteger($byteCount=1) {
      switch ($byteCount) {
         case 4:
            // for some strange reason this is still broken...
            return @reset(unpack('N',fread($this->fp,4)));
            break;

         case 2:
            return @reset(unpack('n',fread($this->fp,2)));
            break;

         default:
            return hexdec($this->_hexReverse(bin2hex(fread($this->fp,$byteCount))));
      }
   }
}

/**
* Returns an image identifier representing the image obtained from the given filename, using only GD, returns an empty string on failure
*
* @param string $fileName
* @return image identifier
*/

function imagecreatefrompsd($fileName) {
   $psdReader = new PhpPsdReader($fileName);
   if (isset($psdReader->infoArray['error'])) return '';
   else return $psdReader->getImage();
}
?>


Hope it helps
PHPSEEKER.ORG Moderator
toshio
Site Admin
 
Posts: 34
Joined: Sat Dec 13, 2008 8:22 pm

Return to AS3 / Flex to PDF using PHP ::: How to

Who is online

Users browsing this forum: No registered users and 1 guest

cron