搜索
首页web前端PS教程怎样编写一个Photoshop滤镜(1)

            在很久前我曾经写过一篇文章简要讲述了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 
cf5ae2c81e53f0d22aed9d2f5fb24220

#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_cast0c54a695f76b87093d6c3a278af28dd6(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; j881f5b20a63bea3877cf8842b6951746= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
    {
        
//处理结束
        ZeroPsRect(&gFilterRecord->inRect);
        ZeroPsRect(
&gFilterRecord->outRect);
        ZeroPsRect(
&gFilterRecord->maskRect);
        
return;
    }
    
//设置下一个tile
    if(m_Tile.right a0849954cdb08ebee6712418c3b6bc53filterRect.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 &#39;PiPL&#39; ( 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 
f4881c45e06129b436475b2a0ddd04d4 "$(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


//

#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中文网!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Photoshop的订阅模型:您的钱是什么Photoshop的订阅模型:您的钱是什么Apr 15, 2025 am 12:17 AM

Photoshop的订阅模式值得购买。1)用户可以随时访问最新版本和跨设备使用。2)订阅费用低,提供持续更新和技术支持。3)高级功能如神经滤镜可用于复杂图像处理。尽管长期成本较高,但其便利性和功能更新对专业用户很有价值。

Photoshop:调查免费试用和折扣选项Photoshop:调查免费试用和折扣选项Apr 14, 2025 am 12:06 AM

你可以通过以下方式以最经济的方式获得Photoshop的使用权:1.利用7天的免费试用期体验软件功能;2.寻找学生或教师折扣,以及季节性促销;3.使用第三方网站上的优惠券;4.订阅AdobeCreativeCloud的月度或年度计划。

设计师的Photoshop:创建视觉概念设计师的Photoshop:创建视觉概念Apr 13, 2025 am 12:09 AM

在Photoshop中创建视觉概念可以通过以下步骤实现:1.创建新文档,2.添加背景层,3.使用画笔工具绘制基本形状,4.调整颜色和亮度,5.添加文本和图形,6.使用蒙版进行局部编辑,7.应用滤镜效果,这些步骤帮助设计师从零开始构建完整的视觉作品。

Photoshop免费吗?了解订阅计划Photoshop免费吗?了解订阅计划Apr 12, 2025 am 12:11 AM

Photoshop不是免费的,但有几种方式可以低成本或免费使用:1.免费试用期为7天,期间可体验所有功能;2.学生和教师优惠可将成本减半,需提供学校证明;3.CreativeCloud套餐适合专业用户,包含多种Adobe工具;4.PhotoshopElements和Lightroom为低成本替代方案,功能较少但价格更低。

Photoshop的价值:权衡成本与其功能Photoshop的价值:权衡成本与其功能Apr 11, 2025 am 12:02 AM

Photoshop值得投资,因为它提供了强大的功能和广泛的应用场景。1)核心功能包括图像编辑、图层管理、特效制作和色彩调整。2)适合专业设计师和摄影师,但业余爱好者可考虑替代品如GIMP。3)订阅AdobeCreativeCloud可按需使用,避免一次性高额支出。

Photoshop的核心目的:创意图像设计Photoshop的核心目的:创意图像设计Apr 10, 2025 am 09:29 AM

Photoshop在创意图像设计中的核心用途是其强大的功能和灵活性。1)它允许设计师通过图层、蒙版和滤镜将创意转化为视觉现实。2)基本用法包括裁剪、调整大小和颜色校正。3)高级用法如图层样式、混合模式和智能对象可创建复杂效果。4)常见错误包括图层管理不当和滤镜使用过度,可通过整理图层和合理使用滤镜解决。5)性能优化和最佳实践包括合理使用图层、定期保存文件和使用快捷键。

网页设计的Photoshop:UI/UX的高级技术网页设计的Photoshop:UI/UX的高级技术Apr 08, 2025 am 12:19 AM

Photoshop在网页设计中可用于创建高保真原型、设计UI元素和模拟用户交互。1.使用图层、蒙版和智能对象进行基础设计。2.通过动画和时间线功能模拟用户交互。3.利用脚本自动化设计过程,提高效率。

新手篇:利用ps笔刷给字体添加裂纹效果(分享)新手篇:利用ps笔刷给字体添加裂纹效果(分享)Apr 07, 2025 am 06:21 AM

之前的文章《一步一步教你使用ps将盘子图片添加印花效果(收藏)》中,给大家介绍了一种小技巧,怎么使用ps将盘子图片添加印花效果。下面本篇文章给大家介绍怎么利用ps笔刷给字体添加裂纹效果,我们一起看看怎么做。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。