psd 解析 java_php读取psd文件格式解析

/* 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('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; $iinfoArray['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();

}

?>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值