视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Photoshop滤镜开发简介--Photoshop回调函数
2020-11-27 14:49:44 责编:小采
文档
 在上一篇文章中,我们介绍了开发Photoshop滤镜插件最基本的一些概念和基础。Ps为了满足插件的应用需求,同时也给插件提供了大量的回调函数(或服务)。例如,滤镜可以在一次调用后,保存最近一次用户设置的参数,并应用到下次调用或显示UI。这就是通过Ps的回调函数完成的。这一篇文章我们将讲解最重要的一些Ps回调函数。了解本文之后,我们将能够使用回调函数,完成例如存储我们的滤镜参数等必要的工作。本篇文章将比第一篇复杂和深入的多,但同时从这篇文章我们也可以一窥PS内部的秘密:缜密的系统设计,完善的接口以及复杂的工作机制。

(一)回调函数的分类:
Ps的回调函数按照获取他们的位置可以被分为两种:
(1)Direct Callback:(可以直接调用的回调函数)
这些回调函数是FilterRecord的直接成员,可以从FilterRecord参数中直接获取。例如AdvanceStateProc(更新数据),TestAbortProc(测试用户取消)等,属于此类。
(2)Callback Suite:(回调函数集)
把函调函数按功能分类而提供的回调函数集,是一组回调函数组成的集合,它是一个指针,指向包含了一组回调函数的结构体(struct),我们可以从FilterRecord获取某个回调函数集,然后调用其中的函数。

当前提供的主要回调函数集有:
Buffer Suite:缓存内存管理(申请和释放缓存空间)。
UI Hook Suite:一组和UI操作有关的函数。
Channel Ports Suite:通道端口读写,用于读写PS内部的真正选区数据!而不是副本拷贝。
Descriptor Suite:描述符操作集,用于脚本记录系统,它本身又包含“读”“写”两个sub-suite(子函数集)。
Color Space Suite:颜色空间服务(颜色转换等)。
Handle Suite:句柄管理(PS封装的句柄和内存管理,和Buffer suite类似)。
Error Suite:接收和向用户显示错误信息(接收不同类型的错误信息字符串)。
GetFileList Suite:获取文件列表(获取文件,调用浏览器浏览网页等)。
GetPath Suite: 获取路径。
ZString Suite:封装字符串处理。

例如UI Hook Suite,提供了一组和UI有关的回调函数。它的第一版本被定义为:

UI Hooks Suite Version1

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.gxlcms.com/

-->#define kPSUIHooksSuiteVersion1 1 // suite版本
typedef struct
{
ProcessEventProc processEvent;
DisplayPixelsProc displayPixels;
ProgressProc progressBar;
TestAbortProc testAbort;
MainAppWindowProc MainAppWindow;
HostSetCursorProc SetCursor;
HostTickCountProc TickCount;
PluginNameProc GetPluginName;
} PSUIHooksSuite1;


请注意,有些回调函数即属于直接回调,又被存储到某个suite中,例如testAbout和displayPixels。我推测,在早期这些函数指针都被添加到FilterRecord中,但随着升级,添加的回调函数越来越多,这样就会使FilterRecord不断升级和增加成员,使维护困难,所以Adobe开始把回调函数归类,分为几种Suite,而只把suite放到FilterRecord中,这样添加函数时只要添加到相应的suite,并升级该suite即可,而不影响FilterRecord。这样早期的一些回调函数,就同时位于两个位置,FilterRecord和其所属的suite中,导致他们即可以直接调用,也可以通过相应的suite来调用。

(二)Suite PEA (插件函数集管理模块(层),我翻译的名字,有待商讨)
Suite PEA是一些Adobe系列软件使用的插件体系,它为宿主程序提供了通用的插件管理核心层,并为插件提供了一个标准接口。
和直接调用略有区别的是,函数集应该在使用前,先进行获取请求(Acquired),在使用后释放(release)suite。
一个获取的函数集本质上是一个结构体指针,指向一个包含了一组函数指针的结构,因此我们调用某个函数时候的形式如下:
sSuite->function();

因此调用一个回调函数集中的函数,形式如下:

Suite的获取和释放

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.gxlcms.com/

-->ADMBasicSuite *sADMBasic;

//获取ADMBasic Suite:
filterParamBlock->sSPBasic->AcquireSuite(
kADMBasicSuite,
kADMBasicSuiteVersion,
&sADMBasic );

//调用
sADMBasic->Beep( );

//释放
filterParamBlock->sSPBasic->ReleaseSuite(
kADMBasicSuite,
kADMBasicSuiteVersion );


(三)一部分比较重要的回调函数简介

下面我们将介绍一些我认为对于滤镜插件比较重要的回调函数。简单介绍这些回调函数的位置和使用方法。
3.1 DisplayPixelsProc( )
功能:在指定的DC上在指定位置输出像素数据(绘制图片)。(当然这个功能实际上我们也可以自己来完成。)
位置:Direct Callback, UI Hook Suite;
定义:
OSErr (*DisplayPixelsProc) (const PSPixelMap *source,
const VRect *srcRect, int32 dstRow, int32 dstCol,
unsigned32 platformContext);
参数说明:
source:第一个参数是一个描述像素信息的结构(PSPixelMap)的指针,它定义如下:

PSPixelMap Struct Define

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.gxlcms.com/

-->typedef struct PSPixelMap
{
int32 version; //版本号
VRect bounds; //边界
int32 imageMode; //模式
int32 rowBytes; //扫描行宽度
int32 colBytes; //列字节数
int32 planeBytes; //每通道字节数
void *baseAddr; //像素数据起始地址
//--------------------
// 省略..
} PSPixelMap;

srcRect:源矩形(源图的复制范围)
dstRow, dstCol:目标起始点坐标(左上角),因为不拉伸绘制,所以只要左上角坐标就够了。
platformContext:在Windows系统下,即device context(DC);

3.2 Descriptor suite(描述符函数集)
描述符集主要是用于ps的脚本系统的,它用于记录(录制)一系列PS中的动作过程中需要的信息和参数,并能够回放。它有分为“读”和“写”两个子函数集。我们可以使用这个函数集,使ps的脚本系统“获知”我们的滤镜并能够记录到某个动作序列中。
获取方式是先通过FilterRecord得到PIDescriptorParameters:

PIDescriptorParameters Struct Define

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.gxlcms.com/

-->typedef struct PIDescriptorParameters
{
int16 descriptorParametersVersion; //版本号
int16 playInfo; //动作播放标识:0-对话框可选;1-需要对话框;2-无对话框;
int16 recordInfo; //动作录制标识:0-对话框不显示;1-对话框显示;2-对话框静寂;
PIDescriptorHandle descriptor; //描述符的句柄,非常重要,我们将用它读写数据!
WriteDescriptorProcs* writeDescriptorProcs; //“写”子函数集
ReadDescriptorProcs* readDescriptorProcs; //“读”子函数集
} PIDescriptorParameters;

然后我们就可以获得“读”或者“写”子函数集:

获取“读”和“写” sub-suite

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.gxlcms.com/

-->//获得描述符参数结构:
PIDescriptorParameters* descParams = gFilterRecord->descriptorParameters;
if (descParams == NULL) return err;

//获得“读”子函数集:
ReadDescriptorProcs* readProcs = gFilterRecord->descriptorParameters->readDescriptorProcs;
if (readProcs == NULL) return err;

//获得“写”子函数集:
WriteDescriptorProcs* writeProcs = gFilterRecord->descriptorParameters->writeDescriptorProcs;
if (writeProcs == NULL) return err;


获取了两个子函数集,我们就可以调用相应子函数集下面的函数进行“读”“写”我们的参数了。两个子函数集的使用和注册表操作类似,我们在进行读写前,首先需要打开相应描述符。因此我们先介绍打开和关闭描述符操作。
OpenReadDescriptorProc( ):打开一个“读”描述符
定义:
PIReadDescriptor (*OpenReadDescriptorProc) (PIDescriptorHandle, DescriptorKeyIDArray);
参数说明:
PIDescriptorHandle:
描述符句柄,我们将用它在后面的操作中读写数据,类似注册表的Key。
DescriptorKeyIDArray:
uint32数组,存储需要查询的key集合。其相关定义为:
typedef unsigned long DescriptorKeyID;
typedef DescriptorKeyID DescriptorKeyIDArray[];
数组里面的元素是你需要的key名,即你要查询的参数名称,即你要求查询哪些key。注意因为是int32类型,所以每个key可以容纳4个字符表示的ASCII码,如果不足4个字节,可以用空格补足。例如,设置这个参数赋为可以设置{'Pam1','Pam2',NULL},这表示你需要查询两个参数,'Pam1'和'Pam2'。 例如脚本系统中,高斯模糊(GaussianBlur)滤镜的key是'GsnB'。
每个键值通过调用GetKeyProc()来得到的,每返回一个值,这个字符串数组中的相应key将被设置为空('