4images Forum & Community

4images Modifications / Modifikationen => Mods & Plugins (Requests & Discussions) => Topic started by: Sunny C. on December 04, 2013, 03:09:44 AM

Title: PSD in 4images anzeigen
Post by: Sunny C. on December 04, 2013, 03:09:44 AM
Hallo zusammen,

ich würde gerne auch PSD-Dateien als Bild ausgeben und anzeigen lassen.
Ich habe dazu eine php-class gefunden, welche die PSD als JPG ausgibt
<?php
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();
}
header("Content-type: image/jpeg");
print imagejpeg(imagecreatefrompsd('PATH-TO-FILE.PSD'));
?>

Wie kann man das umsetzen?

Ich habe nun versucht die Klasse und die functionen zu separieren:
psdtojpg.php (includes ordner)
<?php
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();
} ?>
template/.../media/psd.html
<?php
include_once('includes/psdtojpg.php')
header("Content-type: image/jpeg");
print imagejpeg(imagecreatefrompsd('{media_src}'));
?>
Funktioniert nicht.... hat da jemand eine Idee