adobe_photoshop_sdk 下载: http://www.adobe.com/devnet/photoshop.html
本文实现的是最简单的filter插件--将图像取反---也就是根本没有任何参数的一个filter!!!
其实要有参数可以自己加对话框(不熟悉windows编程,没实现),,完全没必要采用adobe的框架。
感觉alien skin exposure ; google nik collection等都是自己实现的:先读一个要修改的图像,在自己插件里选好效果后执行,返回结果到PS。 因而学习adobe家的架构不是太必要
注:只保证对RGB图像有效,,,对灰度图本来可以,,后来不知道怎么回事,直接弹对话框说接口不支持。。。。
修改自 http://www.cnblogs.com/hoodlum1980/archive/2009/05/11/1453870.html 非常好的中文教程,,但是我改了他的没成功,,年份久了,接口变了,,,
以及 adobe_photoshop_sdk_cc_2014_win 中的 dissolve 例程
最后工程用的dissolve例程的,本文件是例程和该网页综合起来的,还有我自己写的
注意例程使用的是相对路径,,,所以本工程必须放到和例程dissolve的同一级目录才行!!!否则请按以上教程所示自行修改头文件及 编译pipl文件的程序路径
重要参考文献:
How to Write a Photoshop Plug-In, Part 1(强烈推荐!!) http://www.mactech.com/articles/mactech/Vol.15/15.04/PhotoshopPlug-InsPart1/index.html
Writing a Photoshop Plug-In, Part 2 http://www.mactech.com/articles/mactech/Vol.15/15.05/PhotoshopPlug-InsPart2/index.html
adobe_photoshop_sdk_cc_2014_win document (很烂,但毕竟比较全)
Photoshop 的插件及其实现: http://www.moon-soft.com/book/plugin.htm
最后贴上主要代码:工程文件见附件
// 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. //------------------------------------------------------------------------------- #include "Matrix.hpp" #include "PiFilter.h" #include "FilterInfo.h" #include <stdio.h> /************************************************************************/ /* Photoshop 的无参数 filter 例程。 其实要有参数可以自己加对话框(不熟悉windows编程,没实现),,完全没必要采用adobe的框架。 感觉alien skin exposure ; google nik collection等都是自己实现的:先读一个要修改的图像,在自己插件里选好效果后执行,返回结果到PS。 因而学习adobe家的架构不是太必要 adobe_photoshop_sdk下载:[url]http://www.adobe.com/devnet/photoshop.html[/url] 修改自 http://www.cnblogs.com/hoodlum1980/archive/2009/05/11/1453870.html 非常好的中文教程,,但是我改了他的没成功,,年份久了,接口变了,,, 以及 adobe_photoshop_sdk_cc_2014_win 中的 dissolve 例程 最后工程用的dissolve例程的,本文件是例程和该网页综合起来的,还有我自己写的 注意例程使用的是相对路径,,,所以本工程必须放到和例程dissolve的同一级目录才行!!!否则请按以上教程所示自行修改头文件及 编译pipl文件的程序路径 重要参考文献: How to Write a Photoshop Plug-In, Part 1(强烈推荐!!) http://www.mactech.com/articles/mactech/Vol.15/15.04/PhotoshopPlug-InsPart1/index.html Writing a Photoshop Plug-In, Part 2 http://www.mactech.com/articles/mactech/Vol.15/15.05/PhotoshopPlug-InsPart2/index.html adobe_photoshop_sdk_cc_2014_win document (很烂,但毕竟比较全) Photoshop 的插件及其实现:http://www.moon-soft.com/book/plugin.htm */ /************************************************************************/ /************************************************************************/ /* 自己从新建立工程步骤(注意因为下面很多路径使用的是相对路径,,,所以本solution必须放到和例程dissolve的同一级目录(filter文件夹下)才行): 1、新建dll工程,, 拷贝本工程的一应文件 2、更改字符集为multibyte ; 更改输出文件类型为.8bf (debug、release要分别改,,下同) 3、拷贝dissolve工程的 c/c++ -> general -> additional include dictionaries 属性 4、拷贝dissolve工程的 linker -> input 属性 5、添加dissolve工程的common sources对应的cpp文件到本工程 6、右键LC_PSFilter.r,,设置编译属性,,这个直接copy就好 7、更改FilterInfo.h文件中的vendorName,,plugInName,,plugInUniqueID,,plugInDescription等属性 8、按下一个注释块更改本文件中的相关函数实现filter功能 */ /************************************************************************/ /************************************************************************/ /* 说明: 要实现自己的filter,,只需要修改processTile() 函数即可 (当前只是对RGB图像的实现)!!! 如果处理的通道不是RGB或灰度的,则也要修改setChannels()函数。 */ /************************************************************************/ /*******************************************/ //参数区 #ifndef NDEBUG #define USE_LOG //输出日志到桌面上 #endif #define USE_TILE__ //如果定义此项,,则将图片分成128*128的图像处理,如果不定义,则一次性进行处理 /*******************************************/ #ifdef USE_LOG //日志文件会出现在桌面上 #include "Logger.h" //template<typename Val> // void log (Logger& l, const char* des, Val v) { // l.Write (des, false); // l.Write (":\t", false); // l.Write (v, true); // } Logger logIt ("LCInvert"); #define printDesVal(des,v) logIt.Write (des, false);logIt.Write (":\t", false); logIt.Write (v, true); #define printDesValLn(v) printDesVal(#v,v); #define print(val) logIt.Write(val,false); #define println(val) logIt.Write(val,true); #else #define printDesVal(des,v) ; #define printDesValLn(v) ; #define print(val) ; #define println(val) ; #endif #ifdef _MANAGED #pragma managed(push, off) #endif #ifndef DLLExport #define DLLExport extern "C" __declspec(dllexport) #endif //======================================= // 全局变量 //======================================= //dll instance HINSTANCE dllInstance; FilterRecord* gFilterRecord; intptr_t* 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; } #ifdef _MANAGED #pragma managed(pop) #endif //=================================================================================================== //------------------------------------ 滤镜被ps调用的函数 ------------------------------------------- //=================================================================================================== DLLExport MACPASCAL void PluginMain (const int16 selector, FilterRecordPtr filterRecord, intptr_t * data, int16 * result) { try { //Timer timeIt; //需要#include "Timer.h" print ("Selector: "); print (selector); print ("\t\t\t"); // update our global parameters gData = data; gResult = result; if (selector == filterSelectorAbout) { MessageBox (GetActiveWindow(), plugInDescription, plugInName, MB_OK); //sSPBasic = gFilterRecord->sSPBasic; } else { gFilterRecord = filterRecord; sSPBasic = gFilterRecord->sSPBasic; //虽然这是dissolve例程中的,,,但有下面两句,,直接不执行 continue了。。。。 //另外自己试的 int err = gFilterRecord->advanceState(); 方法也无法正常使用。。。(不报错,但是数据指针均为空)不知道注释了之后行不行,,没试 // if (gFilterRecord->bigDocumentData != NULL) // gFilterRecord->bigDocumentData->PluginUsing32BitCoordinates = true; } // do the command according to the selector switch (selector) { case filterSelectorAbout: println ("filterSelectorAbout"); //DoAbout(); break; case filterSelectorParameters: println ("filterSelectorParameters"); DoParameters(); break; case filterSelectorPrepare: println ("filterSelectorPrepare"); DoPrepare(); break; case filterSelectorStart: println ("filterSelectorStart"); DoStart(); break; case filterSelectorContinue: println ("filterSelectorContinue"); DoContinue(); break; case filterSelectorFinish: println ("filterSelectorFinish"); DoFinish(); break; default: break; } print ("Image size:"); print (filterRecord->imageSize.h); print ("*"); println (filterRecord->imageSize.v); printDesValLn (filterRecord->maxSpace); printDesValLn (filterRecord->planes); printDesValLn (filterRecord->depth); //printDesValLn( timeIt.GetElapsed()); println (""); } // end try catch (...) { if (NULL != result) *result = -1; } } //这里准备参数,就这个滤镜例子来说,我们暂时不需要做任何事 void DoParameters() { } //在此时告诉PS(宿主)滤镜需要的内存大小 void DoPrepare() { if (gFilterRecord != NULL) { gFilterRecord->bufferSpace = 0; gFilterRecord->maxSpace = 0; } } void setChannels() { //设置我们需要处理的通道 int nchanel = 3; switch (gFilterRecord->imageMode) { //我们这里只处理灰度图,或者RGB图像 case plugInModeRGBColor: nchanel = 3; case plugInModeGrayScale: nchanel = 1; default: nchanel = 3; break; } gFilterRecord->inLoPlane = 0; gFilterRecord->inHiPlane = nchanel - 1; gFilterRecord->outLoPlane = 0; gFilterRecord->outHiPlane = nchanel - 1; } //inRect : 滤镜请求PS发送的矩形区域。 //outRect : 滤镜通知PS接收的矩形区域。 //filterRect : PS通知滤镜需要处理的矩形区域。 //由于我们是使用固定的红色进行填充,实际上我们不需要请求PS发送数据 //所以这里可以把inRect设置为NULL,则PS不向滤镜传递数据。 void DoStart() { if (gFilterRecord == NULL) return; #ifdef USE_TILE__ //我们初始化第一个Tile,然后开始进行调用 m_Tile.left = gFilterRecord->filterRect.left; m_Tile.top = gFilterRecord->filterRect.top; m_Tile.right = min (m_Tile.left + TILESIZE, gFilterRecord->filterRect.right); //只要修改这里就变成分tile处理的了 m_Tile.bottom = min (m_Tile.top + TILESIZE, gFilterRecord->filterRect.bottom); #else //不分tile了,一次完成!!!! m_Tile.left = gFilterRecord->filterRect.left; m_Tile.top = gFilterRecord->filterRect.top; m_Tile.right = gFilterRecord->filterRect.right; m_Tile.bottom = gFilterRecord->filterRect.bottom; #endif //设置inRect, outRect //ZeroPsRect (&gFilterRecord->inRect); CopyPsRect (&m_Tile, &gFilterRecord->inRect); CopyPsRect (&m_Tile, &gFilterRecord->outRect); setChannels();//设置需要请求的通道 } template<typename T> void processTile() { //定位像素 int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1; //通道数量 CopyPsRect (&gFilterRecord->outRect, &m_Tile); const int R = m_Tile.bottom - m_Tile.top; const int C = m_Tile.right - m_Tile.left; switch (planes) { case 1: {//单通道图像 T* pOut = (T*) gFilterRecord->outData; T* pIn = (T*) gFilterRecord->inData; LC::Matrix<T> in (pIn, R, C , gFilterRecord->inRowBytes); LC::Matrix<T> out (pOut, R, C, gFilterRecord->outRowBytes); printDesValLn ( (int) pIn[0]); for (int r = 0; r < R; r++) { //Sleep (100); // gFilterRecord->progressProc (r, out.rows() ); //显示进度条,此时按ESC键可以撤销该filter!!! // if (gFilterRecord->abortProc() ) {*gResult=-1; return}; for (int c = 0; c < C; c++) { T& orgb = out (r, c); T& irgb = in (r, c); orgb = LC::maxValInPS<T>() - irgb; } } } break; case 3: { //RGB图像 LC::RGB<T> *pOut = (LC::RGB<T>*) gFilterRecord->outData; LC::RGB<T>* pIn = (LC::RGB<T>*) gFilterRecord->inData; LC::Matrix<LC::RGB<T>> in (pIn, R, C, gFilterRecord->inRowBytes); LC::Matrix<LC::RGB<T>> out (pOut, R, C, gFilterRecord->outRowBytes); printDesValLn ( (int) pIn[0].r); //我们把输出矩形拷贝到 m_Tile for (int r = 0; r < R; r++) { //Sleep (100); // gFilterRecord->progressProc (r, out.rows() ); //显示进度条,此时按ESC键可以撤销该filter!!! // if (gFilterRecord->abortProc() ) {*gResult=-1; return}; for (int c = 0; c < C; c++) { LC::RGB<T>& orgb = out (r, c); LC::RGB<T>& irgb = in (r, c); orgb.r = LC::maxValInPS<T>() - irgb.r; orgb.g = LC::maxValInPS<T>() - irgb.g; orgb.b = LC::maxValInPS<T>() - irgb.b; } } } break; default: *gResult = -1; break; } } //这里对当前贴片进行处理,注意如果用户按了Esc,下一次调用将是Finish void DoContinue() { if (gFilterRecord == NULL) return; gResult = 0; println (gFilterRecord->depth); switch (gFilterRecord->depth) { case 8: processTile<uint8>(); break; case 16: processTile<uint16>(); break; case 32: processTile<uint32>(); break; default: *gResult = -1; break; } //判断是否已经处理完毕 if (gResult != 0 || ( 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.left + 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.top + TILESIZE, gFilterRecord->filterRect.bottom); } // ZeroPsRect (&gFilterRecord->inRect); CopyPsRect (&m_Tile, &gFilterRecord->inRect); CopyPsRect (&m_Tile, &gFilterRecord->outRect); } //处理结束,这里我们暂时什么也不需要做 void DoFinish() { }