|
导读Adobe Photoshop,简称“PS”,是由Adobe Systems开发和发行的图像处理软件。Photoshop主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具,可以有效地进行图片... Adobe Photoshop,简称“PS”,是由Adobe Systems开发和发行的图像处理软件。Photoshop主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具,可以有效地进行图片编辑工作。ps有很多功能,在图像、图形、文字、视频、出版等各方面都有涉及。 Photoshop是数字图像处理领域内的杰出软件。同时,它也允许第三方以插件(Plugin) 的形式扩展其功能。Photoshop的插件目前一共可分为以下九种:自动化(批处理)(出现在‘自动’子菜单下),颜色拾取,导入,导出(出现在‘导入’‘导出’子菜单下),扩展,滤镜,文件格式(出现在打开,存储为),解析(与导出导出功能),选取(出现在‘选择’菜单下)。这里我们以最为用户熟悉的滤镜为例讲解。(一)插件的通用部分介绍: 调用插件的主程序我们成为宿主,在大多数情况下就是Photoshop(以下简称PS),一个插件实际上在windows系统下是一个动态链接库(只是具有不同扩展名)。PS使用LoadLibray加载插件模块。当用户采取相应操作时,将引起一系列ps对插件模块的调用。所有的这些调用都是调用同一个入口点。该入口点是这样一个函数,定义如下:(由于PS采取对windows和苹果机兼容,这里我们只给出在windows系统上的定义) void ENTRYPOINT ( short selector, void* pluginParamBlock, long* pluginData, short* result); selector: 操作类型指示符。当seletor=0时,它对所有类型的插件都具有相同的意义,即要求显示一个关于对话框。其他值,则根据插件类型而意义有所不同。 pluginParamBlock: 这是一个指向一个很大结构的指针,这个结构用于在宿主和插件之间传递信息和数据。对于不同类型插件,它具有不同结构。 pluginData: 一个指向int32类型的指针。它是为PS为插件在多次调用期间保存的一个值。它的一个标准用法是插件可把一些全局数据的指针交给该参数保存, result: 一个指向int16的指针,每次插件被调用它必须设置result。返回0表示插件代码中没有发生错误。当发生错误时,这个值返回一个错误码。有关错误码,ps为不同类型的插件分别划分了错误码的范围,并在SDK中预定义了一些值。 关于对话框: 所有插件应该响应about调用。插件可以显示一个自定义的对话框。但是为了保持一致性,应该遵守下面的约定: (1)显示在主屏幕的水平居中,垂直1/3高度处。 (2)不需要包含一个OK按钮,而是响应在任意位置的点击以及回车键。 (二)滤镜插件的介绍 滤镜插件的作用是,针对图像的选择区域做出修改。滤镜行为从调节饱和度,亮度,到对图像的滤波等等。滤镜在windows下的扩展名是“.8BF”。 下图显示了PS和滤镜插件之间的调用序列,非常重要,这是在SDK文档中的一个图片,对每一个类型的插件都有这样一幅图,这里显示的是滤镜插件的调用序列。 ![]() 滤镜可以使用滤镜菜单进行调用,即最上面的调用起始点。在调用一次以后,Photoshop将把最近一次滤镜操作放到滤镜菜单的“最近一次滤镜”子菜单上,以后点击该菜单则对应上图中的“最近一次滤镜命令”。下面我们将简要介绍上图流程。首先我们看一个滤镜的入口点函数的“模板”: EntryPoint Of Plugin :PlugInMain 注意,上面这个函数就是我们的滤镜的最重要的一个函数,因为这个函数是提供给PS调用的,我们可以看到这个函数声明为了一个Dll导出函数。从调用序列可以看到,这个机制使得这个函数的作用和 窗口的窗口过程 非常类似。窗口过程用于根据MSG ID处理消息,而这个函数主要用于根据selector做相应操作。因此他们都是有包含一个switch-case分支处理结构。 advanceState回调示例 inRect, outRect & maskRect 设置inRect 和 outRect (当使用选区蒙版时设置maskRect),以请求第一个处理区域。如果可能,你应该把图片切成小片,这样可以减少传递数据时的内存需求量。使用 64x64 或者128x128 的贴片是一个比较习惯性的做法。 (3.4)filterSelectorContinue调用: 当inRect, outRect, maskRect之中的任一个不是空矩形时,该调用会持续发生。 inData, outData & maskData 这三个成员都是void *指针,指向你请求的图像数据起始点,我们最主要的工作就是计算,然后设置这里的数据,在调用时,inData和outData会根据你请求的矩形区域被相应位置的图像数据填充,然后你的处理任务主要是修改outData数据区,告诉PS你的处理结果,PS会把结果更新到图像。注意,你不需要考虑传递进来的选区和选区形状,因为这个工作PS会自动保护选区外的数据,你只需要关注你自己的算法即可。处理结束后,设置下一次处理的inRect,outRect。如果结束了,那么把它们置空即可。注意,inRect不一定和outRect是一样的。 progressProc 回调:(用于设置PS进度条) 它的类型定义为: typedef MACPASCAL void (*ProgressProc) (int32 done, int32 total); 这是PS提供的用于设置进度条的回调函数,插件可以使用这个回调让PS更新下面的进度条,它接收两个参数,一个是已经完成的任务数,一个是总任务数。当你需要想用户反馈你的处理进度,则可以这样设置进度: gFilterRecord->progressProc ( progress_complete, progress_total ); abortProc 回调:(用于向宿主查询用户是否采取了取消行为) 其类型定义为: typedef Boolean (*TestAbortProc) (void); 这个回调用于查询用户是否取消了操作,在一个消耗时间较长的处理中,插件应该每秒钟调用几次这个函数,确认用户是否做了取消(例如按下Esc键等)。如果返回TRUE说明当前的操作应该取消,并且返回一个正的错误码。 (3.5)filterSelectorFinish调用: 该调用允许插件在处理结束后做清理工作。当并且仅当start调用成功(没有返回错误)时,finish才会被调用。即使continue中发生错误,finish调用依然会发生。 注意!:小心处理用户在continue调用期间取消的行为,通常这时候你在期待下一次continue调用。如果用户取消,下一次调用将是finish调用,而不是continue!!!。 规则:如果start调用成功,Photoshop保证将会发起Finish调用。 (3.6)错误码 插件可以返回标准的操作系统错误码,或者报告它自己的错误(正整数)。在sdk中有定义: #define filterBadParameters –30100 // #define filterBadMode –30101 // 不支持该模式图片 (四)雨滴滤镜的DEMO 前面我们主要讲述了一个滤镜的基础知识。然后这还是仅仅提取了最重要的部分讲解的,更多的技术细节限于篇幅无法估计。上文的主要基础是PS SDK6.0的文档,其中的主要规则属于对原文的翻译,有少量内容属于我个人的实践和理解(我将在有时间的时候把属于个人理解的用颜色区分注明)。 现在我们才开始进入demo的讲解!!!真的很累。。。。 雨滴滤镜的算法主要参考了国外的一个网址,这是一个网友给我的另一篇文章的回复中报告给我的地址。这个滤镜的起源是球形化算法(在PS中有此内置滤镜)。算法我们不做介绍了,因为它虽然是滤镜的核心,但不是本文重点。我们给出在此基础上水滴效果的伪码: ---水滴效果-------------------- 随机产生一个位置cx,cy,随机产生一个半径R, 在cx,cy处以R为半径做球形化扭曲。 在该位置处加上水滴的高光和阴影。 对水滴内部做一个3*3模板的高斯模糊。 ---------------------------------- (4.1)像素定位 重复上述过程,将产生多个水滴。这就是这个滤镜的核心算法。具体公式不给出了。但是为了处理数据,我们必须了解如何在PS传递来的数据中定位一个像素数据,例如我们想获得原图上(x,y)位置上R通道的像素数据,我们如何拿到呢?这里还要介绍FilterRecord中和像素定位相关的重要数据成员, int32 inRowBytes ,outRowBytes, maskRowBytes, 这是相应的inData,outData,maskData中的扫描行宽度,都是int32类型,属于PS提供给插件的数据。在c#中相当于BitmapData.Stride。但是注意的是,在inData和outData中,数据未必是按照4byte对齐的!但是ps也没有说行尾就没有任何冗余字节。总之,它是一行图像数据在内存中的占据的字节数量(跨度)。 int16 inLoPlane, inHiPlane, outLoPlane, outHiPlane, 属于插件像PS请求时通知给PS的数据,值得是下一个处理中请求的第一个通道和最后一个通道值,注意这个值是以0为base的索引值。例如对于RGB图像来讲,有三个通道,0到2分别对应B,G,R(注意这里保持文件中顺序,而不是PS中的习惯的RGB顺序!!!)。我们可以一次请求一个通道,也可以一次请求多个通道,多个通道的数据将会依次交叉排布(interleave)。例如,如果我们设置inLoPlane=0,inHiPlane=2,则PS提供给我们的inData数据排列是: [B G R] [B G R] ... .... 如果我们把inLoPlane=inHiPlane=1,则PS提供给我们的inData是: [G] [G] ...... 好了有了上面的几个关键成员讲解,我们可以看到我们如何定位一个像素,其方式如下: 首先我们请求的通道数量设为planes:则: planes=inHiPlane-inLoPlane+1; //通道数量 uint8 *pixels=(uint8*)inData; 我们取到(x,y)位置的索引为k的通道数据表达式如下: pixels [ y * inRowBytes + x * planes + k ]; 或者 *(pixels + y * inRowBytes + x * planes + k); 例如,我们请求了一副图片的RGB三个通道(inLoPlane=0,inHiPlane=2),为简便,inRect设置为整个图片大小,则位于(x,y)位置的像素数据如下: pixels [ y * inRowBytes + x * 3 ]; // p(x,y).B pixels [ y * inRowBytes + x * 3 + 1 ]; // p(x,y).G pixels [ y * inRowBytes + x * 3 + 2 ]; // p(x,y).R 好了,有了上面的基础,我们可以看下面的高斯3*3模板处理,高斯3*3模板如下: 1 2 1 2 4 2 /16 1 2 1 我们使用上面的像素定位方式,可以很容易写出下面的循环处理中的内容: 高斯模糊(3*3模板)
更多对Photoshop第三方滤镜插件开发的简介相关文章请关注PHP中文网! Photoshop默认保存的文件格式,可以保留所有有图层、色版、通道、蒙版、路径、未栅格化文字以及图层样式等。 |
温馨提示:喜欢本站的话,请收藏一下本站!