PhotoShop插件开发之选区(Selection)
2010-07-25 20:46:57 来源:WEB开发网在插件中,如果想从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======================================
本文配套源码
更多精彩
赞助商链接