初学,,感觉PS插件的文档很烂,,教程也很少,,也就这么简单学一下了!!!
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() {
}