王朝网络
分享
 
 
 

VC++开发PhotoShop插件之选区

王朝vc·作者佚名  2008-06-01
宽屏版  字体: |||超大  

本文转自vc知识库,文中内容不代表本站观点,仅供参考

我们的程序里用到的图都是放在一张大图里的,所以就有一个文件记录每个小图是放在这张大图的什么地方,类似这个样子:

<name="button" left="10" top="30" right="24" bottom="70"/>.

图要是少了还好,多到几十、几百个这样的记录,每次要更新一个图都要找半天,尤其是界面大变的时候,几乎所有的小图的位置都变了,这样就要在Photoshop里找到每一个小图,记下它的坐标,然后在写到配置文件中。要是偶然做做也就忍了,可是这种不幸的事情经常发生,忍无可忍,觉得这种事情计算机应该可以胜任,它能干的事情,我们果断不能替它干。仔细研究了几天,总算研究明白了PS的插件机制,可以实现先Ctrl+C一些坐标位置,然后在PS中选中这些区域。

还是Adobe比较牛,我们辛辛劳苦帮它开发插件,它还要收费。现在的PS插件开发的SDK已经不免费下载了,还好在免费的互联网上还能找到早期版本的免费SDK,我找到的是6.0的,开发的插件可以在最新的PS CS2中使用。

据官方文档声明,PS大概支持9种插件,比较常见的是Filter,俗称滤镜,一般用来实现一些非凡的图像处理算法,如边缘提取等,我感爱好的是Select插件,看名字就像是和选区有关。插件的使用很简单,放到PS安装目录下的Plug-Ins目录下的相应类别下即可,比如滤镜就放在Plug-Ins\Filters下,扩展名是.8BF,选择插件放在Plug-Ins\Select下,扩展名为.8BS.PS启动时会搜索这个目录。

PS的SDK带了很多插件的例子,你可以找你感爱好的那个类别的插件例子看看,然后改改就可以了。我们先看看PS 6.0 SDK 带的Selection目录下的Selectorama这个例子。它演示了如何在当前的文档上选中感爱好的区域,不过例子似乎稍微复杂了点儿。

PS的Windows下的插件一般是一个标准的dll,入口函数为PluginMain,原型是:

void PluginMain (const short selector,

PISelectionParams *selectionParamBlock,long *data,short *result);

其中,selector是一个类型参数,说明本次调用的目的是什么,假如是常量"selectionSelectorAbout",说明需要显示一个关于对话框。在滤镜插件中,PluginMain会被调用多次,可以根据selector来决定具体做什么操作。

selectionParamBlock 是指向一个庞大的结构的指针,里面几乎有所有你需要的东西。比如,当前文档的大小可以通过

selectionParamBlock->documentInfo->bounds

获取,假如想知道现在用户是否选择了一块区域,可以通过 selectionParamBlock->documentInfo->selection->bounds 来获取。

剩下的两个都是输出参数,可以用来存储句柄,返回错误等,暂时可以不用理会。

在PluginMain函数中,会间接调用DoExecute这个函数,传递的参数叫globals,其实是把输入参数 selectionParamBlock 包装了一下,真正有用的还是:

globals->selectionParamBlock

在插件中,假如想从PS里读数据,需要一个叫做read port的东西,例子中使用了ReadFromWritePort这个宏来获取一个read port,这个我们暂时可以不用管它,接着向下看,会看到分配了三块缓冲区:sBuffer,dBuffer,rBuffer,假如transparency不空的话,还会分配一个mBuffer的缓冲区。我实际用到的只是sBuffer和dBuffer,其它两个高级的东东还没用到。接下来是调用 AccountChannel 计算需要处理的通道,一般会有R G B 三个通道。然后就是要害的 ApplyChannel 函数来完成实际的工作。

这个函数的参数很多,不过你只要记住刚才提到的sBuffer和dBuffer就够了。sBuffer用来保存从当前的图像中读来的图像数据,dBuffer用来保存你的选区信息,和sBuffer一一对应,假如某个象素需要选中,直接赋值为255即可。原例中需要选择的部分赋值是原来图像的内容,经过实践发现这样会造成魔棒选区的特效,我用不着这个高级功能,所以就直接赋成255了,可以精确的按我的要求工作。在这个函数里,考虑到图像可能会比较大,一次读过来可能受不了,所以先用了两个循环,按64×64的块大小循环读取处理,我们就可以再来一次循环,对每个64×64块的每个象素处理,根据剪贴板里设定的选区信息,判定当前象素的位置是否在这个选区内,假如是,就把dBuffer中的相应位置置为255,否则就是0。详情请参阅代码,为了使程序流程清楚,代码做了适当的整理。

//=============================PluginMain Start======================

DLLEXPort MACPASCAL void PluginMain (const short selector,

PISelectionParams *selectionParamBlock,

long *data,short *result)

{

//显示About对话框

if (selector == selectionSelectorAbout)

{

DoAbout((AboutRecordPtr)selectionParamBlock);

}

else

{

static const FProc routineForSelector [] =

{

/* selectionSelectorAbout DoAbout, */

/* selectionSelectorExecute */DoExecute

};

Ptr globalPtr = NULL;// Pointer for global strUCture

GPtr globals = NULL; // actual globals

//包装selectionParamBlock到globals中,真正有用的还是globals->selectionParamBlock

globalPtr = AllocateGlobals ((uint32)result,

(uint32)selectionParamBlock,

selectionParamBlock->handleProcs,

sizeof(Globals),

data,

InitGlobals);

if (globalPtr == NULL)

{

*result = memFullErr;return;

}

globals = (GPtr)globalPtr;

//调用 DoExecute 函数

if (selector > selectionSelectorAbout && selector <= selectionSelectorExecute)

(routineForSelector[selector-1])(globals);

else

gResult = selectionBadParameters;

if ((Handle)*data != NULL)

PIUnlockHandle((Handle)*data);

} // about selector special

}

//=============================PluginMain End=================================

//=============================DoExecute Start=================================

void DoExecute (GPtr globals)

{

//一些变量声明,省略...

//...

//

//从剪贴板中读取自己定义格式的选区信息,保存到全局变量中,我加的

//省略部分内容

gQueryForParameters = ReadScriptParams (globals);

gStuff->treatment = 0;//KeyToEnum(EnumToKey(gCreate,typeMyCreate),typeMyPISel);

//忽略原程序的UI参数处理

//获取读取端口

gResult = ReadFromWritePort(&selectionRead, selection->port);

//省略部分内容

//分配内存

gResult = AllocateBuffer (kBufferSize, &sBuffer);

if (gResult != noErr) goto CleanUp;

gResult = AllocateBuffer (kBufferSize, &dBuffer);

if (gResult != noErr) goto CleanUp;

gResult = AllocateBuffer (kBufferSize, &rBuffer);

if (gResult != noErr) goto CleanUp;

sData = LockBuffer (sBuffer, false);

dData = LockBuffer (dBuffer, false);

rData = LockBuffer (rBuffer, false);

//省略部分内容

//统计要处理的通道

curChannel = composite;

while (curChannel != NULL)

{

if (DoTarget curChannel->target : curChannel->shown)

total += AccountChannel (curChannel, transparency, selection);

curChannel = curChannel->next;

}

//进行实际的处理工作

while (curChannel != NULL)

{

if (DoTarget curChannel->target : curChannel->shown)

{

ApplyChannel (globals, curChannel, &sDesc,

transparency, &mDesc,

selection, selectionRead, &dDesc,

&rDesc, &done, total);

if (gResult != noErr) goto CleanUp;

}

curChannel = curChannel->next;

}

//善后工作...

}

//=========DoExecute End===========

//========ApplyChannel Start========

static void ApplyChannel (GPtr globals,

ReadChannelDesc *source,

PixelMemoryDesc *sDesc,

ReadChannelDesc *mask,

PixelMemoryDesc *mDesc,

WriteChannelDesc *dest,

ChannelReadPort destRead,

PixelMemoryDesc *dDesc,

PixelMemoryDesc *rDesc,

int32 *done,int32 total)

{

//声明变量,参数检查,省略

//内层循环中,每次读取64×64的块处理

//#define kBlockRows 64

for (row = limit.top; row < limit.bottom; row += kBlockRows)

for (col = limit.left; col < limit.right; col += kBlockCols)

{

//省略部分内容

gResult = ReadPixels (destRead, &scaling, &area, dDesc, &wrote);

//省略部分内容

gResult = ReadPixels (source->port, &scaling, &area, sDesc, &wrote);

s = (unsigned8 *) sDesc->data;//这里是原图象数据

d = (unsigned8 *) dDesc->data;//这里保存处理结果

//逐个象素处理64×64的块

for (row2 = 0; row2 < kBlockRows; ++row2)

{

int y = row + row2;

for (col2 = 0; col2 < kBlockCols; ++col2)

{

int x = col + col2;

int nRc = 0;

bool bFound = false;

while(nRc < g_rcCount)//g_rcCount是一共要显示的区域数,通过剪贴板传递计算

{

if(PtInRect(&g_rcArr[nRc],x,y))//g_rcArr存放所有要显示的区域

{

*d = 255;//这个象素处于选区内

bFound = true;

break;

}

++nRc;

}

//if(!bFound) *d = 0;

++s;

++d;

++r;

}

}

//处理完毕一小块,写回

gResult = WritePixels (dest->port, &area, dDesc);

//省略部分内容

}

}

//========ApplyChannel End=====

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有