文档章节

php读取psd文件格式解析

大灰狼wow
 大灰狼wow
发布于 2016/10/31 23:08
字数 1123
阅读 240
收藏 2

psd文件格式解析 http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_75067 参考资料 http://www.kingsquare.nl/php-psd-reader

<?
/* 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; $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();
}
?>

© 著作权归作者所有

大灰狼wow
粉丝 48
博文 396
码字总数 49161
作品 1
嘉兴
程序员
私信 提问
PSD解析工具实现(二)

要想通过文件流的形式来解析psd文件,首先要了解psd的文件格式, adobe的开发者文档里面有着很详细的说明: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ 首先,总体来说是...

小姚
2016/03/23
547
0
使用phpexcel解析Excel数据表并存储到数据库中全过程_PHP_thinkphp_cmf

分享经验是为了让你少走弯路————华伟君 使用PHPExcel解析Excel数据表并存储到数据库中全过程 --- 第一部分:thinkphp中实例化上传类获取from表单提交的文件(非thinkPHP用户可以忽略,直...

尘世如潮
2016/06/17
664
1
纯 PHP 电子表格读写库--PhpSpreadsheet

PhpSpreadsheet 一个读取和写入电子表格文件的纯 PHP 库。允许您读取和写入不同的电子表格文件格式,如 Excel 和 LibreOffice Calc。 支持的文件格式 要求 PHP 5.5 以上版本 PHP 扩展 phpzip...

匿名
2016/12/27
1K
0
第一章:Photoshop基础

一、初始Photoshop 1.1 简介及功能 Photoshop是Adobe公司旗下最为出名的图像处理软件之一。它集图像、设计、合成、网页制作以及高品质图片输出功能为一体。从专业设计人员到家庭用户,Photo...

鲁雯雪
2015/01/22
134
1
PSD解析工具实现(一)

包括做游戏,我们做程序的很多时候都是需要跟psd打交道,那么如何对psd这个东西进行程序化操作就成为了我们提高工作效率的手段。 相信有研究过psd脚本的人都知道,psd的脚本是用js写的,大体...

小姚
2016/03/23
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

vue 2打包注意点

使用npm run build打包之后往往直接本地运行,路径类似这样:http://127.0.0.1:5500/xa/dist/index.html 或者http://127.0.0.1:5500/dist/index.html。然后页面打开是空白的,打开控制台查看...

牧云橙
26分钟前
4
0
归并排序

1.原理图 2.代码 public static void merge(int []a,int left,int mid,int right){ int []tmp=new int[a.length];//辅助数组 int p1=left,p2=mid+1,k=left;//p1、p2是检测......

wen123
30分钟前
4
0
css实现透明的两种方法

一、opacity:0~1 值越高,透明度越低: div{opacity:0.5 } 选择器匹配到的节点们,包括节点们的孩子节点,都会实现%50透明,另 0.5 可直接写成 .5 二、rgba(0~255,0~255,0~255,0~1) r...

Bing309
33分钟前
4
0
Tomcat 配置访问路径

此处只是部署完成后idea打开的默认路径,并非项目部署路径, 此处才是项目实际部署路径,可以有多个项目部署路径,idea可以配置默认打开一个

Aeroever
36分钟前
4
0
将ApiBoot Logging采集的日志上报到Admin

通过ApiBoot Logging可以将每一条请求的详细信息获取到,在分布式部署方式中,一个请求可能会经过多个服务,如果是每个服务都独立保存请求日志信息,我们没有办法做到统一的控制,而且还会存...

恒宇少年
36分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部