Photoshop滤镜开发简介(2)--Photoshop回调函数

        在上一篇文章中,我们介绍了开发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
#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的获取和释放
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
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
typedef struct PIDescriptorParameters
{
       int16 descriptorParametersVersion;  //版本号
       int16 playInfo; //动作播放标识:0-对话框可选;1-需要对话框;2-无对话框;
       int16 recordInfo; //动作录制标识:0-对话框不显示;1-对话框显示;2-对话框静寂;
       PIDescriptorHandle descriptor; //描述符的句柄,非常重要,我们将用它读写数据!
       WriteDescriptorProcs* writeDescriptorProcs; //“写”子函数集
        ReadDescriptorProcs* readDescriptorProcs; //“读”子函数集
} PIDescriptorParameters;

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

获取“读”和“写” sub-suite
//获得描述符参数结构:
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将被设置为空('\0')。正常情况下,当你在调用CloseReadDescriptorProc()时,这个数组将变成全部是空,否则说明有的key并没有被查询到,这时你将丢失你的数据,或者通过显示对话框要求用户来提供数据。

      CloseReadDescriptorProc( ):关闭一个“读”描述符
      定义:
      OSErr (*CloseReadDescriptorProc) (PIReadDescriptor);
      描述;关闭一个描述符,如果读过程中产生错误,它将返回最主要的错误。

       GetKeyProc( ):获取一个Key
       定义:
        (*GetKeyProc) (PIReadDescriptor descriptor, DescriptorKeyID *key, DescType *type, int16 *flags);
        描述:这个函数返回一个KeyID(参数名),描述符类型,和标识。根据函数返回时的key,表示当前查询到的是哪个key。然后我们可以使用下面将要提到的相应的查询函数获得这个key的value。相关类型定义:
        typedef unsigned long DescriptorKeyID;
        typedef unsigned long DescriptorTypeID;

         OpenWriteDescriptorProc( )
         定义: PIWriteDescriptor (*OpenWriteDescriptorProc) (void);
         描述:打开一个写描述符,失败时,返回NULL;
         CloseWriteDescriptorProc( )
         定义:
         OSErr (*CloseWriteDescriptorProc) (PIWriteDescriptor descriptor, PIDescriptorHandle *newDescriptor);
         描述:
         这个函数关闭一个写描述符,并创建一个新的描述符句柄,你需要把新描述符通过设置到PIDescriptorParameteres中,以返回给宿主程序。这里的函数的行为有些类似GDI操作中的SelectObject。在GDI操作中,当你对设备上下文设置新的属性时,它会把现有属性返回给你,以期待你做个备份。

         两个子函数集中读出和写入数据的函数:
         由于这里的函数较多,我们不一一逐个讲解,这里只是介绍大概形式,需要时单独讲解。
         大多数具有比较规范的特点(有少部分函数具有例外形式,我们后面单独介绍),即读用Get开头,写用Put开头,第一个参数是相应描述符,第二个参数是用于接收查询结果(或者用于存放写入数据)的相应类型数据指针。假设我们需要查询的数据类型是TypeName,则其如下:

          OSErr (*GetTypeNameProc) (PIReadDescriptor descriptor,  TypeName *dest); //读
          OSErr (*PutTypeNameProc) (PIWriteDescriptor descriptor,  DescriptorKeyID, TypeName *dest);  //写:
          下面我们列出所有读子函数集和写子函数集的函数(在piaction.h中定义):

Read Descriptor sub-suite
//读子函数集成员
typedef struct ReadDescriptorProcs
 {
 int16 readDescriptorProcsVersion; //版本号
 int16 numReadDescriptorProcs;     //函数数量
 OpenReadDescriptorProc  openReadDescriptorProc;  //打开一个读描述符
 CloseReadDescriptorProc  closeReadDescriptorProc;  //关闭一个读描述符
 GetKeyProc     getKeyProc;     //读取一个key
 GetIntegerProc    getIntegerProc;  //获取一个整数
 GetFloatProc    getFloatProc; //获取一个整数
 GetUnitFloatProc   getUnitFloatProc; //获取一个double数
 GetBooleanProc    getBooleanProc; //获取一个int32
 GetTextProc     getTextProc; //获取一个text的Handle
 GetAliasProc    getAliasProc; //获取一个(别名?)的句柄
 GetEnumeratedProc   getEnumeratedProc; //获取枚举类型
 GetClassProc    getClassProc; //例外,提供一个类型,和一个接收对象句柄的指针
 GetSimpleReferenceProc  getSimpleReferenceProc; //获取一个引用。
 GetObjectProc    getObjectProc; //例外,额外提供对象类型
 GetCountProc    getCountProc; //获取uint32数据
 GetStringProc    getStringProc; //获取unsigned char[256](第一个字符是字符串长度,以\0结尾)
 GetPinnedIntegerProc  getPinnedIntegerProc; //例外:获取指定范围内的整数,额外提供最小值和最大值。
 GetPinnedFloatProc   getPinnedFloatProc;    //例外:获取指定范围内的double,额外提供最小值和最大值。
 GetPinnedUnitFloatProc  getPinnedUnitFloatProc; //例外:获取指定范围内指定单位(距离,密度,角度,像素,百分比)的double,
                                                                       //额外提供最小值和最大值。
} ReadDescriptorProcs;

Write Descriptor sub-suite
//写子函数集成员,形式类似前面的函数,但都额外需要提供key
typedef struct WriteDescriptorProcs
 {
 int16 writeDescriptorProcsVersion;
 int16 numWriteDescriptorProcs;
 OpenWriteDescriptorProc  openWriteDescriptorProc;
 CloseWriteDescriptorProc closeWriteDescriptorProc;
 PutIntegerProc    putIntegerProc;
 PutFloatProc    putFloatProc;
 PutUnitFloatProc   putUnitFloatProc;
 PutBooleanProc    putBooleanProc;
 PutTextProc     putTextProc;
 PutAliasProc    putAliasProc;
 PutEnumeratedProc   putEnumeratedProc;
 PutClassProc    putClassProc;
 PutSimpleReferenceProc  putSimpleReferenceProc;
 PutObjectProc    putObjectProc;
 PutCountProc    putCountProc; 
 PutStringProc    putStringProc; 
 /* Scoped classes are not for use by plug-ins in Photoshop 4.0 */
  PutScopedClassProc   putScopedClassProc;
 PutScopedObjectProc   putScopedObjectProc; 
 } WriteDescriptorProcs;

         读写参数实例:
         从脚本系统读出参数:假设我们的参数的key为'Pam1',我们用一个临时变量param1来接收他:

Read A Parameter Demo Code
    PIReadDescriptor token = NULL;  //读操作符
    DescriptorKeyID key = NULL;  //uint32,即char*,键名
    DescriptorTypeID type = NULL; //描述符类型
    int32 flags = 0;     //标识
    DescriptorKeyIDArray array = { 'Pam1', NULL }; //要查询的key集合
    double param1;    //我们要读取的参数
    //获取描述符参数结构
    PIDescriptorParameters* descParams = gFilterRecord->descriptorParameters;
    if (descParams == NULL) return err;
    //获取Descriptor Suite中的“读”子函数集
    ReadDescriptorProcs* readProcs = gFilterRecord->descriptorParameters->readDescriptorProcs;
    if (readProcs == NULL) return err;
    
    if (descParams->descriptor != NULL)
    {
        //打开“读”描述符
        token = readProcs->openReadDescriptorProc(descParams->descriptor, array);
        if (token != NULL)
        {
            //获取一个键
            while(readProcs->getKeyProc(token, &key, &type, &flags) && !err)
            {
                switch (key)
                {
                    case 'Pam1'://读取到我们的参数
                        err = readProcs->getFloatProc(token, &param1);
                        break;
                    default:
                        err = readErr;
                        break;
                }
            }
            //关闭读描述符
            err = readProcs->closeReadDescriptorProc(token);
            //释放描述符
            gFilterRecord->handleProcs->disposeProc(descParams->descriptor);
            descParams->descriptor = NULL;
        }
   }

        向脚本系统写入参数:同上面的例子:

Write Descriptor Demo Code
    OSErr err = noErr;
    PIWriteDescriptor token = NULL;
    PIDescriptorHandle h;
    const double param1 = 1.05;

    PIDescriptorParameters*    descParams = gFilterRecord->descriptorParameters;
    if (descParams == NULL) return err;
    
    WriteDescriptorProcs* writeProcs = gFilterRecord->descriptorParameters->writeDescriptorProcs;
    if (writeProcs == NULL) return err;

    token = writeProcs->openWriteDescriptorProc();
    if (token != NULL)
    {
        //写入参数~
        writeProcs->putFloatProc(token,'Pam1',&param1);
        //释放描述符
        gFilterRecord->handleProcs->disposeProc(descParams->descriptor);
        //关闭该“读”描述符
        writeProcs->closeWriteDescriptorProc(token, &h);
        //把新的描述符返还给photoshop
        descParams->descriptor = h;
    }

3.3  DescriptorRegistry suite:(描述符注册函数集)
        描述符注册函数集主要用于描述符的注册和获取。这样可以实现在滤镜多次被调用期间,委托ps保存我们的参数。它包含注册,移除,获取key的几个关键函数。
        Register()
         描述:注册一个key。
         定义:
         OSErr (*Register)
         (
                /* IN */ const char* key,     // 唯一的字符串或ID
                /* IN */ PIActionDescriptor descriptor,  //描述符句柄
                /* IN */ Boolean isPersistent   // 是否委托PS维护以能够存储和恢复
         );
        Erase()
        描述:移除一个Key
        定义:
        OSErr (*Erase)
         (
                 /* IN */ const char* key     // 唯一的字符串或ID
         );
         Get()
         描述:返回一个Key。返回的描述符是一个拷贝,所以使用完后你必须主动释放它。
         定义:
         OSErr (*Get)
         (
                /* IN */ const char* key,                        // 唯一的字符串或者ID
                /* OUT */ PIActionDescriptor* descriptor  // 使用完后释放他
          );

3.4 ActionDescriptor suite: (动作描述符函数集)
         动作描述符函数集,用于存放keys(或对象)到描述符,以及从描述符读出他们,及其他描述符管理。这个函数集中同时包含了读写函数,使用方法和上一节中的描述符类似。它的定义如下:

PSActionDescriptorProcs Struct
typedef struct PSActionDescriptorProcs
    {
    // ALLOCATES: descriptor
    SPAPI OSErr (*Make)(PIActionDescriptor *descriptor);  
    SPAPI OSErr (*Free)(PIActionDescriptor descriptor);
    SPAPI OSErr (*GetType)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorTypeID *type);
    // index is zero based
    SPAPI OSErr (*GetKey)(PIActionDescriptor descriptor, uint32 index, DescriptorKeyID *key);
    SPAPI OSErr (*HasKey)(PIActionDescriptor descriptor, DescriptorKeyID key, Boolean *hasKey);
    SPAPI OSErr (*GetCount)(PIActionDescriptor descriptor, uint32 *count);
    SPAPI OSErr (*IsEqual)(PIActionDescriptor descriptor, PIActionDescriptor other, Boolean *isEqual);
    SPAPI OSErr (*Erase)(PIActionDescriptor descriptor, DescriptorKeyID key);
    SPAPI OSErr (*Clear)(PIActionDescriptor descriptor);
    /*存入数据*/    
    SPAPI OSErr (*PutInteger)(PIActionDescriptor descriptor, DescriptorKeyID key, int32 value);
    SPAPI OSErr (*PutFloat)(PIActionDescriptor descriptor, DescriptorKeyID key, double value);
    SPAPI OSErr (*PutUnitFloat)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorUnitID unit, double value);
    SPAPI OSErr (*PutString)(PIActionDescriptor descriptor, DescriptorKeyID key,  char *cstrValue);
    SPAPI OSErr (*PutBoolean)(PIActionDescriptor descriptor, DescriptorKeyID key, Boolean value);
    SPAPI OSErr (*PutList)(PIActionDescriptor descriptor, DescriptorKeyID key,  PIActionList value);
    SPAPI OSErr (*PutObject)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID type,  PIActionDescriptor value);
    SPAPI OSErr (*PutGlobalObject)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID type,  PIActionDescriptor value);
    SPAPI OSErr (*PutEnumerated)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorEnumTypeID type, DescriptorEnumID value);
    SPAPI OSErr (*PutReference)(PIActionDescriptor descriptor, DescriptorKeyID key,  PIActionReference value);
    SPAPI OSErr (*PutClass)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID value);
    SPAPI OSErr (*PutGlobalClass)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID value);
    SPAPI OSErr (*PutAlias)(PIActionDescriptor descriptor, DescriptorKeyID key, Handle value);
    /*获取数据*/
    SPAPI OSErr (*GetInteger)(PIActionDescriptor descriptor, DescriptorKeyID key, int32* value);
    SPAPI OSErr (*GetFloat)(PIActionDescriptor descriptor, DescriptorKeyID key, double* value);
    SPAPI OSErr (*GetUnitFloat)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorUnitID* unit, double* value);
    SPAPI OSErr (*GetStringLength)(PIActionDescriptor descriptor, DescriptorKeyID key, uint32 *stringLength);
    SPAPI OSErr (*GetString)(PIActionDescriptor descriptor, DescriptorKeyID key, char *cstrValue, uint32 maxLength);
    SPAPI OSErr (*GetBoolean)(PIActionDescriptor descriptor, DescriptorKeyID key, Boolean* value);
    SPAPI OSErr (*GetList)(PIActionDescriptor descriptor, DescriptorKeyID key, PIActionList* value);
    SPAPI OSErr (*GetObject)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID* type, PIActionDescriptor* value);
    SPAPI OSErr (*GetGlobalObject)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID* type, PIActionDescriptor* value);
    SPAPI OSErr (*GetEnumerated)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorEnumTypeID* type, DescriptorEnumID* value);
    SPAPI OSErr (*GetReference)(PIActionDescriptor descriptor, DescriptorKeyID key, PIActionReference* value);
    SPAPI OSErr (*GetClass)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID* value);
    SPAPI OSErr (*GetGlobalClass)(PIActionDescriptor descriptor, DescriptorKeyID key, DescriptorClassID* value);
    SPAPI OSErr (*GetAlias)(PIActionDescriptor descriptor, DescriptorKeyID key, Handle* value);
    /*数组形式*/
    SPAPI OSErr (*HasKeys)(PIActionDescriptor descriptor, DescriptorKeyIDArray requiredKeys, Boolean *hasKeys);
    SPAPI OSErr (*PutIntegers)(PIActionDescriptor descriptor, DescriptorKeyID key, uint32 count,  int32* value);
    SPAPI OSErr (*GetIntegers)(PIActionDescriptor descriptor, DescriptorKeyID key, uint32 count, int32* value);
    SPAPI OSErr (*AsHandle)(PIActionDescriptor descriptor, PIDescriptorHandle *value); /*转换为句柄*/
    SPAPI OSErr (*HandleToDescriptor)(PIDescriptorHandle value, PIActionDescriptor *descriptor); /*句柄转换为描述符*/
    SPAPI OSErr (*PutZString)(PIActionDescriptor descriptor, DescriptorKeyID key, ASZString zstring);
    SPAPI OSErr (*GetZString)(PIActionDescriptor descriptor, DescriptorKeyID key, ASZString *zstring);
    SPAPI OSErr (*PutData)(PIActionDescriptor descriptor, DescriptorKeyID key, int32 length, void *value);
    SPAPI OSErr (*GetDataLength)(PIActionDescriptor descriptor, DescriptorKeyID key, int32* value);
    SPAPI OSErr (*GetData)(PIActionDescriptor descriptor, DescriptorKeyID key, void* value); 
    } PSActionDescriptorProcs;

          把我们的参数写入描述符并注册的例子:在此之前,我们需要为我们的插件的参数指定一个唯一的ID,以注册和提取属于我们的描述符,例如:
          #define plugInUniqueID  "d9543b0c-3c91-11d4-97bc-00b0d0204936"

写入我们的参数
//写入参数并注册
SPErr WriteRegistryParameters(void)
{
    SPErr err = noErr;
    //获得SPBasicSuite,它是获取其他Suite的基础
    SPBasicSuite* basicSuite = gFilterRecord->sSPBasic;
    //描述符注册函数集指针
    PSDescriptorRegistryProcs* registryProcs = NULL;
    //描述符函数集指针
    PSActionDescriptorProcs* descriptorProcs = NULL;
    //描述符句柄
    PIActionDescriptor descriptor = NULL;
    //我们的参数
    double param1=0.1;

    //获取描述符注册函数集
    err = basicSuite->AcquireSuite(kPSDescriptorRegistrySuite, 
                                   kPSDescriptorRegistrySuiteVersion, 
                                   (const void **)&registryProcs);

    //获取动作描述符函数集
    err = basicSuite->AcquireSuite(kPSActionDescriptorSuite, 
                                   kPSActionDescriptorSuiteVersion, 
                                   (const void **)&descriptorProcs);
                                   
    err = descriptorProcs->Make(&descriptor);
    //写入我们的参数
    err = descriptorProcs->PutFloat(descriptor, 'Pam1',param1);
    //注册指定ID的描述符
    err = registryProcs->Register(plugInUniqueID, descriptor, true);
    //释放描述符
    if (descriptor != NULL)
        descriptorProcs->Free(descriptor);
    //释放函数集
    if (registryProcs != NULL)
        basicSuite->ReleaseSuite(kPSDescriptorRegistrySuite, 
                                 kPSDescriptorRegistrySuiteVersion);
    if (descriptorProcs != NULL)
        basicSuite->ReleaseSuite(kPSActionDescriptorSuite, 
                                 kPSActionDescriptorSuiteVersion);
    return err;
}

          读取我们的参数的例子:

读取注册的参数
//读取注册的参数
SPErr ReadRegistryParameters(void)
{
    SPErr err = noErr;
    //获取基本函数集,SPBasicSuite,通过它获取其他函数集
    SPBasicSuite* basicSuite = gFilterRecord->sSPBasic;
    PSDescriptorRegistryProcs* registryProcs = NULL;
    PSActionDescriptorProcs* descriptorProcs = NULL;
    PIActionDescriptor descriptor = NULL;
    double param1;

    //获取描述符注册函数集
    err = basicSuite->AcquireSuite(kPSDescriptorRegistrySuite, 
                                   kPSDescriptorRegistrySuiteVersion, 
                                   (const void **)&registryProcs);

    //获取动作描述符函数集
    err = basicSuite->AcquireSuite(kPSActionDescriptorSuite, 
                                   kPSActionDescriptorSuiteVersion, 
                                   (const void **)&descriptorProcs);

  //获取指定ID的描述符
    err = registryProcs->Get(plugInUniqueID, &descriptor);
    //读取注册的参数
    err = descriptorProcs->GetFloat(descriptor, 'Pam1',&param1);
    //释放描述符
    if (descriptor != NULL)
        descriptorProcs->Free(descriptor);
    //释放描述符注册函数集
    if (registryProcs != NULL)
        basicSuite->ReleaseSuite(kPSDescriptorRegistrySuite, 
                                 kPSDescriptorRegistrySuiteVersion);
    //释放动作描述符函数集
    if (descriptorProcs != NULL)
        basicSuite->ReleaseSuite(kPSActionDescriptorSuite, 
                                 kPSActionDescriptorSuiteVersion);
    return err;
}

         
(四)小结
        这一篇文章中,我们介绍了一些Photoshop提供给插件(不仅仅是给滤镜插件)的回调函数,他们主要分为两大类,一种是直接包含在插件参数结构中,称为直接回调函数;另一类是包含在回调函数集中的回调函数。
        对于直接回调函数,文本仅讲解了DisplayPixelsProc可以用于在设备DC上贴图。包括第一篇文中提到的AdvanceStateProc,TestAbortProc,UpdateProgressProc都属于直接回调,同时有的直接回调函数又隶属于某个Suite。
        对于回调函数集(Callback Suite),然后我们重点介绍了回调函数集中的Descriptor Suite中的读写,注册等操作,这个函数集可以使PS记录我们的滤镜参数到动作序列,也可以注册我们的滤镜参数以在多次调用期间保存和读取它们。其他回调函数集例如内存管理,颜色空间服务等函数集限于篇幅暂时还没有涉及。(--By hoodlum1980)

--------------------结束分割线----------------------

时间: 2024-09-13 09:53:06

Photoshop滤镜开发简介(2)--Photoshop回调函数的相关文章

怎样编写一个Photoshop滤镜(1)

            在很久前我曾经写过一篇文章简要讲述了 Photoshop 的滤镜开发的基本概念,并描述了滤镜和 PS之间的协作关系,也提供了一个雨滴效果滤镜的 Demo.但是缺少源代码.而且我们将要产生疑问,我们如何从头开始编写一个 Photoshop 滤镜呢?我们如何建立一个最简单的 PS 滤镜插件的基本框架,然后在这个基础上继续添加我们想要的功能呢?这里,我就以回答一个网友向我提出的问题为例,从最基本的建立项目开始讲起.这个例子(也是这个网友的问题)是,他想做一个最简单的滤镜,也就是

怎样编写一个Photoshop滤镜(3)-- Scripting Plug-ins

            在第一篇文章中我们建立了一个没有UI的基本滤镜框架,并且引入PIPL资源使之能被PS加载到菜单.在第二篇文章中我们又引入了滤镜参数和相应的对话框资源,并且讲解了对话框在滤镜调用流程中的显示时机.这一篇文章我们将使滤镜支持动作记录和回放,也就是通过添加"术语资源",使我们的滤镜参数被PS的脚本系统所获知(scripting-aware),并能够记录和回放.             从Photoshop 4.0开始引入了一个新的面板以及相应的命令和回调函数:动作面板

怎样编写一个Photoshop滤镜(4) -- 在对话框上增加缩略图

            在上一篇文章里,我们讲解了为滤镜添加术语资源,从而使我们的滤镜可以被PS的scripting system感知和描述,这样即友好支持了PS的"动作"面板.在这一篇文章中,我们将对此前的DEMO进行进一步的细化,例如在参数对话框上增加实时预览的小缩略图等.对话框的引入主要是给用户一个机会和接口,设置或调节滤镜使用的图像处理算法.通常作为UI的友好性,在对话框上应该提供预览图,这样可以直观的把参数对结果产生的影响反馈给用户,指导他们调整参数.而不是要用户必须反复执行

怎样编写一个Photoshop滤镜(2)

            在上一篇文章中,我们讲解了怎样创建一个Photoshop滤镜的项目,以及如何为滤镜嵌入PIPL资源使滤镜可以被PS识别和加载.并且我们已经建立了一个最简单最基本的滤镜框架.在这篇文章中,我们将细化滤镜和PS之间的调用流程,我们将为滤镜引入一个对话框资源,使用户可以对滤镜进行自定义参数的配置.并且我们将看到当用户从不同菜单位置发起滤镜调用时的流程区别,然后我们还将为我们的滤镜参数引入PS脚本描述系统的读写支持,将我们的参数存入PS的脚本系统中,并在以后的调用中读取出这些参数

Photoshop滤镜的选择技巧

技巧|滤镜 Photoshop的滤镜主要有五个方面的作用:优化印刷图象.优化WEB图象.提高工作效率.提供创意滤镜和创建三维效果.滤镜的出现,极大地增强了Photoshop 的功能,有了滤镜,我们就可以轻易地创造出十分"专业"的艺术效果.但Photoshop滤镜种类繁多,我们该如何选择实用的Photoshop 滤镜呢? 一.文字特效处理滤镜选择 用Photoshop制作的特效字不仅视觉效果一流,而且也非常实用.用Photoshop 的外挂滤镜来制作特效字就更简单了. 1.首选Ulead

Photoshop滤镜的原理与使用方法

  一.什么是滤镜? 滤镜原本是一种摄影器材,如下图所示:摄像师将他们安装在照相机的前面来改变照片的拍摄方式,可以影响色彩或者产生特殊的拍摄效果. photoshop中的滤镜是一种插件模块,他们能够操纵图像中的像素.位图(如照片.图像素材等)是由像素构成的,每一个像素都有自己的位置和颜色值,滤镜就是通过改变像素的位置或颜色来生成各种特殊效果的. 二.滤镜的种类和主要用途 滤镜分为内置滤镜和外挂滤镜两大类.内置滤镜就是photoshop自身提供的各种滤镜,外挂滤镜则是由其他厂商开发的滤镜,它们需要

《网页设计与前端开发 Dreamweaver+Flash+Photoshop+HTML+CSS+JavaScript 从入门到精通》—— 导读

前言 网页设计与前端开发 Dreamweaver+Flash+Photoshop+HTML+CSS+JavaScript 从入门到精通 网络技术的日益成熟,给人们带来了诸多方便.如今,网络正在各个领域发挥着巨大的作用,成为人们日常生活中不可或缺的部分.人们可以足不出户网上购物,随时查询股票信息,在自己的博客上尽情发表言论--以上这些都离不开最基本的网页设计.制作与维护. 制作一个网站需要很多技术,包括图像设计和处理.网页动画的制作和网页版面的布局编辑等.随着网页制作技术的不断发展和完善,产生了众

Photoshop滤镜打造璀璨的星球夜空图

极坐标滤镜是非常常用的,可以快速把平面图转为有趣的球体.同时我们还可以适当的进行美化,如加入一些装饰素材等.这样出来的画面会更加精美,生动. 三联推荐:photoshop7.0迷你版免费下载    |  Photoshop CS5 中文免费下载  |  photoshop免费下载   查看更多PS教程 最终效果 1.我们这里选择的图片是一张夜晚的全景图片.所以首先要对图片进行裁切.截取灯光比较密集,光线比较亮的地方.注意天空的比例尽量小一些. 2.接下来我们对画面的整体色调进行调整.原作品的曝光

巧用Photoshop滤镜绘制仿真水纹效果

滤镜 今天我们用Photoshop从无到有绘制一种仿真的水纹效果. 首先,在Photoshop中新建一个文件,设置为默认的前景色与背景色,RGB颜色模式.72分辨率,450*350象素大小.点好确认.然后执行滤镜-渲染-云彩.重复执行几次,直到出现如下效果: 然后执行滤镜-模糊-径向模糊.参数设置如下: 再执行滤镜-模糊-高斯模糊,设置参数为1.5象素.完成后如下图. 再执行滤镜-素描-基底凸现参数设置如下:细节14,平滑度8光照方向为下,点好.如下图: 然后执行滤镜-素描-铬黄,参数设置为:细