VC++开发PhotoShop插件之选区

2016-02-19 21:33 63 1 收藏

今天天气好晴朗处处好风光,好天气好开始,图老师又来和大家分享啦。下面给大家推荐VC++开发PhotoShop插件之选区,希望大家看完后也有个好心情,快快行动吧!

【 tulaoshi.com - 编程语言 】

本文转自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-InsFilters下,扩展名是.8BF,选择插件放在Plug-InsSelect下,扩展名为.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); elsegResult = 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=====
   

来源:https://www.tulaoshi.com/n/20160219/1626475.html

延伸阅读
滑动控件是Windows中最常用的控件之一。一般而言它是由一个滑动条,一个滑块和可选的刻度组成,用户可以通过移动滑块在相应的控件中显示对应的值。通常,在滑动控件附近一定有标签控件或编辑框控件,用于显示相应的值。滑动控件在应用程序中用途级为广泛,如在桌面的属性中就可以看到。为此,让我们一起来看一下它的实现方法。 (...
包含头文件:#include winsvc.h 以下以web服务为例: #include winsvc.h void CStartServiceDlg::OnBnClickedButton1() {        // 打开服务管理对象     SC_HANDLE hSC = ::OpenSCManager( NULL,               &nbs...
*假设调试机IP 192.168.0.182   远程机IP 192.168.0.161 *远程机为调试机分配权限,使调试机可以使用远程桌面登陆到远程机器上(这样调试起来方便)。 *调试机上安装visual studio .net 2003 共享调试机上的Visual Studio上的远程调试目录(以我的机器为例) C:Program FilesMicrosoft Visual Studio .NET 2003Common7PackagesDe...
VC++通用GIS功能开发解决方案 2.0v 介绍 作者/潘立群 下载 Demo 示例程序 综述    《VC++通用GIS功能开发解决方案》源代码是基于VC++6.0 MFC 类库,在Win2000平台上开发的。界面部分用到了较低版本的 CJ60Lib 开放源码库,用户可自行替换高...
概述 管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信...

经验教程

634

收藏

61
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部