VC++開發PhotoShop插件之選區

本文轉自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=====

 
VC++開發BHO插件—定制浏覽器
VC++開發BHO插件—定制浏覽器
在Windows操作系統上,我們最常見的浏覽器有兩種:文件浏覽器(eXPloer.exe,應用于文件系統)和Internet浏覽器(iexplore.exe,應用于互聯網資源)。由于這兩個浏覽器功能強大,而且又與Windows操作系統捆綁銷售,最...查看完整版>>VC++開發BHO插件—定制浏覽器
 
VC++開發BHO插件——定制你的浏覽器
VC++開發BHO插件——定制你的浏覽器  作者 陸其明 關鍵字 BHO Browser COM ATL 網址過濾原作者姓名 陸其明 讀者評分 5 評分次數 1 正文在Windows操作系統上,我們最常見的浏覽器有兩種:文件浏覽器(exploer.exe,...查看完整版>>VC++開發BHO插件——定制你的浏覽器
 
VC++開發BHO插件定制你的浏覽器
在Windows操作系統上,我們最常見的浏覽器有兩種:文件浏覽器(exploer.exe,應用于文件系統)和Internet浏覽器(iexplore.exe,應用于互聯網資源)。由于這兩個浏覽器功能強大,而且又與Windows操作系統捆綁銷售,最...查看完整版>>VC++開發BHO插件定制你的浏覽器
 
VC++開發BHO插件——定制你的浏覽器
原作者姓名 陸其明 文章原始出處 http://hqtech.nease.net 正文 在Windows操作系統上,我們最常見的浏覽器有兩種:文件浏覽器(exploer.exe,應用于文件系統)和Internet浏覽器(iexplore.exe,應用于互聯網資源)...查看完整版>> VC++開發BHO插件——定制你的浏覽器
 
VC++開發BHO插件——定制你的浏覽器
原作者姓名 陸其明文章原始出處 http://hqtech.nease.net 正文在Windows操作系統上,我們最常見的浏覽器有兩種:文件浏覽器(exploer.exe,應用于文件系統)和Internet浏覽器(iexplore.exe,應用于互聯網資源)。由...查看完整版>>VC++開發BHO插件——定制你的浏覽器