faww |
2008-08-30 17:06 |
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。
|
|