新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → VC++开发PhotoShop插件之选区 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 4342 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: VC++开发PhotoShop插件之选区 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 VC++开发PhotoShop插件之选区

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

    <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。详情请参阅代码,为了使程序流程清楚,代码做了适当的整理。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/4/11 10:08:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    //=============================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=====

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/4/11 10:09:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/9/21 14:13:16

    本主题贴数2,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    66.406ms