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

怎样编写一个Photoshop滤镜(2),第1张

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

(1)设计我们的滤镜参数。

我们的滤镜完成的是一个最基本的任务,仅仅是“填充”,因此我们可以对填充的颜色进行配置,此外,我们还可以设置填充颜色的不透明度。因此我们引入下面的参数,把它定义为一个struct,包括一个RGB填充色,和一个不透明度(0~100):

//======================================

// 定义我们的参数

//======================================

typedef struct _MYPARAMS

{

COLORREF fillColor; //填充颜色

int opacity; //百分比(0~100)

} MYPARAMS;

(2) 现在我们添加一个对话框资源。编辑对话框模块如下所示。然后我们对主要控件设置控件ID。

注意编辑资源文件后,由于VC将会重写rc文件,因此在编译项目前,我们还需要手工打开rc文件,自己重新添加#include "FillRedpipl"。

否则编译好的滤镜将无法被PS正确识别和加载到滤镜菜单。

(3)下面我们为该对话框添加窗口过程。为此我们为项目添加 ParamDlgh 和 ParamDlgcpp文件。

注意由于窗口过程位于我们的DLL中,因此我们必须把窗口过程声明为DLL导出函数,以便让系统知道该函数的地址。

关于窗口过程的编写则完全属于 windows 编程领域的内容(这方面的知识可以参考相关书籍),这里我们不详细介绍怎样写窗口过程。但值得一提的是,我在这里引入了一个PS中的UI特性,即PS中例如它的字体设置对话框,当鼠标悬停在控件前面的Lable(Static标签)上方时,光标形状可以改变为特殊光标,按下并左右拖动鼠标,则相关控件的值就会根据鼠标移动方向自动增加或减小,类似slider控件的效果。因此我在窗口过程中为它加入了这个特性,这会使得窗口过程的代码看起来稍显复杂一些,不过这个功能(可能是PS发明的?)很有趣也很新颖。为此我还引入了一个自定义的光标文件。具体代码不贴出了,请参考项目源代码中的 ParamDlgcpp文件中的代码。

(4)在第一篇文章的基础上,我们需要改写FillRedcpp中的一些代码。

因为现在我们引入了不透明度参数,不透明度的算法是:(opacity = 0~ 100)

结果值 = 输入值 (1- opacity001) + 填充颜色 opacity001;

(a)对DoStart 和 DoContinue:我们需要知道原图中原来的颜色,因此我们的 inRect 和 inHiPlane 将不在为空矩形。这体现在 DoStart 和 DoContinue 函数中,我们对inRect 和 inHiPlane 修改为和 outRect , outHiPlane 一致,这样PS就会把原图数据通过 inData 发送给我们。

(b)当用户点击滤镜菜单时,将从 parameter 调用开始,这样我们就在这里设置一个标记,表示需要显示对话框。

(c)当用户点击“最近滤镜”菜单时,将从 prepare 调用开始,这样表示我们不需要显示对话框,而是直接取此前的缓存参数。为此我们引入 ReadParams 和 WriteParams 函数。即使用PS提供的回调函数集使我们的参数和PS Scripting System进行交换数据。

下面我们主要看一下DoContinue函数发生的变化。主要是对算法进行了改动,对 inRect , inHiPlane 这两个数据进行了变动,以请求PS发送数据。在DoStart()函数中设置了第一个贴片,对inRect 和 inHiPlane 的改动是同样的。同时,在DoStart函数中, 根据事先设置过的标志,来决定是否显示对话框。

//DLLMain

BOOL APIENTRY DllMain( HMODULE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

dllInstance = static_cast<HINSTANCE>(hModule);

if (ul_reason_for_call == DLL_PROCESS_ATTACH || ul_reason_for_call == DLL_THREAD_ATTACH)

{

//在DLL被加载时,初始化我们的参数!

gParamsfillColor = RGB(0, 0, 255);

gParamsopacity = 100;

}

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;

gFilterRecord = (FilterRecordPtr)filterRecord;

if (selector == filterSelectorAbout)

sSPBasic = ((AboutRecord)gFilterRecord)->sSPBasic;

else

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 DoAbout()

{

AboutRecord aboutPtr = (AboutRecord)gFilterRecord;

PlatformData platform = (PlatformData)(aboutPtr->platformData);

HWND hwnd = (HWND)platform->hwnd;

MessageBox(hwnd, "FillRed Filter: 填充颜色 -- by hoodlum1980", "关于 FillRed", MB_OK);

}

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

void DoParameters()

{

//parameter调用说明,用户点击的是原始菜单,要求显示对话框

m_ShowUI = TRUE;

//设置参数地址

if(gFilterRecord->parameters == NULL)

gFilterRecord->parameters = (Handle)(&gParams);

}

//在此时告诉PS(宿主)滤镜需要的内存大小

void DoPrepare()

{

if(gFilterRecord != NULL)

{

gFilterRecord->bufferSpace = 0;

gFilterRecord->maxSpace = 0;

//设置参数地址

if(gFilterRecord->parameters == NULL)

gFilterRecord->parameters = (Handle)(&gParams);

}

}

//inRect : 滤镜请求PS发送的矩形区域。

//outRect : 滤镜通知PS接收的矩形区域。

//filterRect : PS通知滤镜需要处理的矩形区域。

//由于我们是使用固定的红色进行填充,实际上我们不需要请求PS发送数据

//所以这里可以把inRect设置为NULL,则PS不向滤镜传递数据。

void DoStart()

{

BOOL showDialog;

if(gFilterRecord == NULL)

return;

//从Scripting System 中读取参数值到gParams中。

OSErr err = ReadParams(&showDialog);

//是否需要显示对话框

if(!err && showDialog)

{

PlatformData platform = (PlatformData)(gFilterRecord->platformData);

HWND hWndParent = (HWND)platform->hwnd;

//显示对话框

int nResult = DialogBoxParam(dllInstance, MAKEINTRESOURCE(IDD_PARAMDLG),hWndParent,(DLGPROC)ParamDlgProc, 0);

if(nResult == IDCANCEL)

{

//选择了取消

ZeroPsRect(&gFilterRecord->inRect);

ZeroPsRect(&gFilterRecord->outRect);

ZeroPsRect(&gFilterRecord->maskRect);

WriteParams();

//注意: (1)如果通知 PS 用户选择了取消,将使PS不会发起 Finish调用!

// (2)只要 start 调用成功,则PS保证一定发起 Finish 调用。

gResult = userCanceledErr;

return;

}

}

//我们初始化第一个Tile,然后开始进行调用

m_Tileleft = gFilterRecord->filterRectleft;

m_Tiletop = gFilterRecord->filterRecttop;

m_Tileright = min(m_Tileleft + TILESIZE, gFilterRecord->filterRectright);

m_Tilebottom = min(m_Tiletop + TILESIZE, gFilterRecord->filterRectbottom);

//设置inRect, outRect

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

CopyPsRect(&m_Tile, &gFilterRecord->inRect);//现在我们需要请求和outRect一样的区域

CopyPsRect(&m_Tile, &gFilterRecord->outRect);

//请求全部通道(则数据为interleave分布)

gFilterRecord->inLoPlane = 0;

gFilterRecord->inHiPlane = (gFilterRecord->planes -1);;

gFilterRecord->outLoPlane = 0;

gFilterRecord->outHiPlane = (gFilterRecord->planes -1);

}

//这里对当前贴片进行处理,注意如果用户按了Esc,下一次调用将是Finish

void DoContinue()

{

int index; //像素索引

if(gFilterRecord == NULL)

return;

//定位像素

int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1; //通道数量

//填充颜色

uint8 r = GetRValue(gParamsfillColor);

uint8 g = GetGValue(gParamsfillColor);

uint8 b = GetBValue(gParamsfillColor);

int opacity = gParamsopacity;

uint8 pDataIn = (uint8)gFilterRecord->inData;

uint8 pDataOut = (uint8)gFilterRecord->outData;

//扫描行宽度(字节)

int stride = gFilterRecord->outRowBytes;

//我们把输出矩形拷贝到 m_Tile

CopyPsRect(&gFilterRecord->outRect, &m_Tile);

for(int j = 0; j< (m_Tilebottom - m_Tiletop); j++)

{

for(int i = 0; i< (m_Tileright - m_Tileleft); i++)

{

index = iplanes + jstride;

//为了简单明了,我们默认把图像当作RGB格式(实际上不应这样做)

pDataOut[ index ] =

(uint8)((pDataIn[ index ](100-opacity) + ropacity)/100); //Red

pDataOut[ index+1 ] =

(uint8)((pDataIn[ index+1 ](100-opacity) + gopacity)/100); //Green

pDataOut[ index+2 ] =

(uint8)((pDataIn[ index+2 ](100-opacity) + bopacity)/100); //Blue

}

}

//判断是否已经处理完毕

if(m_Tileright >= gFilterRecord->filterRectright && m_Tilebottom >= gFilterRecord->filterRectbottom)

{

//处理结束

ZeroPsRect(&gFilterRecord->inRect);

ZeroPsRect(&gFilterRecord->outRect);

ZeroPsRect(&gFilterRecord->maskRect);

return;

}

//设置下一个tile

if(m_Tileright < gFilterRecord->filterRectright)

{

//向右移动一格

m_Tileleft = m_Tileright;

m_Tileright = min(m_Tileright + TILESIZE, gFilterRecord->filterRectright);

}

else

{

//向下换行并回到行首处

m_Tileleft = gFilterRecord->filterRectleft;

m_Tileright = min(m_Tileleft + TILESIZE, gFilterRecord->filterRectright);

m_Tiletop = m_Tilebottom;

m_Tilebottom = min(m_Tilebottom + TILESIZE, gFilterRecord->filterRectbottom);

}

//ZeroPsRect(&gFilterRecord->inRect);

CopyPsRect(&m_Tile, &gFilterRecord->inRect);//现在我们需要请求和outRect一样的区域

CopyPsRect(&m_Tile, &gFilterRecord->outRect);

//请求全部通道(则数据为interleave分布)

gFilterRecord->inLoPlane = 0;

gFilterRecord->inHiPlane = (gFilterRecord->planes -1);;

gFilterRecord->outLoPlane = 0;

gFilterRecord->outHiPlane = (gFilterRecord->planes -1);

}

//处理结束,这里我们暂时什么也不需要做

void DoFinish()

{

//清除需要显示UI的标志

m_ShowUI = FALSE;

//记录参数

WriteParams();

} (5)从PS Scripting System中读写我们的参数,我们为项目添加 ParamsScriptingh 和 ParamsScriptingcpp,代码如下。引入ReadParams 和 WriteParams 方法,该节主要涉及 PS 的描述符回调函数集,比较复杂,但在这里限于精力原因,我也不做更多解释了。具体可以参考我以前发布的相关随笔中有关讲解PS回调函数集的一篇文章以及代码注释。其相关代码如下:

#include "stdafxh"

#include "ParamsScriptingh"

#include <stdioh>

OSErr ReadParams(BOOL showDialog)

{

OSErr err = noErr;

PIReadDescriptor token = NULL; //读操作符

DescriptorKeyID key = NULL; //uint32,即char,键名

DescriptorTypeID type = NULL;

int32 flags = 0;

int32 intValue; //接收返回值

char text[128];

//需要读取的keys

DescriptorKeyIDArray keys = { KEY_FILLCOLOR, KEY_OPACITY, NULL };

if (showDialog != NULL)

showDialog = m_ShowUI;

// For recording and playback 用于录制和播放动作

PIDescriptorParameters descParams = gFilterRecord->descriptorParameters;

if (descParams == NULL)

return err;

ReadDescriptorProcs readProcs = gFilterRecord->descriptorParameters->readDescriptorProcs;

if (readProcs == NULL)

return err;

if (descParams->descriptor != NULL)

{

摘要:旅游过程中我们会拍很多的照片,照片经过P图,能有更好地效果,发到朋友圈也能收获更多点赞!一般来说我们在用PS进行优化时,常常会用到ps中的滤镜功能,滤镜就在ps软件上的菜单栏里,点击即可。在调滤镜的时候,首先我们要进行的选择,再是滤镜的选择等步骤。接下来本文将简单介绍ps滤镜在软件中的位置以及该怎么调,和我一起来学学吧!一、ps滤镜在软件中的位置

ps里执行滤镜在PS菜单栏上面的滤镜里面。点击就可以进入选择。

ps滤镜主要是用来实现图像的各种特殊效果。它在ps中具有非常神奇的作用。滤镜通常需要同通道、图层等联合使用,才能取得最佳艺术效果。如果想在最适当的时候应用滤镜到最适当是位置,除了平常的美术功底之外,还需要用户的滤镜的熟悉和操控能力,甚至需要具有很丰富的想象力。

二、ps滤镜怎么使用

在这里以给云朵添加滤镜为例:

1、在ps的软件中,鼠标左键单击菜单文件|打开,选择一张准备添加滤镜效果的。

2、根据的情况,给的蓝色云彩背景添加滤镜。鼠标左键在PS的图层面板上,把云彩背景显示,人物图层不显示。

3、给云彩背景图像添加晶格化滤镜,鼠标左键单击菜单滤镜|像素化|晶格化。

4、在弹出晶格化的滤镜窗口上,设置滤镜参数。可以根据滤镜显示的预览窗口上看到滤镜添加在图像上显示的效果。

5、接着,鼠标左键单击好按钮,这样晶格化滤镜就添加在图像上,可以看到显示效果。

6、然后,在图层面板上,鼠标左键把人物图层显示出来,看整体效果是否表现主题。如果发现添加的滤镜不能表现主题,这时就要使用其它滤镜来添加到背景图像上。

7、接着,给云彩背景图像添加镜头光晕滤镜,鼠标左键单击菜单滤镜|渲染|镜头光晕。

8、然后,在弹出镜头光晕的滤镜窗口上,调整滤镜参数。可以根据滤镜显示的预览窗口上看到滤镜添加在图像上显示的效果。

9、接着,鼠标左键单击好按钮,这样镜头光晕滤镜就添加在图像上,可以看到显示效果,如下图所示。在图层面板上,鼠标左键把人物图层显示出来,看到整体效果可以突出表现主题,表示使用镜头光晕滤镜就合适。

10、把主题输入在上,查看创意设计的滤镜效果是否满足主题表达需要。

11、最后,在图像上添加一朵花的图像,并把主题输入在上。查看创意设计的效果是否满足主题表达需要。

在这个使用滤镜的实例中,可以总结出滤镜的使用需要根据主题的表达来使用。大家也来用PS的滤镜,来创意设计自己的作品吧。

提到调色,应该是PS众多功能中最常用的一种了,甚至在很多小伙伴心中都有着“PS=调色”这样的等式。而色彩风格千千万万,日系、德味、油画等等,不一而足,所谓弱水三千取一瓢饮也,本文阿随君要聊到的是“**级”风格。当然了,也并不是说带上“**级”就代表着多么高级啦,毕竟**也有好**有烂**,之所以要提出“**级”的说法,也只是这样方便沟通,大家都能意会指的是什么内容。

而提到PS中的“**级”调色,能够使用的工具和方法也是多种多样的,比如 ACR中使用此类xml预设、“颜色查找”中使用lut预设,或者借用外形胶片滤镜 等,都是非常方便和快速的。但是,阿随君本文要提到的此时从调色方式上来说就很“**”的一款第三方滤镜,它就是出自插件大厂 “红巨星”旗下的“Photolooks”滤镜 。用PS的小伙伴,可能对“红巨星”了解不多,但是玩视频剪辑和特效的一定早就知道了,他们在视频领域的多种插件套装都几乎是同类中的佼佼者。

Photolooks滤镜是红巨星调色套装中的一款滤镜,它对应的是视频调色look插件,是从视频到的完美移植,保留了视频调色中的工作原理,所以整个滤镜的面板布局到使用方法都保留了“look”的一贯做法,整个体验就跟为视频调色是极为相似的,所以,这是一款从诞生之初起就是为了服务**的,为调色当然也不在话下了。接下来,阿随君就简单来介绍一下这款滤镜。

Photolooks的启动,当然是很简单的啦。首先,打开PS软件后,我们拖入一张案例,这里阿随君使用了一张龙珠剧照。然后,点击菜单栏的“滤镜>Magic Bullet>Photolooks”即可打开这款滤镜了,图下图所示。

如下图所示,Photolooks面板非常简洁,中间最大的区域当然是实时预览区,左侧是观察区,右侧是具体参数控制区,下方是具体可调整的元素,选中每一个就在右侧的控制区有相应的参数出现了。最左下角的“loos”则是wuli懒人最爱的预设菜单了。

那么,接下来,通过一张gif动图来感受下Photolooks的面板布局吧。

那么,看完滤镜的面板,可能很多小伙伴会觉得好多参数啊,好麻烦啊,其实参数还是常见的那些,Photolooks的优势是工作方式,把**级的操作方法引入到了静帧中。当然了,如果,想快速上手,不想花太多学习成本的话,该滤镜丰富的预设库也足以满足了,一点就成,滤镜也按照色彩风格把预设分好类了,可以说是非常方便了。

20个大类下,每一类展开都有很多预设可选择的,下面通过一张gif动画,感受下这款滤镜的使用效果了。预设种类真的非常多,而且速度非常快,一点就应用了,足够我们用上好一阵子的了。

好了,这就是阿随君本文要介绍的一款**级的PS调色滤镜了。小伙伴们平时都还会用到哪些好用的调色滤镜呢,欢迎留言讨论哦。

欢迎分享,转载请注明来源:品搜搜测评网

原文地址:https://pinsoso.cn/meirong/3028377.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2024-01-16
下一篇2024-01-16

随机推荐

  • 戴宜戴白美白牙套可以吃饭喝水吗?

    美白牙套为了给大家做到体验感最佳状态厚度只有05毫米,不影响说话,可以正常喝常温或者凉水及饮料,避免佩戴牙套时,饮用色素沉淀较高的饮料及滚烫的热水。如红酒,桑葚汁,蓝莓汁等,不可以佩戴吃饭,吃饭前取下,冲洗牙套放置在赠送的牙套盒内,饭后将牙

    2024-04-15
    57500
  • 好用的唇膏有哪些

    1赫莲娜胶原卵白丰润密集唇霜深度滋润津润唇部,当即由内而外丰盈唇廓,淡化唇纹。独家专利成分Pro-Xfill能激起并加强细纹幼纹上层皮肤所短缺的胶原卵白IV型及胶原卵白VII型生成,重新弥补唇部因胶原流掉所造成的干涩、毁坏、凹痕和细纹。2

    2024-04-15
    54400
  • 精华露和精华液的顺序

    精华露和精华液的顺序,其实并没有固定的标准。不同品牌、不同产品之间,使用顺序也可能存在一些差异。但是,一般来说,我们可以这样理解:我们需要明确两者的功能区别。精华液是一种具有高浓度活性成分的保养品,可以为肌肤提供深层营养滋润,在保持肌肤水油

    2024-04-15
    56200
  • 干性皮肤用什么牌子的护肤品好?

    我是一个超级大干皮,夏天都会干到爆皮的那种,冬天要是不做好保湿再出门,简直就是灾难。我首先比较在意我眼部的状况,因为我黑眼圈比较重,平时就算是不上粉底液,都一定要用遮暇遮一下黑眼圈。前段时间,我一直在用网上推爆款的咖啡因眼霜。但是每次我上完

    2024-04-15
    48200
  • 妮维雅身体乳能美白么,妮维雅美白身体乳真的能美白吗

    俗话说“一白遮三丑”,这句话的意思就是白皙的皮肤可以遮盖人脸部上的很多缺点,这也会许多女孩子渴望美白肌肤的原因。改善肤色的办法有很多,大部分女生会选择涂抹具有美白功效的的护肤产品。现如今市面上的美白护肤产品越来越多,其中妮维雅的美白身体乳就

    2024-04-15
    47800
  • 欧诗漫珍珠白凝乳和珍珠白保湿乳的区别

    欧诗漫珍珠白凝乳和珍珠白保湿乳的区别:1、欧诗漫珍珠白保湿乳液是一种液体,而欧诗漫珍珠白保湿凝露属于面霜类,保湿乳液的质地通常都比较轻盈,而且还比较清爽,涂抹在脸上并没有粘稠感,但保湿凝露与乳液不同,保湿凝露质地比较厚重,擦在脸上有粘腻感。

    2024-04-15
    47500
  • 欧莱雅火山岩洁面膏,水凝露,平衡露和面膜怎么用?顺序

    使用顺序:洁面膏--水凝露--平衡露--面膜一、洁面膏。独特晶红啫喱质地,蕴含火山岩矿物精华。即刻净化油脂污垢,有效减少痘痘。冰感清爽配方,皮肤即刻净爽舒适。使用方法:取适量的产品于掌心,加水揉搓出泡沫。涂抹在润湿的面部并集中在前额,鼻子和

    2024-04-15
    45100

发表评论

登录后才能评论
保存