欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

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

程序员文章站 2022-05-23 23:41:37
...
在很久前我曾经写过一篇文章简要讲述了photoshop的滤镜开发的基本概念,并描述了滤镜和PS之间的协作关系,也提供了一个雨滴效果滤镜的Demo。但是缺少源代码。而且我们将要产生疑问,我们如何从头开始编写一个Photoshop滤镜呢?我们如何建立一个最简单的Ps滤镜插件的基本框架,然后在这个基础上继续添加我们想要的功能呢?这里,我就以回答一个网友向我提出的问题为例,从最基本的建立项目开始讲起。这个例子(也是这个网友的问题)是,他想做一个最简单的滤镜,也就是仅仅把图像填充为“红色”。对于PS用户来说,这当然是非常简单容易的事情,只需要一个快捷键操作而已,(滤镜通常是用于完成比较复杂的任务的),我们就从这个最基本的例子出发讲解编写滤镜的过程。在文章最后将附上范例的源码下载链接。

(1)我们使用的开发工具是Visual Studio .NET 2005版本,搭配Photoshop SDK CS(本质上就是一些C++代码和资源等文件组成的发行包)。开发语言使用的是C和C++。

那么使用C#或者其他语言行吗?目前来看可行性不大。所以要开发 Photoshop 滤镜,则要求开发者必须具有较好的C 和 C++ 基础,这是最重要的。当然如果开发者熟悉图像处理,数字信号处理的基本知识将会更好。

(2)准备好工具后,我们打开VS2005,新建项目。项目模板我们选择 Visual C++ 的 Win32。项目名称我们输入我们想要创建的滤镜名称,例如“FillRed”滤镜,表示这个滤镜用于填充红色,如下图:

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

点击确定以后,在弹出的设置对话框上,点击“应用程序设置”,在应用程序类型中选择选择“DLL”,然后点击确定。

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

(3)项目建立为一个标准DLL项目,我们在“解决方案资源管理器”中右键点击项目名称,在项目属性中我们做如下一些设置:

(a)在常规中,我喜欢把项目使用的字符集改为“使用多字节字符集”,这使我们可以用char*以及直接使用双引号的字符串类型。当然也可以使用Unicode,但是两者的使用的字符串函数会有所不同。可以随你的喜欢设定。

(b)项目已经默认输出为DLL, 由于Photoshop的滤镜文件的扩展名是8bf,所以我们在链接器->常规中,把输出文件的扩展名8bf。改为如下图所示。

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

(c)下面点击工具-》选项,在弹出的对话框中,选择“项目和解决方案”-》VC++目录, 在右侧下拉框中选取“包含文件”:把几个Photoshop SDK的文件夹添加到 选项的VC++包含目录中,这将会方便我们编译项目时不会报告找不到文件的错误。如下图所示:

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

(4)到这里我们已经基本设置好了项目,然后我们打开DLL的主要源文件“FillRed.cpp”,我们把该源文件的代码替换为如下:

// FillRed.cpp : 定义 DLL 应用程序的入口点。
//

#include "stdafx.h"
#include "PiFilter.h"
#include <stdio.h>

#ifdef _MANAGED
#pragma managed(push, off)
#endif


#ifndef DLLExport
#define DLLExport extern "C" __declspec(dllexport)
#endif

//=======================================
//        全局变量
//=======================================
//dll instance
HINSTANCE        dllInstance;
FilterRecord*    gFilterRecord;
int32*            gData;
int16*            gResult;
SPBasicSuite*    sSPBasic = NULL;
#define            TILESIZE    128 //贴片大小:128 * 128 
Rect            m_Tile;            //当前图像贴片(128*128)


//=======================================
//        函数列表
//=======================================
//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest);
//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest);
void DoParameters();
void DoPrepare();
void DoStart();
void DoContinue();
void DoFinish();


//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest)
{
    dest->left = src->left;
    dest->top = src->top;
    dest->right = src->right;
    dest->bottom = src->bottom;
}

//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest)
{
    dest->left = 0;
    dest->top = 0;
    dest->right = 0;
    dest->bottom = 0;
}

//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    dllInstance = static_cast<HINSTANCE>(hModule);
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

//===================================================================================================
//------------------------------------ 滤镜被ps调用的函数 -------------------------------------------
//===================================================================================================
DLLExport void PluginMain(const int16 selector,    void * filterRecord, int32 *data, int16 *result)
{
    gData = data;
    gResult = result;
    
    if (selector == filterSelectorAbout)
    {
        //显示关于对话框
        MessageBox(GetActiveWindow(), "FillRed Filter: 填充红色-- by hoodlum1980", "关于 FillRed", MB_OK);
    } 
    else 
    {
        gFilterRecord = (FilterRecordPtr)filterRecord;
        sSPBasic = gFilterRecord->sSPBasic;
    }

    switch (selector)
    {
        case filterSelectorAbout:
            //DoAbout();
            break;
        case filterSelectorParameters:
            DoParameters();
            break;
        case filterSelectorPrepare:
            DoPrepare();
            break;
        case filterSelectorStart:
            DoStart();
            break;
        case filterSelectorContinue:
            DoContinue();
            break;
        case filterSelectorFinish:
            DoFinish();
            break;
        default:
            *gResult = filterBadParameters;
            break;
    }
}

//这里准备参数,就这个滤镜例子来说,我们暂时不需要做任何事
void DoParameters()
{
}

//在此时告诉PS(宿主)滤镜需要的内存大小
void DoPrepare()
{
    if(gFilterRecord != NULL)
    {
        gFilterRecord->bufferSpace = 0;
        gFilterRecord->maxSpace = 0;
    }
}

//inRect     : 滤镜请求PS发送的矩形区域。
//outRect    : 滤镜通知PS接收的矩形区域。
//filterRect : PS通知滤镜需要处理的矩形区域。

//由于我们是使用固定的红色进行填充,实际上我们不需要请求PS发送数据
//所以这里可以把inRect设置为NULL,则PS不向滤镜传递数据。
void DoStart()
{
    if(gFilterRecord == NULL)
        return;

    //我们初始化第一个Tile,然后开始进行调用
    m_Tile.left = gFilterRecord->filterRect.left;
    m_Tile.top = gFilterRecord->filterRect.top;
    m_Tile.right = min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
    m_Tile.bottom = min(m_Tile.top + TILESIZE, gFilterRecord->filterRect.bottom);

    //设置inRect, outRect
    ZeroPsRect(&gFilterRecord->inRect); //我们不需要PS告诉我们原图上是什么颜色,因为我们只是填充
    CopyPsRect(&m_Tile, &gFilterRecord->outRect);

    //请求全部通道(则数据为interleave分布)
    gFilterRecord->inLoPlane = 0;
    gFilterRecord->inHiPlane = 0;
    gFilterRecord->outLoPlane = 0;
    gFilterRecord->outHiPlane = (gFilterRecord->planes -1);
}

//这里对当前贴片进行处理,注意如果用户按了Esc,下一次调用将是Finish
void DoContinue()
{
    if(gFilterRecord == NULL)
        return;

    //定位像素
    int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1; //通道数量         
    uint8 *pData=(uint8*)gFilterRecord->outData;

    //扫描行宽度(字节)
    int stride = gFilterRecord->outRowBytes;

    //我们把输出矩形拷贝到 m_Tile
    CopyPsRect(&gFilterRecord->outRect, &m_Tile);
    for(int j = 0; j< (m_Tile.bottom - m_Tile.top); j++)
    {
        for(int i = 0; i< (m_Tile.right - m_Tile.left); i++)
        {
            //为了简单明了,我们默认把图像当作RGB格式(实际上不应这样做)
            //pData[ i*planes + j*stride + 0 ] = 0;    //Red  
            //pData[ i*planes + j*stride + 1 ] = 0;    //Green 
            pData[ i*planes + j*stride + 2 ] = 255;    //Blue
        }
    }

    //判断是否已经处理完毕
    if(m_Tile.right >= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
    {
        //处理结束
        ZeroPsRect(&gFilterRecord->inRect);
        ZeroPsRect(&gFilterRecord->outRect);
        ZeroPsRect(&gFilterRecord->maskRect);
        return;
    }
    //设置下一个tile
    if(m_Tile.right < gFilterRecord->filterRect.right)
    {
        //向右移动一格
        m_Tile.left = m_Tile.right;
        m_Tile.right = min(m_Tile.right + TILESIZE, gFilterRecord->filterRect.right);
        
    }
    else
    {
        //向下换行并回到行首处
        m_Tile.left = gFilterRecord->filterRect.left;
        m_Tile.right = min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
        m_Tile.top = m_Tile.bottom;
        m_Tile.bottom = min(m_Tile.bottom + TILESIZE, gFilterRecord->filterRect.bottom);
    }

    ZeroPsRect(&gFilterRecord->inRect);
    CopyPsRect(&m_Tile, &gFilterRecord->outRect);
    //请求全部通道(则数据为interleave分布)
    gFilterRecord->inLoPlane = 0;
    gFilterRecord->inHiPlane = 0;
    gFilterRecord->outLoPlane = 0;
    gFilterRecord->outHiPlane = (gFilterRecord->planes -1);
}

//处理结束,这里我们暂时什么也不需要做
void DoFinish()
{
}


// FillRed.cpp : 定义 DLL 应用程序的入口点。
//

#include
"stdafx.h"
#include
"PiFilter.h"
#include
<stdio.h>

#ifdef _MANAGED
#pragma managed(push, off)
#endif


#ifndef DLLExport
#define DLLExport extern "C" __declspec(dllexport)
#endif

//=======================================
// 全局变量
//=======================================
//dll instance
HINSTANCE dllInstance;
FilterRecord
* gFilterRecord;
int32
* gData;
int16
* gResult;
SPBasicSuite
* sSPBasic = NULL;
#define TILESIZE 128 //贴片大小:128 * 128
Rect m_Tile;
//当前图像贴片(128*128)


//=======================================
// 函数列表
//=======================================
//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest);
//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest);
void DoParameters();
void DoPrepare();
void DoStart();
void DoContinue();
void DoFinish();


//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest)
{
dest
->left = src->left;
dest
->top = src->top;
dest
->right = src->right;
dest
->bottom = src->bottom;
}

//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest)
{
dest
->left = 0;
dest
->top = 0;
dest
->right = 0;
dest
->bottom = 0;
}

//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
dllInstance
= static_cast<HINSTANCE>(hModule);
return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

//===================================================================================================
//------------------------------------ 滤镜被ps调用的函数 -------------------------------------------
//===================================================================================================
DLLExport void PluginMain(const int16 selector, void * filterRecord, int32 *data, int16 *result)
{
gData
= data;
gResult
= result;

if (selector == filterSelectorAbout)
{
//显示关于对话框
MessageBox(GetActiveWindow(), "FillRed Filter: 填充红色-- by hoodlum1980", "关于 FillRed", MB_OK);
}
else
{
gFilterRecord
= (FilterRecordPtr)filterRecord;
sSPBasic
= gFilterRecord->sSPBasic;
}

switch (selector)
{
case filterSelectorAbout:
//DoAbout();
break;
case filterSelectorParameters:
DoParameters();
break;
case filterSelectorPrepare:
DoPrepare();
break;
case filterSelectorStart:
DoStart();
break;
case filterSelectorContinue:
DoContinue();
break;
case filterSelectorFinish:
DoFinish();
break;
default:
*gResult = filterBadParameters;
break;
}
}

//这里准备参数,就这个滤镜例子来说,我们暂时不需要做任何事
void DoParameters()
{
}

//在此时告诉PS(宿主)滤镜需要的内存大小
void DoPrepare()
{
if(gFilterRecord != NULL)
{
gFilterRecord
->bufferSpace = 0;
gFilterRecord
->maxSpace = 0;
}
}

//inRect : 滤镜请求PS发送的矩形区域。
//outRect : 滤镜通知PS接收的矩形区域。
//filterRect : PS通知滤镜需要处理的矩形区域。

//由于我们是使用固定的红色进行填充,实际上我们不需要请求PS发送数据
//所以这里可以把inRect设置为NULL,则PS不向滤镜传递数据。
void DoStart()
{
if(gFilterRecord == NULL)
return;

//我们初始化第一个Tile,然后开始进行调用
m_Tile.left = gFilterRecord->filterRect.left;
m_Tile.top
= gFilterRecord->filterRect.top;
m_Tile.right
= min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
m_Tile.bottom
= min(m_Tile.top + TILESIZE, gFilterRecord->filterRect.bottom);

//设置inRect, outRect
ZeroPsRect(&gFilterRecord->inRect); //我们不需要PS告诉我们原图上是什么颜色,因为我们只是填充
CopyPsRect(&m_Tile, &gFilterRecord->outRect);

//请求全部通道(则数据为interleave分布)
gFilterRecord->inLoPlane = 0;
gFilterRecord
->inHiPlane = 0;
gFilterRecord
->outLoPlane = 0;
gFilterRecord
->outHiPlane = (gFilterRecord->planes -1);
}

//这里对当前贴片进行处理,注意如果用户按了Esc,下一次调用将是Finish
void DoContinue()
{
if(gFilterRecord == NULL)
return;

//定位像素
int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1; //通道数量
uint8 *pData=(uint8*)gFilterRecord->outData;

//扫描行宽度(字节)
int stride = gFilterRecord->outRowBytes;

//我们把输出矩形拷贝到 m_Tile
CopyPsRect(&gFilterRecord->outRect, &m_Tile);
for(int j = 0; j< (m_Tile.bottom - m_Tile.top); j++)
{
for(int i = 0; i< (m_Tile.right - m_Tile.left); i++)
{
//为了简单明了,我们默认把图像当作RGB格式(实际上不应这样做)
//pData[ i*planes + j*stride + 0 ] = 0; //Red
//pData[ i*planes + j*stride + 1 ] = 0; //Green
pData[ i*planes + j*stride + 2 ] = 255; //Blue
}
}

//判断是否已经处理完毕
if(m_Tile.right >= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
{
//处理结束
ZeroPsRect(&gFilterRecord->inRect);
ZeroPsRect(
&gFilterRecord->outRect);
ZeroPsRect(
&gFilterRecord->maskRect);
return;
}
//设置下一个tile
if(m_Tile.right < gFilterRecord->filterRect.right)
{
//向右移动一格
m_Tile.left = m_Tile.right;
m_Tile.right
= min(m_Tile.right + TILESIZE, gFilterRecord->filterRect.right);

}
else
{
//向下换行并回到行首处
m_Tile.left = gFilterRecord->filterRect.left;
m_Tile.right
= min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
m_Tile.top
= m_Tile.bottom;
m_Tile.bottom
= min(m_Tile.bottom + TILESIZE, gFilterRecord->filterRect.bottom);
}

ZeroPsRect(
&gFilterRecord->inRect);
CopyPsRect(
&m_Tile, &gFilterRecord->outRect);
//请求全部通道(则数据为interleave分布)
gFilterRecord->inLoPlane = 0;
gFilterRecord
->inHiPlane = 0;
gFilterRecord
->outLoPlane = 0;
gFilterRecord
->outHiPlane = (gFilterRecord->planes -1);
}

//处理结束,这里我们暂时什么也不需要做
void DoFinish()
{
}

上面的代码也就是滤镜的一个基本框架,我们可以看到DLL将提供的一个导出函数是PluginMain函数,我们将把图像用128*128像素的切片进行分割处理,这可以使PS和滤镜之间每次传递较少量数据,尤其是对很大的图像来说,切片处理将有利于应对内存紧张的情况,也是Photoshop所提倡的,64*64或者128*128是比较典型的尺寸。

其调用过程是,在 start 调用中初始化第一个贴片(Tile),然后我们把第一个贴片设置为outRect,表示我们请求PS提供一个缓冲区用以接收该矩形所在位置的处理后数据,至于inRect,由于我们仅仅是填充,所以我们不关心图像的原来颜色如何,所以 inRect 可以设置为“空矩形”。图像的通道这里我们为了代码的直观和简单起见,我们就仅仅考虑RGB图像,即有3个通道的图像。设置好第一个 outRect,然后PS就会依次不停的开始进行 continue 调用,贴片从左至右,从上到下的顺序拼贴,直到贴片全部处理完成。注意 inData 和 outData 是 PS 向滤镜提供的申请数据和“回写缓冲区”,一个用于读,一个用于写,它们的大小是由滤镜向PS通知请求时填写的数据控制的,操作时绝不能越出其边界。

注意在滤镜处理数据的代码中请务必小心操作,一旦指针越界将会导致 Photoshop 程序崩溃!

有关该滤镜主体代码详细请参见代码注释,以及我此前一篇文章的解释。以及PS SDK的官方文档。这里我们就不再细述代码的原理了,因为它是恨简单的。上面的一切代码里面需要引用ps sdk中的头文件。

(4)这时,项目已经可以成功编译。但下面一步是是欠入 PIPL 资源。

必须为滤镜插入 PIPL 资源,才能被Photoshop所正确识别和加载。根据PS提供的文档介绍,PIPL的发音读作"pipple",它表示 Plug-In Property List。它是一个灵活,可扩展的用于表示插件模块元数据(metadata)的数据结构。pipl包括了Photoshop识别和加载插件模块的所有信息,包含一些标记,以及控制每个插件的各种静态属性等等,你的滤镜可以包含一个或者多个“pipl”结构。

为滤镜插入pipl资源的过程如下,首先我们需要给项目添加一个*.r(Macintosh的Rez文件)文件,然后使用 cl.exe 把这个文件编译为一个 *.rr文件,最后用 Ps SDK提供的一个资源转换工具 CnvtPipl.Exe 把*.rr 文件转换为 *.pipl 文件,然后为滤镜添加一个 *.rc资源文件,在rc文件的末尾把 pipl文件包含进来即可。

ps sdk已经为我们提供了一个通用的 r文件,包括了通用的属性定义,它是 PIGeneral.r 文件。

(a)下面我们就为项目添加一个 r文件,在资源管理器中右键点击“资源文件”文件夹,点击添加新的文件,文件名输入“FillRed.r”。双击打开该文件,复制以下内容:

// ADOBE SYSTEMS INCORPORATED
// Copyright  1993 - 2002 Adobe Systems Incorporated
// All Rights Reserved
//
// NOTICE:  Adobe permits you to use, modify, and distribute this 
// file in accordance with the terms of the Adobe license agreement
// accompanying it.  If you have received this file from a source
// other than Adobe, then your use, modification, or distribution
// of it requires the prior written permission of Adobe.
//-------------------------------------------------------------------------------
#define plugInName            "FillRed Filter"
#define    plugInCopyrightYear "2009"
#define plugInDescription \
    "FillRed Filter.\n\t - http:\\www.cnblogs.com\hoodlum1980"

#include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\includes\PIDefines.h"

#ifdef __PIMac__
    #include "Types.r"
    #include "SysTypes.r"
    #include "PIGeneral.r"
    #include "PIUtilities.r"
    #include "DialogUtilities.r"
#elif defined(__PIWin__)
    #define Rez
    #include "PIGeneral.h"
    #include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\PIUtilities.r"
    #include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\WinDialogUtils.r"
#endif

resource 'PiPL' ( 16000, "FillRed", purgeable )
{
    {
        Kind { Filter },
        Name { plugInName },
        Category { "Demo By hoodlum1980" },
        Version { (latestFilterVersion << 16) | latestFilterSubVersion },
        #ifdef __PIWin__
            CodeWin32X86 { "PluginMain" },
        #else
            CodeMachOPowerPC { 0, 0, "PluginMain" },
        #endif

        SupportedModes
        {
            noBitmap, doesSupportGrayScale,
            noIndexedColor, doesSupportRGBColor,
            doesSupportCMYKColor, doesSupportHSLColor,
            doesSupportHSBColor, doesSupportMultichannel,
            doesSupportDuotone, doesSupportLABColor
        },
            
        EnableInfo
        {
            "in (PSHOP_ImageMode, GrayScaleMode, RGBMode,"
            "CMYKMode, HSLMode, HSBMode, MultichannelMode,"
            "DuotoneMode, LabMode,"
            "Gray16Mode, RGB48Mode, CMYK64Mode, Lab48Mode)"
        },

        PlugInMaxSize { 2000000, 2000000 },

        FilterCaseInfo {
            {    /* array: 7 elements */
                /* Flat data, no selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Flat data with selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Floating selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Editable transparency, no selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Editable transparency, with selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Preserved transparency, no selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination,
                /* Preserved transparency, with selection */
                inStraightData,
                outStraightData,
                doNotWriteOutsideSelection,
                doesNotFilterLayerMasks,
                doesNotWorkWithBlankData,
                copySourceToDestination
            }
        }
    }
};


// ADOBE SYSTEMS INCORPORATED
// Copyright 1993 - 2002 Adobe Systems Incorporated
// All Rights Reserved
//
// NOTICE: Adobe permits you to use, modify, and distribute this
// file in accordance with the terms of the Adobe license agreement
// accompanying it. If you have received this file from a source
// other than Adobe, then your use, modification, or distribution
// of it requires the prior written permission of Adobe.
//-------------------------------------------------------------------------------
#define plugInName "FillRed Filter"
#define plugInCopyrightYear "2009"
#define plugInDescription \
"FillRed Filter.\n\t - http:\\www.cnblogs.com\hoodlum1980"

#include
"E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\includes\PIDefines.h"

#ifdef __PIMac__
#include
"Types.r"
#include
"SysTypes.r"
#include
"PIGeneral.r"
#include
"PIUtilities.r"
#include
"DialogUtilities.r"
#elif defined(__PIWin__)
#define Rez
#include
"PIGeneral.h"
#include
"E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\PIUtilities.r"
#include
"E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\WinDialogUtils.r"
#endif

resource
'PiPL' ( 16000, "FillRed", purgeable )
{
{
Kind { Filter },
Name { plugInName },
Category {
"Demo By hoodlum1980" },
Version { (latestFilterVersion
<< 16) | latestFilterSubVersion },
#ifdef __PIWin__
CodeWin32X86 {
"PluginMain" },
#else
CodeMachOPowerPC {
0, 0, "PluginMain" },
#endif

SupportedModes
{
noBitmap, doesSupportGrayScale,
noIndexedColor, doesSupportRGBColor,
doesSupportCMYKColor, doesSupportHSLColor,
doesSupportHSBColor, doesSupportMultichannel,
doesSupportDuotone, doesSupportLABColor
},

EnableInfo
{
"in (PSHOP_ImageMode, GrayScaleMode, RGBMode,"
"CMYKMode, HSLMode, HSBMode, MultichannelMode,"
"DuotoneMode, LabMode,"
"Gray16Mode, RGB48Mode, CMYK64Mode, Lab48Mode)"
},

PlugInMaxSize {
2000000, 2000000 },

FilterCaseInfo {
{
/* array: 7 elements */
/* Flat data, no selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Flat data with selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Floating selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Editable transparency, no selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Editable transparency, with selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Preserved transparency, no selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination,
/* Preserved transparency, with selection */
inStraightData,
outStraightData,
doNotWriteOutsideSelection,
doesNotFilterLayerMasks,
doesNotWorkWithBlankData,
copySourceToDestination
}
}
}
};



在FillRed.r文件中我们可以看到我们定义了滤镜的名称,所在的滤镜分组名称(Category),可以启用的图像模式等信息。然后右键点击该文件,在该文件的自定义生成规则的命令行中,点击编辑,输入以下内容:

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

在“命令行”一栏点击编辑按钮,在弹出的窗口中输入以下两行:

cl /I E:\Codes\Adobe~1\samplecode\Common\Includes /IE:\Codes\Adobe~1\PhotoshopAPI\Photoshop /IE:\Codes\Adobe~1\PhotoshopAPI\PICA_SP /IE:\Codes\Adobe~1\samplecode\Common\Resources /EP /DWIN32=1 /Tc"$(InputPath)" > "$(ProjectDir)\$(InputName).rr"


Cnvtpipl.exe "$(ProjectDir)\$(InputName).rr" "$(ProjectDir)\$(InputName).pipl"

其中,第一行表示使用 CL.EXE 把该文件编译为 *.rr文件,上面的“/I”选项表示需要的包含目录。

第二行表示使用PS SDK中的 Cnvtpipl.exe 工具把 rr文件编译为 pipl文件,请注意为了简单,我把该工具复制到了项目的源文件所在文件夹下面。它位于SDK的路径是:“\samplecode\resources\cnvtpipl.exe”。

(b)下面我们为项目添加一个 rc文件,同样右键点击“资源文件”,添加一个FillRed.rc文件。

这是一个windows的资源文件,我们暂时还不需要任何资源,所以我们直接用文本方式打开IDE自动生成的RC文件,在结尾处添加下面的一行:

//

#endif    // APSTUDIO_INVOKED

#endif    // 英语(美国)资源
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// 从 TEXTINCLUDE 3 资源生成。
//
#include "FillRed.pipl"

/////////////////////////////////////////////////////////////////////////////
#endif    // 不是 APSTUDIO_INVOKED


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

#endif // APSTUDIO_INVOKED

#endif // 英语(美国)资源
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// 从 TEXTINCLUDE 3 资源生成。
//
#include "FillRed.pipl"

/////////////////////////////////////////////////////////////////////////////
#endif // 不是 APSTUDIO_INVOKED

(5)我们编译项目,即可在项目的输出目录中看到 生成 FillRed.8bf 文件,下面我们把这个文件复制到 Photoshop的滤镜文件夹下面,例如我的Photoshop CS的滤镜所在目录是:“D:\Program Files\Adobe\Photoshop CS\增效工具\滤镜”

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

最后我们启动Photoshop,Photoshop会扫描插件目录,并把我们的滤镜加载到相应的菜单上,我们选择一个矩形选区,然后点击我们制作的滤镜相应菜单,即可看到效果,如下图所示。注意,下面的例子的效果是我仅仅把蓝通道填充了255。

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

在Photoshop 的帮助菜单- 关于增效工具 - 的子菜单中,可以看到我们编写的“FillRed Filter ...”一项,当点击它时PS即发起 about 调用,即可看到弹出的 MessageBox。

(6)最后,还是附上这个小例子的源代码下载链接:

请注意这个项目中有一些设置,比如 PhotoshopSDK的目录等,需要依据具体环境做出相应调整。PS SDK提供的资源转换工具也包含在项目文件夹内。(注意:附件中并未包含完整PS SDK)

http://files.cnblogs.com/hoodlum1980/FillRed.rar

(7)总结:

这一节讲述了从项目创建,到嵌入pipl资源,建立了一个基本的滤镜框架。但它的功能是非常基本和简单的,在以后的时间里,我们可能需要继续丰富这个例子,包括为它引入对话框资源,令PS为我们的滤镜缓存和读取我们的参数,包括在对话框表面绘制滤镜的预览图形等等。

更多怎样编写一个Photoshop滤镜(1)相关文章请关注PHP中文网!

相关标签: Photoshop滤镜