对于PSD文件的读取,国外已经有很多源代码可以下载,而且效率还不错,但对于PSD图层的读取,在下颇为少见,所有决心自己写一个,希望能为广大吃苦耐劳的写程序的人民出点棉力....

首先必须说明一下,PSD文件的图像储存方式和一般的Pic图或者Bitmap图极为不同,它不是以Pixel (象素点) 作为储存标准,而是以Channel (通道)作为储存的标准,例如PSD图为RGB格式时,其Channel 为 Mask  Red  Green  Blue 4个,因为在下的源代码只是涉及到RGB的PSD图片,所以本文主要讲述如何读取RGB格式的PSD图片的各个图层.

宰牛必先磨刀.说到文件格式这样东西,就必须去下载个说明文档回来看看..
大家可以到http://www.moon-soft.com/program/FORMAT/ 找找,里面有很多不同文件格式的说明,当然也包括<<Photoshop 4.0文件.PSD文件格式的英文说明书>>.

好了,现在有说明书了,但有个遗憾是En文版的,看是能看,但是如果有个源代码对比会不会好点.嗯….去 codeproject 搜一下..
http://www.codeproject.com/bitmap/MyPSD.asp ihaml先生的读取PSD文件图片的源代码,在下个人认为ihaml写得已经很明确,而且MyPSD::CPSD类也已经比较完善,遗憾得是有些图还是会出错,但已经没关系了,可以着手动工了.

打开我们刚才下载回来得说明文档,找下第二章Document file formats ,去到
Photoshop3.0 file format 你会看到一下图表 (图1)..

   (图1)

这说明了PSD文件的总结构.这里在下简单说明一下.

File Header:
为定长结构,24bytes,陈述了图片的标记,Channel数目,Rows图片高度(Pixel为单位),Columns图片宽度 (Pixel为单位),Depth图片深度,则每个Channel有多少bits,还有的就是Mode..注意,Mode为3的时候是RGB图,如果阁下的图片不是Mode=3,那么本说明文的源代码就处理不了阁下的图片了.

我们再看看其他的结构,都是变长结构,但幸运的是,每个结构的前4个byte都说明了该结构的长度,这让我们很容易的跳过其中一个结构,了解下一个结构.
 
图2

现在我们再回看图1.在下发现, Color Mode Data结构和Image Resources结构对读取RGB模式的图层是没有什么实际用途的.说明一下, Color Mode Data结构只有当图像模式为Indexed和Duotone时(Mode=2或者Mode=8)才有内容,否则只是为4Bytes的零值.我认为这个结构应该是给图片提供一个索引的颜色值,类似于调色板的用途,由于没有认真考证过,希望这个猜测是对的.而Image Resources结构是储存文件相关的信息,例如Photoshop版本号,文件路径,颜色的Function等等..

好了,到目前为止,我们认为File Header和Layer and Mask Information是对我们有用的,至于Image Data结构,储存的是生成后的图像信息,也就是说通过各种效果,各种处理后的图像,我们在这里可以看到.这一部分的图像读取, ihaml先生已经做得很好,建议去http://www.codeproject.com/bitmap/MyPSD.asp下载他得源代码分析.

好了,我们最后的,也是最艰巨的任务就是分析Layer and Mask Information结构.

现在我们必须从说明文档中的Table2-10 (Layer and Mask Information) 着手.
下图 (图3) 为在下分解后得到的部分结构层次分析.

图3

当然并不是所有的信息都是有用的,我们只是用到部分结构里面的部分信息,为了统一起见,我把该用到的信息列一下:

(需要说明的是,原说明文档有一处地方是错的,Table 2-13里面的变长结构Layer应该指向的是Table2-14,不是Table2-18,请大家注意)

1.Table2-13里面的Count,让我们知道总共有多少个Layer,如果取到的值小于零,用该值的绝对值.然后通过这个数值循环下面的Table2-14(Layer Records)的读取,有多少个Layer就读取多少遍该结构.
2.Table2-14里面,Layer的Top,Bottom,Left,Right属性.
3. Table2-14里面,Layer的NumberOfChannels,找到我们的Layer里面包含的Channel数.
4.Table2-14里面,Channel Length Info (详见Table2-15),找到该Channel里面含数据的长度.
Ok,暂停一下,我们发现以上4个条款说明了一个道理,先循环Layer Count来找到每个Layer的信息,然后循环Layer信息里面的Channel数来找到每个Channel的长度信息.如图(图4)


图4

接下来继续..

5.Table2-14里面,Blend Mode Signature 和 Blend Mode Key.通过这两个属性来对应一下,判断我们读取到的结构到底对不对, Blend Mode Signature必须为"8BIM",而Blend Mode Key为Table2-14里面列表内属性的一种.

6.Table2-14里面,Extra Data Size,表明了这个结构以下4个结构的总长度.跳过这个长度,我们就可以获得下个Layer Record结构的信息了,当然,如果把全部的Layer Record信息都读完了,那以下的便是我们所十分需要的Channel Image Data结构了,那便是我们储存Channel图像的地方了....如图5

图5

实行以上6个条款,是我们要取得Channel Image Data的必要条件.

现在再用VB的调试窗口看看我们我们取得的成果.如图6

图6

好了,现在我们只是完成需要做的事情的一小半,Now,我们应该开始读取Channel Image Data结构了.
在这之前,我们必须说明一下Channel Image Data结构(Table2-18).每个Channel Image Data都是以Compression(压缩)属性开始,该属性指明以下Image Data信息的数据是否被压缩,0为不压缩,1为压缩.接着就是具体的象素数据.那么我们需要读取的Image Data长度是多少,还有就是要读取多少个Channel Image Data结构呢!呵呵,我们原来
通过第3条款和第4条款得到的NumberOfChannels和Channel Length Info就有用了.

做个例子吧,一个标准的RGB模式PSD图,里面有3个Layer,由于每个Layer拥有4个Channel(Mask Red Green Blue),则我们要读3*4=12个Channel Image Data结构,如图7

图7

我们再一次用VB的调试窗口说明下问题吧.
 
图8

好了,我们已经很成功的得到Layer Image Data的数据了,包括每个Channel的Compression属性和象素具体的Buffer.那我们接着就是要把每个Layer 的Channel数据投放 (转换) 到Layer 的 RGB象素形式…
因为在VB里面没有实际的指针概念,所以我们还必须借用以下的自定义Type.

Private Type COLOR
    R As Integer   '0~255
    G As Integer
    B As Integer
End Type

Private Type IMAGE_DATA
    nWidth As Long
    nHeight As Long
    pixlData() As COLOR
End Type

如果要转换,我们就必须了解Table2-18里面的Image Data是怎样储存的.
首先是Compression=0,象素数据没有压缩的情况.
在这种情况下, Image Data储存区是以Layer的Top-Left 到 Bottom-Right的顺序,储存每个象素点的当前Channel值,每点值占1个byte.我们要做的是把Layer里面R G B的channle信息分别读取到 IMAGE_DATA结构的RGB值内..

'转换图层Channel Red的数据
If Layer_image_data(图层号).cData(1).Compression=0 Tthen
For 象素号=0 Tto 图片象素
IMAGE_DATA.pixlData(象素号).R = Layer_image_data(图层号).cData(1).Data(象素号)
Next 象素号
End If

'转换图层Channel Green的数据
If Layer_image_data(图层号).cData(2).Compression=0 Tthen
For 象素号=0 Tto 图片象素
IMAGE_DATA.pixlData(象素号).G = Layer_image_data(图层号).cData(2).Data(象素号)
Next 象素号
End If

………
……

我们再用图片说明一下把,如图9

图9

Ok,接下来我们要处理最麻烦的, Compression=1,象素数据压缩的情况.

在这种情况下, Image Data首先是 以(Layer.Bottom-Layer-Top)*2个Byte为开头,则(Layer.Height*2)Bytes,保存的是图片每一行(Columns)占用的数据长度大小.接下来的就是以2个Byte块为单位,表示Channel值在图片里有效长度(Pixel)和当前Channel值,这样以块为单位一直顺序循环下来,直到,Channel Image Data结构结束.
例如,现在有个4pixel*2 pixel的图层,图层的Channel Image Data结构如下.

我们在程序里面定义了nLen(Layer.nHeight - 1) as Long 变量表示每一行占用的字节长度,根据这个长度量顺序读取Channel值的有效象素长度和Channel值,然后转换到相对的RGB Image Data里面.

'cData(1)表示我们现在要读的是Channel R的数据
        If m_layer_image_data(countLayer).cData(1).Compression = 1 Then
            ReDim nLen(m_image_data.nHeight - 1)
            nPos = 0  '当前Buffer的地址
            '取得每行图像占用的字节长度
            For i = 0 To m_image_data.nHeight - 1
                nLen(i) = m_layer_image_data(countLayer).cData(1).Data(0 + nPos) * 256
+ m_layer_image_data(countLayer).cData(1).Data(1 + nPos)
                nPos = nPos + 2
            Next i
           
            For nLineCount = 0 To UBound(nLen)
                nBeginPos = nPos
                '读取RLE Data,并分解到每个R Buffer里面
                While nPos < nBeginPos + nLen(nLineCount)
                    '读取第一个字节,看看Channel的有效象素长度
                    nLenEx = m_layer_image_data(countLayer).cData(1).Data(nPos)
                    nPos = nPos + 1
                    If nLenEx = 128 Then
                        '当这个有效长度值为128时,不做任何事
                    ElseIf nLenEx < 128 Then
                        '当这个有效长度值<128时,实际值为nLenEx+1
                        '这时,Image Data结构后nLenEx+1个Byte表示的都是Channel值,他们分别对应
                        '图像后nLenEx+1个象素的R值
                        nLenEx = nLenEx + 1
                        For i = 0 To nLenEx - 1
                            m_image_data.pixlData(nPixlCount).R = m_layer_image_data(countLayer).cData(1).Data(nPos)
                            nPixlCount = nPixlCount + 1
                            nPos = nPos + 1
                        Next i
                    ElseIf nLenEx > 128 Then
                        '当这个有效长度值>128时,实际值为255 - nLenEx + 2
                        '这时,把下一个Byte表示的Channel值,赋值到图像后255 - nLenEx + 2个象素的
                        'R值里面
                        nLenEx = 255 - nLenEx + 2
                        For i = 0 To nLenEx - 1
                            m_image_data.pixlData(nPixlCount).R = m_layer_image_data(countLayer).cData(1).Data(nPos)
                            nPixlCount = nPixlCount + 1
                        Next i
                        nPos = nPos + 1
                    End If
                Wend
            Next nLineCount
        End If

我们按照这个步骤,分别把 RGB的值都得到, Type IMAGE_DATA里面,最后用SetPixel API画到PictureBox里面.

需要记得的是,nLenEx要分成3个不同逻辑来处理(>128, <128, =128),至于为什么这样,我也不是很清楚,在下也是按照ihaml先生给出的源代码分析得到的,如果阁下想了解详细的资料,可以参考下TIFF和Macintosh ROM的资料.

在下的源码里面还有很多应该判断的的逻辑都没有写上去,包括Mask Channel的应用,Channel Image Data的预定义值为白色等…..

好了,大家可以到 http://www.ubekar.com/downloads/PSD_LayerReader.rar  下载在下的Demo源代码.

补充一点,在下之所以用VB来写Demo,是因为VB可以快速的做Buffer调试,虽然VB里面没有纯属的指针,对于Buffer的拷贝处理会比较慢,但调试和编译都比VC要快,所以大家可以尝试在做Demo时候使用比较简单的构造方式,例如VB….

如果大家对PSD的读取分析有其他见解,或者对本代码做了有效的修改或加强,又或者通过本文的某些信息编写出了更好的Demo,请告知在下,如果能附上源代码,在下无甚感激,在下养了只猫Xeden3@Hotmail.Com.

又或者阁下在编写的时候有什么疑问,也可以发Email给在下.

谢谢各位

Xeden 2005-9

如何读取PSD文件(photoshop)的图层......相关推荐

  1. 怎样把一个PSD文件里的图层移到另一个PSD文件里

    你可以先打开两个PSD文件,然后进入你想要复制图层的那个PSD文件,选中你想要的图层,右击,复制(注意,是右击图层的空白部分,不是它的图标),然后会弹出一个对话框,你下拉菜单,然后你选择另一个PSD文 ...

  2. PS打开PSD文档服务器未响应,优化你的 PSD 文件防止 Photoshop 崩溃卡死 - 文章教程...

    大家可能都有这样的感觉,使用 Photoshop 做设计的时候,保存的 PSD 文件都很大,如果使用压缩文件压一下,会发现压缩率很高,这可能和 PSD 文件的算法有关,今天我们说的如何优化你的 PSD ...

  3. psd文件丢失了怎么恢复?分享原因及对应恢复方法

    PSD文件在设计行业中非常重要.但是,不幸的是,有时这些文件可能会因多种原因而丢失.那么在未备份PSD文件的情况下,PSD文件丢失了怎么恢复呢?如果您遇到了这种问题,不要惊慌,在本篇文章中,我们将根据 ...

  4. 批量导出 Photoshop 文字图层的文本的方法

    收到多个psd文件,文字图层多到不能直视,需要将里边的文字全部复制出来,网上找了一段脚本,挺好用,记录一下,感谢作者: #target photoshop/** filename: ps-save-l ...

  5. Sketch如何转psd文件?3种方法搞定它!

    Sketch 是一款广受设计师喜爱的设计工具,但是它并不支持 Windows 系统,这给部分设计师带来了一些麻烦.有时候,我们需要将 Sketch 文件转换为 PSD 格式文件,以满足某些特殊需求.虽 ...

  6. ps保存psd后图层全没了_明明只有几个图层,为什么我的 PSD 文件这么大?

    不知道有多少人被这个问题困扰过,总有那么几个 PSD 文件,明明只有几个图层而已,图层内均没有特别大的图片,但 PSD 文件却特别大,至少都比合理的大小超出几倍.而且在设计过程当中,保存时也会出现明显 ...

  7. js解析PSD文件,Java处理psd文件智能图层

    现在市面上很多的webapp都提供模板功能,所谓模板就是一系列元素的集合,模板的制作一般都需要设计师先在Photoshop等软件中制作好设计好,然后再一定的方式来还原设计稿,要么需要编码要么需要在某些 ...

  8. php编辑psd图层,psd文件怎么编辑

    psd文件怎么编辑? 1.首先下载Photoshop这款软件,下载之后打开.进入首页,点击菜单栏"文件"→"打开",开始打开你的PSD格式文件 2.选择好PSD ...

  9. 如何使用Photoshop在PSD文件上切图

    在前端或者后台的项目操作中都可能会用到切图,那么如何运用Photoshop在PSD文件上切图呢?拿到psd图本人常用一下两种情况,希望可以帮助到大家. 1.讲所有图层合并为一个完整的大图: 用Ctrl ...

最新文章

  1. Java中的深浅拷贝问题你清楚吗?
  2. SQLite 基本命令使用方式
  3. Xshell连接不上虚拟机Linux系统
  4. FPGA之道(9)BLOCK RAM以及DSP硬核
  5. Hacker's Browser
  6. 用java程序将GBK字符转成UTF-8编码格式(转)
  7. 【整理】ABAP 7.40新特性介绍(上)
  8. 征战蓝桥 —— 2014年第五届 —— C/C++A组第8题——地宫取宝
  9. base64 不一致_这几项超好用的云开发扩展能力,别说你还不知道!
  10. Java错别字检查_java中关于异常的处理
  11. ANSYS——相同模型不同创建方式的同载荷同约束下的比较
  12. 【渝粤题库】陕西师范大学202421 教育管理心理学 作业 (专升本)
  13. 叠加卡片列表_使用PowerBI制作卡片图
  14. java工作中mq应用多吗_RabbitMQ消息中间件在工作中的应用场景
  15. java.lang.ClassNotFoundException: com.sun.image.codec.jpeg.JPEGCodec
  16. 华中科技大计算机第八次基础作业,华中科技大计算机基础第三次作业.doc
  17. 用Excel和OutLook实现自动批量发邮件
  18. 仿QQ聊天界面里边的相册(QQ相册)
  19. 电脑怎么隐藏文件夹?6个步骤完成!
  20. 利用二进制位求平均值

热门文章

  1. 什么是JavaBean?
  2. 通过Python的speech_recognition库将音频文件转为文字
  3. 股票期货数据接口常见的代码介绍
  4. CT原理与技术 第2章 扫描成像系统
  5. Android bindService报错:has leaked ServiceConnection ***that was originally bound here
  6. 国内各地图API坐标系统比较
  7. python curl 保存文件_curl使用文档
  8. 猫狗分类代码,小白适宜
  9. vue之双向绑定与计算属性
  10. PHP环境搭建(phpStudy)与集成开发工具(phpStorm)的安装