日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

调色板原理

發(fā)布時(shí)間:2023/12/10 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 调色板原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
調(diào)色板原理 & 編程 ? 邏輯調(diào)色板結(jié)構(gòu)LOGPALETTE,該結(jié)構(gòu)定義如下:
  typedef struct tagLOGPALETTE
  {
    WORD palVersion;  //調(diào)色板的板本號(hào),應(yīng)該指定該值為0x300;
    WORD palNumEntries;//調(diào)色板中的表項(xiàng)數(shù),對(duì)于灰度圖像該值為256;
    PALETEENTRY palPalEntry[1];//調(diào)色板中的顏色表項(xiàng),由于該表項(xiàng)的數(shù)目不一定,所以這里數(shù)組長(zhǎng)度定義為1,灰度圖像對(duì)應(yīng)的該數(shù)組的長(zhǎng)度為      ???????????????????????????????????????????????????? 256;
  } LOGPALETTE;
  顏色表項(xiàng)結(jié)構(gòu)PALETTEENTRY定義了調(diào)色板中的每一個(gè)顏色表項(xiàng)的顏色和使用方式,定義如下:
  typedef struct tagPALETTEENTRY
  {
    BYTE peRed; //R分量值;
    BYTE peGreen; //G分量值;
    BYTE peBlue; //B分量值;
    BYTE peFlags; // 該顏色被使用的方式,一般情況下設(shè)為"0";
  }PALETTEENTRY;

  Windows系統(tǒng)使用調(diào)色板管理器來管理與調(diào)色板有關(guān)的操作,通常活動(dòng)窗口的調(diào)色板即是當(dāng)前系統(tǒng)調(diào)色板,所有的非活動(dòng)窗口都必須按照此系統(tǒng)調(diào)色板來顯示自己的顏色,此時(shí)調(diào)色板管理器將自動(dòng)的用系統(tǒng)調(diào)色板中的最近似顏色來映射相應(yīng)的顯示顏色。如果窗口或應(yīng)用程序按自己的調(diào)色板顯示顏色,就必須將自己的調(diào)色板載入到系統(tǒng)調(diào)色板中 這種操作叫作實(shí)現(xiàn)調(diào)色板,實(shí)現(xiàn)調(diào)色板包括兩個(gè)步驟: 1.? 首先將調(diào)色板選擇到設(shè)備上下文中,可以通過CDC::SelectPalette() 選入設(shè)備上下文 2.? 然后在設(shè)備上下文中實(shí)現(xiàn)調(diào)色板,????可以通過 CDC::RealizePalette()實(shí)現(xiàn)設(shè)備調(diào)色板。 ? 在實(shí)現(xiàn)調(diào)色板的過程中,通過在框架類中處理Windows定義的消息WM_QUERYNEWPALETTE 、WM_PALETTECHANGED及視圖類中處理自定義消息WM_DOREALIZE(該消息在主框架窗口定義如下:#define WM_REALIZEPAL (WM_USER+101))來實(shí)現(xiàn)調(diào)色板的操作。當(dāng)系統(tǒng)需要處理調(diào)色板的變化時(shí),將向程序的主窗口發(fā)送WM_QUERYNEWPALETTE 、WM_PALETTECHANGED,例如當(dāng)某一窗口即將激活時(shí),主框架窗口將收到WM_QUERYNEWPALETTE消息,通知該窗口將要收到輸入焦點(diǎn),給它一次機(jī)會(huì)實(shí)現(xiàn)其自身的邏輯調(diào)色板;當(dāng)系統(tǒng)調(diào)色板改變后,主框架窗口將收到WM_PALETTECHANGED消息,通知其它窗口系統(tǒng)調(diào)色板已經(jīng)改變,此時(shí)每一窗口都應(yīng)該實(shí)現(xiàn)其邏輯調(diào)色板,重畫客戶區(qū)。

  由于上述的調(diào)色板變更消息是發(fā)往主框架窗口的,所以我們只能在主窗口中響應(yīng)這兩個(gè)消息,然后由主框架窗口通知各個(gè)視窗,使得程序激活時(shí)能自動(dòng)裝載自己的調(diào)色板。我們定義的用戶消息WM_REALIZEPAL用于主框架窗口通知視窗它已經(jīng)收到調(diào)色板變更消息,視窗應(yīng)該協(xié)調(diào)其調(diào)色板。下面我們給出了各個(gè)消息的響應(yīng)處理函數(shù)的具體實(shí)現(xiàn)代碼和注釋:

//
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{  //總實(shí)現(xiàn)活動(dòng)視的調(diào)色板
  CMDIFrameWnd::OnPaletteChanged(pFocusWnd);
  CMDIChildWnd* pMDIChildWnd = MDIGetActive();//得到活動(dòng)的子窗口指針;
  if (pMDIChildWnd == NULL)
      return
  CView* pView = pMDIChildWnd->GetActiveView();//得到視圖的指針;
  ASSERT(pView != NULL);
  SendMessageToDescendants(WM_DOREALIZE, (WPARAM)pView->m_hWnd); //通知所有子窗口系統(tǒng)調(diào)色板已改變
}

BOOL CMainFrame::OnQueryNewPalette()//提供實(shí)現(xiàn)系統(tǒng)調(diào)色板的機(jī)會(huì)
{
    // 實(shí)現(xiàn)活動(dòng)視的調(diào)色板
  CMDIChildWnd* pMDIChildWnd = MDIGetActive();//得到活動(dòng)的子窗口指針;
  if (pMDIChildWnd == NULL)
        return FALSE;//no active MDI child frame (no new palette)
  CView* pView = pMDIChildWnd->GetActiveView();//得到活動(dòng)子窗口的視圖指針;
        ASSERT(pView != NULL);

  pView->SendMessage(WM_DOREALIZE, (WPARAM)pView->m_hWnd);//通知活動(dòng)視圖實(shí)現(xiàn)系統(tǒng)調(diào)色板
    return TRUE;
}
/
BOOL CDibView::OnDoRealize(WPARAM wParam, LPARAM)//實(shí)現(xiàn)系統(tǒng)調(diào)色板
{
  ASSERT(wParam != NULL);
  CDibDoc* pDoc = GetDocument();
  if (pDoc->m_hDIB == NULL)
      return FALSE; // must be a new document
  CPalette* pPal = pDoc->m_palDIB;
//調(diào)色板的顏色表數(shù)據(jù)在InitDIBData()函數(shù)中實(shí)現(xiàn)
  if (pPal != NULL)
  {
    CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd;//得到程序的主框架指針;
    ASSERT_KINDOF(CMainFrame, pAppFrame);
    CClientDC appDC(pAppFrame);//獲取主框架的設(shè)備上下文;
    CPalette* oldPalette = appDC.SelectPalette(pPal, ((HWND)wParam) != m_hWnd);
    if (oldPalette != NULL)
    {
      UINT nColorsChanged = appDC.RealizePalette();//實(shí)現(xiàn)系統(tǒng)調(diào)色板
      if (nColorsChanged > 0)
        pDoc->UpdateAllViews(NULL);//更新視圖
      appDC.SelectPalette(oldPalette, TRUE);?//將原系統(tǒng)調(diào)色板置為背景調(diào)色板
  }
  else
  {
      TRACE0("\\tSelectPalette failed in");
  }
  return TRUE;
}

  注:在調(diào)用API函數(shù)顯示位圖時(shí),不要忘記設(shè)置邏輯調(diào)色板,即"背景"調(diào)色板,否則位圖將無法正確顯示,讀者可以從后面的顯示部分的實(shí)現(xiàn)看出我們?cè)陲@示時(shí)實(shí)現(xiàn)了邏輯調(diào)色板。上述的處理相對(duì)來說比較繁瑣復(fù)雜,可能對(duì)于初學(xué)者來說也比較難于理解,所以如果我們的程序僅僅限于處理灰度圖象,可以采用另外一種相對(duì)簡(jiǎn)單的辦法,即在文檔類的初始化階段定義一個(gè)灰度調(diào)色板,然后在設(shè)備上下文中實(shí)現(xiàn)它,這樣作的好處是在度取灰度位圖時(shí)可以不再考慮文件中的顏色表信息,提高了文件讀取速度,筆者在開發(fā)一個(gè)基于機(jī)器視覺的項(xiàng)目時(shí)采用的就是這種方法,取的了比較滿意的效果。首先定義一個(gè)指向邏輯顏色表結(jié)構(gòu) LOGPALETTE的指針pPal,填充該指針,然后將該指針與調(diào)色板指針聯(lián)系起來,該方法的具體實(shí)現(xiàn)如下:

/
  CDibDoc::CDibDoc()
  {
    LOGPALETTE *Pal;
    Pal=new LOGPALETTE;
    m_palDIB=new Cpalette;
    pPal->palVersion=0x300;
    pPal->palNumEntries=256;
    for(int i=0;i<256;i++)
    {//每個(gè)顏色表項(xiàng)的R、G、B值相等,并且各個(gè)值從"0"到"255"序列展開;
      Pal->palPalentry[i].peRed=i;
      pPal->palPalentry[i].peGreen=i;
      pPal->palPalentry[i].peBlue=i;
      pPal->palPalentry[i].peFlags=0;
    }
         m_palDIB->CreatePalette(pPal);
  } 2.??調(diào)色板的原理    PC機(jī)上顯示的圖象是由一個(gè)個(gè)像素組成的,每個(gè)像素都有自己的顏色屬性。在PC的顯示系統(tǒng)中,像素的顏色是基于RGB模型的,每一個(gè)像素的顏色由紅(B)、綠(G)、藍(lán)(B)三原色組合而成。每種原色用8位表示,這樣一個(gè)的顏色就是24位的。以此推算,PC的SVGA適配器可以同時(shí)顯示224約一千六百多萬種顏色。24位的顏色通常被稱作真彩色,用真彩色顯示的圖象可達(dá)到十分逼真的效果。但是,真彩色的顯示需要大量的視頻內(nèi)存,一幅640×480的真彩色圖象需要約1MB的視頻內(nèi)存。由于數(shù)據(jù)量大增,顯示真彩色會(huì)使系統(tǒng)的整體性能迅速下降。

?

?如圖為一個(gè)256色顯示模式中的調(diào)色板的工作原理 ? ?圖11.1 調(diào)色板工作原理

?

為了解決這個(gè)問題,計(jì)算機(jī)使用調(diào)色板來限制顏色的數(shù)目。調(diào)色板實(shí)際上是一個(gè)有256個(gè)表項(xiàng)的RGB顏色表,顏色表的每項(xiàng)是一個(gè)24位的RGB顏色值。使用調(diào)色板時(shí),在視頻內(nèi)存中存儲(chǔ)的不是的24位顏色值,而是調(diào)色板的4位或8位的索引。這樣一來,顯示器可同時(shí)顯示的顏色被限制在256色以內(nèi),對(duì)系統(tǒng)資源的耗費(fèi)大大降低了(不同時(shí)刻可以采用不同的調(diào)色板,因此可以擴(kuò)展總共可以顯示的顏色)。  顯示器可以被設(shè)置成16、256、64K、真彩色等顯示模式,前兩種模式需要調(diào)色板。在16或256色模式下,程序必須將想要顯示的顏色正確地設(shè)置到調(diào)色板中,這樣才能顯示出預(yù)期的顏色。圖11.1顯示了調(diào)色板的工作原理。使用調(diào)色板的一個(gè)好處是不必改變視頻內(nèi)存中的值,只需改變調(diào)色板的顏色項(xiàng)就可快速地改變一幅圖象的顏色或灰度。   在DOS中,調(diào)色板的使用不會(huì)有什么問題。由于DOS是一個(gè)單任務(wù)操作系統(tǒng),一次只能運(yùn)行一個(gè)程序,因此程序可以獨(dú)占調(diào)色板。在Windows環(huán)境下,情況就不那么簡(jiǎn)單了。Windows是一個(gè)多任務(wù)操作系統(tǒng),可以同時(shí)運(yùn)行多個(gè)程序。如果有幾個(gè)程序都要設(shè)置調(diào)色板,就有可能產(chǎn)生沖突。為了避免這種沖突,Windows使用邏輯調(diào)色板來作為使用顏色的應(yīng)用程序和系統(tǒng)調(diào)色板(物理調(diào)色板)之間的緩沖。? ? ? ? 圖11.2 調(diào)色板的映射關(guān)系 ?   在Windows中,應(yīng)用程序是通過一個(gè)或多個(gè)邏輯調(diào)色板來使用系統(tǒng)調(diào)色板(物理調(diào)色板)。 在256色系統(tǒng)調(diào)色板中,Windows保留了20種顏色作為靜態(tài)顏色,這些顏色用作顯示W(wǎng)indows界面,應(yīng)用程序一般不能改變。 缺省的系統(tǒng)調(diào)色板只包含這20種靜態(tài)顏色,調(diào)色板的其它項(xiàng)為空。應(yīng)用程序要想使用新的顏色,必須將包含有所需顏色的邏輯調(diào)色板實(shí)現(xiàn)到系統(tǒng)調(diào)色板中。在實(shí)現(xiàn)過程中 1. Windows首先將邏輯調(diào)色板中的項(xiàng)與系統(tǒng)調(diào)色板中的項(xiàng)作完全匹配,對(duì)于邏輯調(diào)色板中不能完全匹配的項(xiàng),Windows將其加入到系統(tǒng)調(diào)色板的空白項(xiàng)中,系統(tǒng)調(diào)色板總共有236個(gè)空白項(xiàng)可供使用, 1. 若系統(tǒng)調(diào)色板已滿,則Windows將邏輯調(diào)色板的剩余項(xiàng)匹配到系統(tǒng)調(diào)色板中盡可能接近的顏色上。 每個(gè)設(shè)備上下文都擁有一個(gè)邏輯調(diào)色板,缺省的邏輯調(diào)色板只有20種保留顏色,如果要使用新的顏色,則應(yīng)該創(chuàng)建一個(gè)新的邏輯調(diào)色板并將其選入到設(shè)備上下文中。但光這樣還不能使用新顏色,程序只有把設(shè)備上下文中的邏輯調(diào)色板實(shí)現(xiàn)到系統(tǒng)調(diào)色板中,新的顏色才能實(shí)現(xiàn)。在邏輯調(diào)色板被實(shí)現(xiàn)到系統(tǒng)調(diào)色板時(shí),Windows會(huì)建立一個(gè)調(diào)色板映射表。當(dāng)設(shè)備上下文用邏輯調(diào)色板中的顏色繪圖時(shí),GDI繪圖函數(shù)會(huì)查詢調(diào)色板映射表以把像素值從邏輯調(diào)色板的索引轉(zhuǎn)換成系統(tǒng)調(diào)色板的索引,這樣當(dāng)像素被輸出到視頻內(nèi)存中時(shí)就具有了正確的顏色值。圖11.2說明了這種映射關(guān)系,從圖中讀者可以體會(huì)到邏輯調(diào)色板的緩沖作用。在該圖中,GDI繪圖函數(shù)使用邏輯調(diào)色板的索引1中的顏色來繪圖,通過查詢調(diào)色板映射表,得知系統(tǒng)調(diào)色板中的第23號(hào)索引與其完全匹配,這樣實(shí)際輸出到視頻內(nèi)存中的像素值是23。注意圖中還演示了顏色的不完全匹配,即邏輯調(diào)色板中的索引15和系統(tǒng)調(diào)色板中的索引46。   每個(gè)要使用額外顏色的窗口都會(huì)實(shí)現(xiàn)自己的邏輯調(diào)色板,邏輯調(diào)色板中的每種顏色在系統(tǒng)調(diào)色板中都有相同或相近的匹配。調(diào)色板的實(shí)現(xiàn)優(yōu)先權(quán)越高,匹配的精度也就越高。Windows規(guī)定,活動(dòng)窗口的邏輯調(diào)色板(如果有的話)具有最高的實(shí)現(xiàn)優(yōu)先權(quán)。這是因?yàn)榛顒?dòng)窗口是當(dāng)前與用戶交互的窗口,應(yīng)該保證其有最佳的顏色顯示。非活動(dòng)窗口的優(yōu)先權(quán)是按Z順序自上到下確定的(Z順序就是重疊窗口的重疊順序)。活動(dòng)窗口有權(quán)將其邏輯調(diào)色板作為前景調(diào)色板實(shí)現(xiàn),非活動(dòng)窗口則只能實(shí)現(xiàn)背景調(diào)色板。

  提示:術(shù)語活動(dòng)窗口(Active window)或前臺(tái)窗口(Foreground window)是指當(dāng)前與用戶交互的窗口,活動(dòng)窗口的頂端的標(biāo)題條呈高亮顯示,而非活動(dòng)窗口的標(biāo)題條則是灰色的。活動(dòng)窗口肯定是一個(gè)頂層窗口(Top-level window),頂層窗口是指沒有父窗口或父窗口是桌面窗口的窗口,這種窗口一般都有標(biāo)題和邊框,主要包括框架窗口和對(duì)話框。術(shù)語重疊窗口是指作為應(yīng)用程序主窗口的窗口,我們可以把對(duì)話框看成是一種特殊的重疊式窗口。

  3.?調(diào)色板的創(chuàng)建和實(shí)現(xiàn) ? MFC的CPalette類對(duì)邏輯調(diào)色板進(jìn)行了封裝。該類的成員函數(shù)CreatePalette負(fù)責(zé)創(chuàng)建邏輯調(diào)色板,該函數(shù)的聲明為: BOOL CreatePalette( LPLOGPALETTE lpLogPalette ); //成功則返回TRUE。 參數(shù)lpLogPalette是一個(gè)指向LPLOGPALETTE結(jié)構(gòu)的指針,LPLOGPALETTE結(jié)構(gòu)描述了邏輯調(diào)色板的內(nèi)容,該結(jié)構(gòu)的定義為: typedef struct tagLOGPALETTE {   WORD palVersion; //Windows版本號(hào),一般是0x300   WORD palNumEntries; //調(diào)色板中顏色表項(xiàng)的數(shù)目   PALETTEENTRY palPalEntry[1]; //每個(gè)表項(xiàng)的顏色和使用方法 } LOGPALETTE;   結(jié)構(gòu)中最重要的成員是PALETTEENTRY數(shù)組,數(shù)組項(xiàng)的數(shù)目由palNumEntries成員指定。PALETTEENTRY結(jié)構(gòu)對(duì)調(diào)色板的某一個(gè)顏色表項(xiàng)進(jìn)行了描述,該結(jié)構(gòu)的定義為: typedef struct tagPALETTEENTRY { ??   BYTE peRed;   //紅色的強(qiáng)度(0~255,下同) ??   BYTE peGreen;  //綠色的強(qiáng)度 ??   BYTE peBlue;   //藍(lán)色的強(qiáng)度 ??   BYTE peFlags; } PALETTEENTRY; 成員peFlags說明了顏色表項(xiàng)的使用方法,在一般應(yīng)用時(shí)為NULL,若讀者對(duì)peFlags的詳細(xì)說明感興趣,可以查看Visual C++的聯(lián)機(jī)幫助。 可以看出,創(chuàng)建調(diào)色板的關(guān)鍵是在PALETTEENTRY數(shù)組中指定要使用的顏色。這些顏色可以是程序自己指定的特殊顏色,也可以從DIB位圖中載入。邏輯調(diào)色板的大小可根據(jù)用戶使用的顏色數(shù)來定,一般不能超過256個(gè)顏色表項(xiàng)。   CreatePalette只是創(chuàng)建了邏輯調(diào)色板,此時(shí)調(diào)色板只是一張孤立的顏色表,還不能對(duì)系統(tǒng)產(chǎn)生影響。程序必需調(diào)用CDC::SelectPalette把邏輯調(diào)色板選入到要使用它的設(shè)備上下文中,然后調(diào)用CDC::RealizePalette把邏輯調(diào)色板實(shí)現(xiàn)到系統(tǒng)調(diào)色板中。函數(shù)的聲明為: CPalette* SelectPalette( CPalette* pPalette, BOOL bForceBackground );
  該函數(shù)把指定的調(diào)色板選擇到設(shè)備上下文中。參數(shù)pPalette指向一個(gè)CPalette對(duì)象。參數(shù)bForceBackground如果是TRUE,那么被選擇的調(diào)色板總是作為背景調(diào)色板使用,如果bForceBackground是FALSE并且設(shè)備上下文是附屬于某個(gè)窗口的,那么當(dāng)窗口是活動(dòng)窗口或活動(dòng)窗口的子窗口時(shí),被選擇的調(diào)色板將作為前景調(diào)色板實(shí)現(xiàn),否則作為背景調(diào)色板實(shí)現(xiàn)。如果使用調(diào)色板的是一個(gè)內(nèi)存設(shè)備上下文,則該參數(shù)被忽略。函數(shù)返回設(shè)備上下文原來使用的調(diào)色板,若出錯(cuò)則返回NULL。 UINT RealizePalette( );
該函數(shù)把設(shè)備上下文中的邏輯調(diào)色板實(shí)現(xiàn)到系統(tǒng)調(diào)色板中。函數(shù)的返回值表明調(diào)色板映射表中有多少項(xiàng)被改變了。   如果某一個(gè)窗口要顯示特殊的顏色,那么一般應(yīng)該在處理WM_PAINT消息時(shí)實(shí)現(xiàn)自己的邏輯調(diào)色板。也就是說,在OnPaint或OnDraw函數(shù)中重繪以前,要調(diào)用SelectPalette和RealizePalette。如果窗口顯示的顏色比較重要,則在調(diào)用SelectPalette時(shí)應(yīng)該指定bForceBackground參數(shù)為FALSE。 前景調(diào)色板具有使用顏色的最高優(yōu)先級(jí),它有無條件占用系統(tǒng)調(diào)色板(20種保留顏色除外)的權(quán)力,也就是說,如果需要,前景調(diào)色板將覆蓋系統(tǒng)調(diào)色板的236個(gè)表項(xiàng),而不管這些表項(xiàng)是否正被別的窗口使用。背景調(diào)色板則無權(quán)破壞系統(tǒng)調(diào)色板中的已使用項(xiàng)。 ? 請(qǐng)讀者注意,前景調(diào)色板應(yīng)該是唯一 如果一個(gè)活動(dòng)窗口同時(shí)要實(shí)現(xiàn)幾個(gè)邏輯調(diào)色板,那么只能有一個(gè)調(diào)色板作為前景調(diào)色板實(shí)現(xiàn),也即在調(diào)用CDC::SelectPalette時(shí)只能有一個(gè)bForceBackground被指定為FALSE,其它的bForceBackground必需為TRUE。 通常是把具有輸入焦點(diǎn)的窗口的調(diào)色板作為前景調(diào)色板實(shí)現(xiàn),其它窗口只能使用背景調(diào)色板。 如果活動(dòng)窗口的子窗口全都使用前景調(diào)色板,則會(huì)導(dǎo)致程序的死循環(huán)。

  提示:請(qǐng)讀者注意區(qū)分活動(dòng)窗口和有輸入焦點(diǎn)的窗口。有輸入焦點(diǎn)的窗口要么是活動(dòng)窗口本身,要么是活動(dòng)窗口的子窗口。也就是說,活動(dòng)窗口不一定具有輸入焦點(diǎn),當(dāng)活動(dòng)窗口的子窗口獲得輸入焦點(diǎn)時(shí),活動(dòng)窗口就會(huì)失去輸入焦點(diǎn)。

  4.?使用顏色的三種方法 ?  在調(diào)用GDI函數(shù)繪圖時(shí),可以用不同的方法來選擇顏色。Windows用COLORREF數(shù)據(jù)類型來表示顏色,COLORREF型值的長(zhǎng)度是4字節(jié),其中最高位字節(jié)可以取三種不同的值,分別對(duì)應(yīng)三種使用顏色的方法。表11.1列出了這些不同的取值及其含義。   COLORREF型值的最高位字節(jié)的含義????

取值

含義

0x00

指定RGB引用。此時(shí)三個(gè)低位字節(jié)含有紅、綠、藍(lán)色的強(qiáng)度,Windows將抖動(dòng)20種保留的顏色來匹配指定的顏色,而不管程序是否實(shí)現(xiàn)了自己的調(diào)色板。

0x01

指定調(diào)色板索引引用。此時(shí)最低位字節(jié)含有邏輯調(diào)色板的索引,Windows根據(jù)該索引在邏輯調(diào)色板中找到所需的顏色。

0x02

指定調(diào)色板RGB引用。此時(shí)三個(gè)低位字節(jié)含有紅、綠、藍(lán)色的強(qiáng)度,Windows會(huì)在邏輯調(diào)色板中找到最匹配的顏色。

? 為了方便用戶的使用,Windows提供了三個(gè)宏來構(gòu)建三種不同的COLORREF數(shù)據(jù),它們是: COLORREF RGB(BYTE bRed,BYTE bGreen,BYTE bBlue); //RGB引用 COLORREF PALETTEINDEX(WORD wPaletteIndex);??? //調(diào)色板索引引用 COLORREF PALETTERGB(BYTE bRed,BYTE bGreen,?BYTE bBlue);??? //調(diào)色板RGB引用
? 例如,我們可以用上述三種方法來指定刷子的顏色: (1). 調(diào)用系統(tǒng)調(diào)色板中的紅色建立一個(gè)刷子:   CBrush brush;   brush.CreateSolidBrush(RGB(255,0,0));   pDC->SelectObject(&brush); (2). 調(diào)用邏輯調(diào)色板的索引2中的顏色來創(chuàng)建一個(gè)刷子:   pDC->SelectPalette(&m_Palette,FALSE);   pDC->RealizePalette( );   CBrush brush;   brush.CreateSolidBrush(PALETTEINDEX(2));   pDC->SelectObject(&brush); (3).調(diào)用邏輯調(diào)色板中最匹配的深灰色來創(chuàng)建一個(gè)刷子:   pDC->SelectPalette(&m_Palette,FALSE);   pDC->RealizePalette( );   CBrush brush;   brush.CreateSolidBrush(PALETTERGB(20,20,20));   pDC->SelectObject(&brush); ? 5.?與系統(tǒng)調(diào)色板有關(guān)的消息 ? ?為了協(xié)調(diào)各個(gè)窗口對(duì)系統(tǒng)調(diào)色板的使用,Windows在必要的時(shí)侯會(huì)向頂層窗口和重疊窗口發(fā)送消息WM_QUERYNEWPALETTE和WM_PALETTECHANGED。 ?當(dāng)某一頂層或重疊窗口(如主框架窗口)被激活時(shí),會(huì)收到WM_QUERYNEWPALETTE消息,在窗口創(chuàng)建之初也會(huì)收到該消息,該消息先于WM_PAINT消息到達(dá)窗口。如果活動(dòng)窗口要使用特殊的顏色,則在收到該消息時(shí)應(yīng)該實(shí)現(xiàn)自己的邏輯調(diào)色板并重繪窗口。如果窗口實(shí)現(xiàn)了邏輯調(diào)色板,那么WM_QUERYNEWPALETTE消息的處理函數(shù)應(yīng)返回TRUE。通常窗口在收到該消息后應(yīng)該為有輸入焦點(diǎn)的窗口(如視圖)實(shí)現(xiàn)前景調(diào)色板,但如果程序覺得它顯示的顏色并不重要,那么在收到該消息后可以把邏輯調(diào)色板作為背景調(diào)色板實(shí)現(xiàn)(指定CDC::SelectPalette函數(shù)的bForceBackground參數(shù)為TRUE),這樣程序就失去了使用系統(tǒng)調(diào)色板的最高優(yōu)先權(quán)。 ?當(dāng)活動(dòng)窗口實(shí)現(xiàn)其前景調(diào)色板并改變了系統(tǒng)調(diào)色板時(shí),Windows會(huì)向包括活動(dòng)窗口在內(nèi)的所有的頂層窗口和重疊窗口發(fā)送WM_PALETTECHANGED消息,在該消息的wParam參數(shù)中包含了改變系統(tǒng)調(diào)色板的窗口的句柄。其它窗口如果使用了自己的邏輯調(diào)色板,那么應(yīng)該重新實(shí)現(xiàn)其邏輯調(diào)色板,并重繪窗口。這是因?yàn)橄到y(tǒng)調(diào)色板已經(jīng)被改變了,必需重新建立調(diào)色板映射表并重繪,否則可能會(huì)顯示錯(cuò)誤的顏色。當(dāng)然,非活動(dòng)窗口只能使用背景調(diào)色板,所以顯示的顏色肯定沒有在前臺(tái)的時(shí)侯好。要注意只有在活動(dòng)窗口實(shí)現(xiàn)了前景調(diào)色板且改變了系統(tǒng)調(diào)色板時(shí),才會(huì)產(chǎn)生WM_PALETTECHANGED消息。也就是說,如果窗口在調(diào)用CDC::SelectPalette時(shí)指定bForceBackground參數(shù)為TRUE,那么是不會(huì)產(chǎn)生WM_PALETTECHANGED消息。 ?總之,WM_QUERYNEWPALETTE消息為活動(dòng)窗口提供了實(shí)現(xiàn)前景調(diào)色板的機(jī)會(huì),而WM_PALETTECHANGED消息為窗口提供了適應(yīng)系統(tǒng)調(diào)色板變化的機(jī)會(huì)。   需要指出的是,子窗口是收不到與調(diào)色板有關(guān)的消息的。因此,如果子窗口(如視圖)要使用自己的邏輯調(diào)色板,那么頂層窗口或重疊窗口應(yīng)該及時(shí)通知子窗口與調(diào)色板有關(guān)的消息。 ? 6.?具體實(shí)例   現(xiàn)在讓我們來看一個(gè)使用調(diào)色板的演示程序。該程序名為TestPal,如圖11.3所示,該程序顯示了兩組紅色方塊,每組方塊都是16×16共256個(gè)。左邊的這組方塊是用邏輯調(diào)色板畫的,紅色的強(qiáng)度從0到255遞增,作為對(duì)比,在右邊用RGB引用畫出了256個(gè)遞增的紅色方塊。讀者可以對(duì)比這兩組方塊的顏色質(zhì)量,以體會(huì)調(diào)色板索引引用和RGB引用的區(qū)別。該程序也著重向讀者演示了處理調(diào)色板消息的方法。 ?   首先,請(qǐng)讀者用AppWizard建立一個(gè)名為TestPal的MFC單文擋應(yīng)用程序。然后,用ClassWizard為CMainFrame類加入WM_QUERYNEWPALETTE和WM_PALETTECHANGED消息的處理函數(shù),使用缺省的函數(shù)名。接著,在TestPal.h文件中類CTestPalApp的定義前加入下面一行: #define WM_DOREALIZE WM_USER+200 當(dāng)收到調(diào)色板消息時(shí),主框架窗口會(huì)發(fā)送用戶定義的WM_DOREALIZE消息通知視圖。 最后,請(qǐng)讀者按清單11.1和11.2修改程序。   清單11.1 CMainFrame類的部分代碼 BOOL CMainFrame::OnQueryNewPalette() { // TODO: Add your message handler code here and/or call default   GetActiveView()->SendMessage(WM_DOREALIZE); return TRUE; //返回TRUE表明實(shí)現(xiàn)了邏輯調(diào)色板 }   void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd) { CFrameWnd::OnPaletteChanged(pFocusWnd); // TODO: Add your message handler code here   if(GetActiveView()!=pFocusWnd) GetActiveView()->SendMessage(WM_DOREALIZE); }   清單11.2 CTestPalView類的部分代碼 // TestPalView.h : interface of the CTestPalView class class CTestPalView : public CView { . . . protected:   CPalette m_Palette; . . . afx_msg LRESULT OnDoRealize(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() };   // TestPalView.cpp : implementation of the CTestPalView class   BEGIN_MESSAGE_MAP(CTestPalView, CView)   . . . ON_MESSAGE(WM_DOREALIZE, OnDoRealize) END_MESSAGE_MAP()   CTestPalView::CTestPalView() { // TODO: add construction code here   LPLOGPALETTE pLogPal; pLogPal=(LPLOGPALETTE)malloc(sizeof(LOGPALETTE)+ sizeof(PALETTEENTRY)*256); pLogPal->palVersion=0x300; pLogPal->palNumEntries=256; for(int i=0;i<256;i++) { pLogPal->palPalEntry[i].peRed=i; //初始化為紅色 pLogPal->palPalEntry[i].peGreen=0; pLogPal->palPalEntry[i].peBlue=0; pLogPal->palPalEntry[i].peFlags=0; } if(!m_Palette.CreatePalette(pLogPal)) AfxMessageBox("Can't create palette!"); }   void CTestPalView::OnDraw(CDC* pDC) { CTestPalDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);   // TODO: add draw code for native data here   CBrush brush,*pOldBrush; int x,y,i;   pDC->SelectPalette(&m_Palette,FALSE); pDC->RealizePalette(); pDC->SelectStockObject(BLACK_PEN); for(i=0;i<256;i++) { x=(i%16)*16; y=(i/16)*16; brush.CreateSolidBrush(PALETTEINDEX(i)); //調(diào)色板索引引用 pOldBrush=pDC->SelectObject(&brush); pDC->Rectangle(x,y,x+16,y+16); pDC->SelectObject(pOldBrush); brush.DeleteObject(); } for(i=0;i<256;i++) { x=(i%16)*16+300; y=(i/16)*16; brush.CreateSolidBrush(RGB(i,0,0)); //RGB引用 pOldBrush=pDC->SelectObject(&brush); pDC->Rectangle(x,y,x+16,y+16); pDC->SelectObject(pOldBrush); brush.DeleteObject(); } }     LRESULT CTestPalView::OnDoRealize(WPARAM wParam, LPARAM) { CClientDC dc(this); dc.SelectPalette(&m_Palette,FALSE); if(dc.RealizePalette()) //若調(diào)色板映射被改變則刷新視圖 GetDocument()->UpdateAllViews(NULL); return 0L; }   在CTestPalView的構(gòu)造函數(shù)中創(chuàng)建了一個(gè)含有256個(gè)遞增紅色的邏輯調(diào)色板。   當(dāng)變?yōu)榛顒?dòng)窗口以及窗口創(chuàng)建時(shí),TestPal程序的主框架窗口都會(huì)收到WM_QUERYNEWPALETTE消息,該消息的處理函數(shù)OnQueryNewPalette負(fù)責(zé)發(fā)送WM_DOREALIZE消息通知視圖, 并返回TRUE以表明活動(dòng)窗口實(shí)現(xiàn)了邏輯調(diào)色板。WM_DOREALIZE消息的處理函數(shù)CTestPalView::OnDoRealize為視圖實(shí)現(xiàn)一個(gè)前景調(diào)色板,該函數(shù)中有一個(gè)判斷語句可提高程序運(yùn)行的效率:如果CDC::RealizePalette返回值大于零,則說明調(diào)色板映射表發(fā)生了變化,此時(shí)必須刷新視圖,否則制圖中的顏色將失真。如果RealizePalette返回零則說明調(diào)色板映射沒有變化,這時(shí)就沒有必要刷新視圖。   無論是TestPal還是別的應(yīng)用程序在實(shí)現(xiàn)前景調(diào)色板并改變了系統(tǒng)調(diào)色板時(shí),TestPal程序的主框架窗口都會(huì)收到WM_PALETTECHANGED消息。請(qǐng)注意該消息的處理函數(shù)CMainFrame::OnPaletteChanged有一個(gè)pFocusWnd參數(shù),該參數(shù)表明是哪一個(gè)窗口改變了系統(tǒng)調(diào)色板。函數(shù)用pFocusWnd來判斷,如果是別的應(yīng)用程序?qū)崿F(xiàn)了前景調(diào)色板,則通知視圖調(diào)用OnDoRealize實(shí)現(xiàn)其邏輯調(diào)色板,注意雖然CDC::SelectPalette的bForceBackground參數(shù)是FALSE,但這時(shí)視圖的邏輯調(diào)色板是作為背景調(diào)色板實(shí)現(xiàn)的。如果是TestPal自己的視圖實(shí)現(xiàn)了前景調(diào)色板,則沒有必要調(diào)用OnDoRealize。   請(qǐng)讀者將Windows當(dāng)前的顯示模式設(shè)置為256色,然后編譯并運(yùn)行TestPal,對(duì)比一下RGB引用與調(diào)色板索引引用的效果,讀者不難發(fā)現(xiàn)左邊用調(diào)色板索引引用輸出的顏色比右邊好的多。通過該程序我們可以看出,即使在系統(tǒng)調(diào)色板中已實(shí)現(xiàn)了豐富的紅色的情況下,RGB引用得到的紅色仍然是20種保留顏色的抖動(dòng)色。   讀者可以打開Windows的畫筆程序,并在該程序中打開一幅256色的位圖(如Windows目錄下的Forest.bmp)。在畫筆和TestPal程序之間來回切換,讀者可以看到,由于兩個(gè)應(yīng)用程序都正確的處理了調(diào)色板消息,在前臺(tái)的應(yīng)用程序總是具有最好的顏色顯示,而后臺(tái)程序的顏色雖然有些失真,但還比較令人滿意。   需要指出的是,TestPal程序只使用了一個(gè)邏輯調(diào)色板,所以它處理調(diào)色板消息的方法比較簡(jiǎn)單。如果程序要用到多個(gè)邏輯調(diào)色板,那么就需要采取一些新措施來保證只有一個(gè)邏輯調(diào)色板作為前景調(diào)色板使用。在11.4節(jié)讀者可以看到使用多個(gè)邏輯調(diào)色板時(shí)的處理方法。

總結(jié)

以上是生活随笔為你收集整理的调色板原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。