切换到宽版
  • 3497阅读
  • 12回复

[图像处理]Photoshop 的插件及其实现 [复制链接]

上一主题 下一主题
离线faww

UID: 439291

 
发帖
95
金币
36
道行
5
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 44(小时)
注册时间: 2008-05-16
最后登录: 2014-07-01
只看楼主 倒序阅读 使用道具 楼主   发表于: 2008-08-30
— 本帖被 雅先生 执行加亮操作(2008-09-21) —
Photoshop 的插件及其实现


一、plug-in概述

1. plug-in结构
plug-in结构由两部分组成,一是插件(plug-in modules),二是宿主(plug-in hosts)。插件是Adobe或第三方开发者开发的、用以扩展标准Photoshop功能的软件模块,用户可以不需改动宿主的代码,而通过在系统中增加或升级插件以满足自己的需要。宿主则负责把插件载入内存并通过一定接口进行调用、协作,当插件功能完毕之后,将插件从内存中卸载。Adobe公司的其他产品,如Premiere、Illustrator、PageMaker等都是宿主,但是它们的plug-in结构各有不同,本文只讨论Photoshop宿主。
plug-in并非Photoshop所独有,许多应用程序都支持特定的插件,Silicon Beach便是一家最早支持plug-in技术的公司,它将插件设计为独立的文件,允许这些文件放置在任意的位置,并且它引入了版本号概念,当新功能增添到接口中时能实现平稳升级。Photoshop有些近似于这一方式,它利用了相似的调用过程和版本号策略,但随着Photoshop针对真彩色图像处理和虚拟内存管理的需要所做的工作,其插入结构不断被完善和发展,现在的具体接口已经和Silicon Beach的完全不同了。

2.插件类型
Photoshop支持以下四种插件:
Acquire modules(扩展名8ba)实现在一个新窗口中打开一幅图像,常用于扫描仪或视频捕捉卡接口,读取压缩格式或系统不支持的文件,通过Acquire子菜单调用。
Export modules(扩展名.8be)实现图像输出,常用于控制特殊打印机或以非标准压缩格式进行文件输出,通过Export子菜单调用。
Format modules(扩展名.8bi)实现标准读写系统不支持的特殊文件格式,出现在Open...、Save As...等对话框的格式栏中。
Filter modules(扩展名.8bf)实施对当前图像中的选定区域进行修改、润色。这是大家最熟悉的部分,许多图像效果便是出自这些模块,通过Filter菜单调用。
在Windows中,插件文件必须放置在特定的路径中(如\photoshop\plugins),这些路径由photos 30.ini中的PLUGIN DIRECTORY栏所指示。一个插件文件可包含一个或多个功能,但并不提倡创建多功能的插件文件,因为这样减少了插件的用户控制。然而,当一组功能紧密相关时,创建多功能的插件可以便于文件管理,弥补了前述不足,所以用户可按照具体情况编制插件。

3.插件的程序接口
宿主程序对插件的调用是对用户操作的响应。一般来说,执行一个用户命令会导致一系列宿主对插件的调用,所有这些调用都是通过插件的入口函数ENTRYPOINT()完成的。其结构如下:
void ENTRYPOINT(
short selector,
void * plugin ParamBlock,
long * pluginData,
short *result);
其中,selector参数指示宿主程序所要求的操作类型,selector=0时表示要显示一个About信息框。按照SDK的规定,此对话框必须放置在主窗口中央、不含OK按钮,但能够对回车键或在其中进行的鼠标点击作出响应。其他selector值在各种插件中有不同的定义。pluginParamBlock参数指向一个用于在宿主和插件之间来回传递信息的数据结构,这个结构随着插件类型的不同而改变。pluginData参数指向一个长整型,它是Photoshop为插件保留的固定区域,其典型的应用便是存储一个长句柄,指向一个插件的全局数据所占用的内存区,当插件第一次被调用时值为0。result参数指向一个短整型,每次当插件被调用时,它都必须设置result。当返回一个0值给宿主时,表示插件代码中没有错误出现;而当result为非0值时,则向宿主表明插件中发生了某些错误,或表明在插件的执行过程中用户取消了操作。
一个插件的主结构实际上是一个多向开关,它把pluginParamBlock、PluginData和result参数发送给各个selector所对应的句柄。下面是一个Filter module的入口代码:
void ENTRYPOINT(
  short selector,
  FilterRecord*filterParamBlock,
  long*data,short*result)
{
Globals globalValues;
GPtr globals=&globalValues;
gResult=noErr;
...
switch(selector){
  case filterSelector About:
    DoAbout(globals);break;
  case filterSelectorParameters;
    DoParameters(globals);break;
  case filterSelectorPrepare:
    DoPrepare(globals);break;
  case filterSelectorStart:
    DoStart(globals);break;
  case filterSelectorContinue:
    DoContinue(globals);break;
  case filterSelectorFinish:
    DoFinish(globals);break;
  default:
    gResult=filterBadParameters;
}
*result=gResult;
...
}

4.内存管理
多数情况下,当用户使用插件时,插件做出的第一个动作便是和Photoshop协商内存的利用问题。一开始,Photoshop将自己所占用但能释放给插件的最大内存字节数赋给插件plugin ParamBlock参数块的maxData域,然后插件根据情况减小这一数字,以获得足够内存加速自身运行。当内存不够时,为了给插件留出尽可能多的内存,Photoshop将所有当前打开的图像数据从内存转移到它的虚拟内存文件中,这样便可使插件全部在内存中运行,如果插件对内存要求很低(如它能将图像数据分片处理),则只需把maxData减小到特定的需求即可。
许多情况下插件只需要少量的内存,但是如果多提供些内存会运行得更快些,所以maxData值可以通过试验寻求一个均衡的最佳值。在实现插件的程序编写时,可采取两种策略:一是将maxData除以2,各分一半给Photoshop和插件,这种方式实现较方便,但是不够优化;二是先将maxData置为0,然后利用开发包提供的缓冲区和句柄回调函数包进行分配,这种方法最优,但是需要额外的编程,较复杂。如果需要特别考虑性能的话,开发人员可以通过大量测试来比较各种内存策略的优劣。

二、plug-in的编写

1.软件和硬件配置
Photoshop SDK提供了Macintosh和Windows两种版本,并提供了相应的转换工具,可以方便地创建跨平台插件,但是由于Photoshop最早是基于Macintosh的,残留了很多Mac风格,所以开发者在Windows下编写plug-in时,必须注意两种平台下数据结构和函数调用的不同。例如字节排列,数字65298在Intel处理器上排列为12FF,而在Motorola或PowerPC处理器上排列为FF12,开发者应严格区分。Photoshop plug-ins for Windows可以用Microsoft Visual C++ 2.0或更高的版本在Windows 95或Windows NT下开发。

2.创建Windows插件
SDK中为各种插件类型建立了相应的数据结构,如FilterRecord,FormatRecord,AcquireRecord,ExportRecord和AboutRecord等,这些结构在各自的头文件中有详细定义。
插件实际上是Windows的动态链接库(DLL),只是根据Photoshop的需要进行了特殊定制而跟普通DLL略有不同,因此,在插件中还应包含32位的动态链接库入口函数BOOL APIENTRY DLLInit(HANDLE,DWORD,LPVOID)。
当用户动作调用插件时,Photoshop执行LoadLibrary调用,将插件调入内存,对其中的所有PiPL(Plug-in Properties Lists)资源调用GetProcAddress(routineName),其中routineName和PIWin3286CodeProperty配合,可以得到子程序的地址。
在宿主通过插件的入口函数调用插件的同时,插件也可以通过其pluginParamBlock参数中的指针向宿主发出回调(callback),这些回调函数能为插件的某些特殊需要提供相应服务,是编写插件时不可缺少的一环。在SDK中回调函数分为两类:一类是direct callback,是直接在参数块中实现的代码,如Boolean(*testAbortProc)(),插件每秒钟应调用多次本函数以测试用户是否取消操作;另一类则归为callback suites,按其功能划分为Buffer suites,Handle suites,Property suites,Image Services suites,Pseudo-Resource suites等五组,如Handle suites中的Handle(*NewPIHandleProc)(int32 size),此函数负责分配一个指定大小的句柄,如果句柄分配不成功,则返回NULL。关于回调函数的详细内容,可以在SDK的PIGeneral.h头文件中参阅其定义。

三、过滤器插件(Filter Module)

过滤器是Photoshop的插件中最丰富的一类,它们从Filter菜单中调取,能对图像的选定区域进行各种修饰,从细微的色调变化到夸张的视觉效果,给设计人员提供了强有力的美术手段,所以我们以过滤器为例,介绍一下插件的具体内容。
下面是其中selector参数的说明:
1. filterSecectorParameters
如果过滤器插件要求用户设置参数,它应该提示用户输入,并且在一个内存区域的参数域中保存这些参数的句柄(当初次运行Photoshop时,这些参数域被设为NULL)。如果一个过滤器刚被运行过一次,用户可以通过选取Filter菜单下的Last Filter子菜单,重复运用相同的参数而不需要再次输入参数,在这种情况下,宿主程序就不调用filterSelectorParameters,用户也不会再看到提示输入的对话框。
2. filterSelectorPrepare
此调用允许插件调整上文所述的Photoshop内存分配算法,以提高整个系统的运行效率。其中imageSize,Planes,filterRect等域可以用于计算缓冲区的大小;bufferSpace可设置超过32K的内存块。
3. filterSelectorStart
在编写过滤器插件处理图像时,最好能将图像划分为若干个块进行操作,这样可以减少内存需求,一般情况下可分为64×64到128×128之间的方块。程序实现时应设置inRect、outRect和maskRect(如果用到了mask的话)去申请第一个图像块进行处理。
4. filterSelectorContinue
当开始进行第一个图像块的处理后,inRect、outRect和maskRect域不再为空,这样filterSelectorContinue便会被反复地调用,每次调用处理一个图像块,首先它处理由inData、outData和maskData所指向的数据,然后改变inRect、outRect和maskRect以申请下一个要处理的图像块,直到这些图像块都被处理完。
5. filterSelectorFinish
只要filterSelectorStart调用成功,Photoshop就会保证filterSelectorFinish被调用。当过滤器执行完毕时,此调用允许过滤器插件从内存中清除,并且只有在filterSelectorStart句柄未返回错误值的情况下才被调用。另外,在实现插件时,应随时处理用户的取消操作,一旦接收到消息就应当调用filterSelectorFinish而不是filterSelectorContinue,以及时结束插件的运行。
以上的句柄及过滤器插件参数块FilterRecord的详细定义可参见SDK提供的PIFilter.h头文件。
如果对深入了解Photoshop SDK有兴趣,读者可以联系Adobe公司的Adobe Developers Association,E-mail地址为acoven@adobe.com

1条评分
By 风火轮 金币 +8 | 理由: 鼓励一下 2008-08-30
 
离线r2r2r2

UID: 260273

精华: *
级别: *
发帖
*
金币
*
道行
*
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: (小时)
注册时间: *
最后登录: *
只看该作者 沙发   发表于: 2008-09-13
你发的帖子很有用!谢了!
山庄新手赚分攻略
 
离线xintianmm

UID: 724572

精华: 1
职务: 山庄囚徒
级别: 武当真人
发帖
206
金币
77
道行
81
原创
14
奖券
20
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 75(小时)
注册时间: 2009-09-12
最后登录: 2013-09-26
只看该作者 板凳   发表于: 2010-01-11
用户被禁言,该主题自动屏蔽!
山庄新手赚分攻略
 
离线sydxba

UID: 450696

发帖
120
金币
57
道行
10
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 23(小时)
注册时间: 2008-05-31
最后登录: 2013-06-22
只看该作者 地板   发表于: 2010-01-28
谢谢,知道了。支持一下
如何不发帖就快速得到金币道行
 
离线zooray

UID: 1155657

发帖
32
金币
72
道行
0
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 0(小时)
注册时间: 2011-04-02
最后登录: 2011-04-03
只看该作者 4楼  发表于: 2011-04-03
楼主好呀 来看看 顺便拉积分吧
如何不发帖就快速得到金币道行
 
离线山姆

UID: 988195

发帖
7758
金币
9970
道行
1610
原创
0
奖券
56
斑龄
0
道券
14
获奖
0
座驾
设备
摄影级
在线时间: 1179(小时)
注册时间: 2010-11-22
最后登录: 2015-08-05
只看该作者 5楼  发表于: 2011-04-04
楼主辛苦了,俺刚学习了一遍,回来再学习,挺管用的。
山庄新手赚分攻略
 
在线qqw77

UID: 1166215

发帖
371
金币
605
道行
140
原创
0
奖券
6
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 339(小时)
注册时间: 2011-04-12
最后登录: 2017-09-21
只看该作者 6楼  发表于: 2011-04-20
管用啊,没看懂啊,真是的,好好学吧。
山庄新手赚分攻略
 
离线jysir

UID: 1183448

发帖
506
金币
9
道行
26
原创
0
奖券
6
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 26(小时)
注册时间: 2011-04-28
最后登录: 2011-08-16
只看该作者 7楼  发表于: 2011-04-28
LZ辛苦了,谢谢
如何不发帖就快速得到金币道行
 
离线meng0505

UID: 643104

发帖
52
金币
1
道行
10
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
A6
设备
手机
摄影级
初级
在线时间: 26(小时)
注册时间: 2009-03-19
最后登录: 2017-06-18
只看该作者 8楼  发表于: 2011-06-17
好好学习!!!天天向上!!!
山庄新手赚分攻略
 
离线11aa99zz

UID: 242012

发帖
501
金币
3417
道行
123
原创
0
奖券
24
斑龄
0
道券
25
获奖
0
座驾
设备
摄影级
在线时间: 553(小时)
注册时间: 2007-07-09
最后登录: 2017-09-07
只看该作者 9楼  发表于: 2011-06-17
确实,我们PS的技术太肤浅了
如何不发帖就快速得到金币道行
 
离线ivanhyyy

UID: 1875128

发帖
259
金币
224
道行
18
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
卡片机
摄影级
在线时间: 35(小时)
注册时间: 2014-03-03
最后登录: 2014-03-24
只看该作者 10楼  发表于: 2014-03-21
有套插件不错值得推荐,叫镜皇。
有些插件感觉很粗糙,就像是用的动作。
如何不发帖就快速得到金币道行
 
离线dongjianwen

UID: 211322

发帖
551
金币
627
道行
38
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 120(小时)
注册时间: 2007-05-30
最后登录: 2017-09-20
只看该作者 11楼  发表于: 08-07
谢谢了,知道了,支持一下
如何不发帖就快速得到金币道行
 
离线dongjianwen

UID: 211322

发帖
551
金币
627
道行
38
原创
0
奖券
0
斑龄
0
道券
0
获奖
0
座驾
设备
摄影级
在线时间: 120(小时)
注册时间: 2007-05-30
最后登录: 2017-09-20
只看该作者 12楼  发表于: 08-17
理论上的东西学习一下
山庄新手赚分攻略
 
快速回复
限120 字节
认真回复加分,灌水扣分~
 
上一个 下一个
      你的浏览器不支持js脚本,无法发帖,请修改浏览器设置,支持js脚本并刷新页面后再发帖!