• 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

            请注意,有些回调函数即属于直接回调,又被存储到某个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的获取和释放

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

           下面我们将介绍一些我认为对于滤镜插件比较重要的回调函数。简单介绍这些回调函数的位置和使用方法。
    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
             srcRect:源矩形(源图的复制范围)
             dstRow,  dstCol:目标起始点坐标(左上角),因为不拉伸绘制,所以只要左上角坐标就够了。
             platformContext:在Windows系统下,即device context(DC);

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

            获取了两个子函数集,我们就可以调用相应子函数集下面的函数进行“读”“写”我们的参数了。两个子函数集的使用和注册表操作类似,我们在进行读写前,首先需要打开相应描述符。因此我们先介绍打开和关闭描述符操作。
            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

    Write Descriptor sub-suite

             读写参数实例:
             从脚本系统读出参数:假设我们的参数的key为'Pam1',我们用一个临时变量param1来接收他:
    Read A Parameter Demo Code
            向脚本系统写入参数:同上面的例子:
    Write Descriptor Demo Code

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

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

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




  • 相关阅读:
    Spring MVC @PathVaribale注解
    Android XML解析并将数据存放在数据库中
    Android平台SoundPool 和 MediaPlayer
    Android编程获取网络连接状态(3G/Wifi)及调用网络配置界面
    程序员必备的七大面向对象设计原则(二)
    Android setRequestedOrientation用法
    Linux系统IP路由基础[第1部分]
    Android中解析XML
    Android学习笔记(6)————Android的线程与进程
    Eclipse最全快捷键
  • 原文地址:https://www.cnblogs.com/hoodlum1980/p/1088191.html
Copyright © 2020-2023  润新知