首页 > 代码库 > 第二章:图像的显示 和运行完整程序代码

第二章:图像的显示 和运行完整程序代码

VC++图像处理程序设计(第2版)    杨淑莹 编著     边奠英 主审
第二章 图像的显示
Joanna-In-Hdu 手工打,印象更深刻
使用工具 VS2010 mfc
 

颜色表中装有该文件所有颜色的R、G、B各分量,每个像素的像素值是颜色索引表的索引号。

通常所称的VGA显示模式是8位显示模式,能显示256种颜色,即0~255进行编号,每一个编号对应一种颜色,颜色的编号就是颜色的索引号。

屏幕上的每一个像素对应一个颜色号,不同像素的颜色对应不同的调色板颜色值。图像的像素值并不是颜色值,而是颜色在调色板查找表中的索引号。

在调色板系统中,每一幅图像都有自己的调色板,显示时必须将自己的调色板载入系统调色板中,实现调色板。

调色板原理:

Windows的调色板管理十分复杂,每一个Windows应用程序都有自己的调色板,在使用调色板时首先要向Wiindows提出申请,Windows根据该应用程序的优先级,来对程序调色板进行分配,一个优先级高(活动窗口,当前正在进行交互操作的,其他都是非活动窗口)的应用程序可以得到Windows的前台调色板,其他的窗口使用后台调色板。

为了保证Windows基本显示界面的一致性,Windows保留了一个有20种颜色的内部系统调色板,用来描绘窗口的图标、边界、按钮等通用界面。该调色板在所有的显示设备中都爆出不变。

每个设备上下文都拥有一个逻辑调色板,如果要使用内部系统调色板之外的颜色,应该创建一个新的逻辑调色板并将其选入设备上下文中。但仅仅这样还不能使用新的颜色,程序只有把设备上下文中的逻辑调色板实现到系统调色板中,新的颜色才能实现。在逻辑调色板被实现到系统调色板时,Wiindows会建立以调色板映射表。当设备上下文用逻辑调色板中的颜色绘图时,GDI绘图函数会查新调色板映射表以把像素值从逻辑调色板的索引转化为系统调色板的索引,这样像素就被输出到视频内存中就具有了正确的颜色值。

建议同步参考链接,有互补的内容:http://blog.csdn.net/hi_dzj/article/details/6226234

调色板的创建与实现:

在Windows中使用了专门的 调色板管理器对调色板进行管理,对逻辑调色板和系统调色板之间的影射进行操作。在使用VC++进行Windows的应用程序设计时,MFC基本类库提供了CDC类和CPalette类,封装了有关调色板的操作,使调色板的操作得以简化。该类的成员函数CreatePalette负责创建逻辑调色板。

一般创建一个逻辑调色板需要5步:

(1)建立一个LOGPALETTE结构和PALETTEENTRY数组;

(2)对数组元素进行初始化并对成员变量进行设置;

(3)建立CPalette对象并使用CreatePalette函数初始化调色板对象;

(4)使用SelectPalette函数来将设备描述表和调色板联系起来;

(5)使用CDC中的RealezePalette函数使调色板生效。

程序建立:

我的程序运行效果界面,这是打开了一个图片后显示的结果:

技术分享

步骤:1、新建一个基于对话框的mfc工程,参考链接:http://www.jizhuomi.com/software/149.html

这里我的工程是:MfcPictureProcessing

然后先介绍MfcPictureProcessingDlg.h文件里的函数,4个标注1的都是我添加的,2是在界面菜单里添加了一个打开按钮后自动生成的:

技术分享

2、在MfcPictureProcessingDlg.h里添加好上图中4个1标注的这4个变量,其中第一个class CDib是强制声明,否则编译器老是不能识别出CDib是个我写的类;

3、在MfcPictureProcessingDlg.cpp中编写上图中第4个1所标注的两个函数;

4、在主对话框中新建一个Menu,第三个1所指的m_Menu变量就是Menu菜单对应的变量;参考链接:http://www.jizhuomi.com/software/210.html和http://www.jizhuomi.com/software/212.html

技术分享

 下面贴出完整运行代码,我不懂的基本上都在后面有些注释,不对的地方希望大家多多指正~:

 1 // MfcPictureProcessingDlg.h : 头文件
 2 //
 3 
 4 #pragma once
 5 
 6 class CDib;
 7 
 8 // CMfcPictureProcessingDlg 对话框
 9 class CMfcPictureProcessingDlg : public CDialogEx
10 {
11 public:
12     
13     CPalette *hPalette;//这两个变量都是指针,为什么不是实体类呢?假如程序一次运行只打开一次文件,类是可以的;多次打开会出现内存错误(大家可以试一下),指针的话,没打开一次都是新建一个类,打开完了即没了,适合用指针
14     CDib *dib;
15     
16     CMenu m_Menu;
17 
18     void OnDraw(CDC* pDC);//CDC类是设备上下文类,用于绘图输出的
19     CPalette* CreateBitmapPalette(CDib *pBitmap);
20 #pragma region 这里面都是系统自己生成的,我没动
21 // 构造
22 public:
23     CMfcPictureProcessingDlg(CWnd* pParent = NULL);    // 标准构造函数
24     
25 // 对话框数据
26     enum { IDD = IDD_MFCPICTUREPROCESSING_DIALOG };
27     
28     
29 
30 protected:
31 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
32 
33 
34 // 实现
35 protected:
36     HICON m_hIcon;
37 
38     // 生成的消息映射函数
39     virtual BOOL OnInitDialog();
40     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
41     afx_msg void OnPaint();
42     afx_msg HCURSOR OnQueryDragIcon();
43 
44     DECLARE_MESSAGE_MAP()
45 #pragma endregion
46 public:
47     afx_msg void On32771();//这就是菜单栏的打开文件按钮的函数
48 };
  1 // MfcPictureProcessingDlg.cpp : 实现文件
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "MfcPictureProcessing.h"
  6 #include "MfcPictureProcessingDlg.h"
  7 
  8 #include "afxdialogex.h"
  9 #include "CDib.h" 
 10 
 11 #ifdef _DEBUG
 12 #define new DEBUG_NEW
 13 #endif
 14 
 15 
 16 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 17 
 18 class CAboutDlg : public CDialogEx
 19 {
 20 public:
 21     CAboutDlg();
 22 
 23 // 对话框数据
 24     enum { IDD = IDD_ABOUTBOX };
 25 
 26     protected:
 27     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
 28 
 29 // 实现
 30 protected:
 31     DECLARE_MESSAGE_MAP()
 32 };
 33 
 34 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
 35 {
 36 }
 37 
 38 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
 39 {
 40     CDialogEx::DoDataExchange(pDX);
 41 }
 42 
 43 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
 44 END_MESSAGE_MAP()
 45 
 46 
 47 // CMfcPictureProcessingDlg 对话框
 48 
 49 
 50 
 51 
 52 CMfcPictureProcessingDlg::CMfcPictureProcessingDlg(CWnd* pParent /*=NULL*/)
 53     : CDialogEx(CMfcPictureProcessingDlg::IDD, pParent)
 54 {
 55     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 56     
 57 }
 58 
 59 void CMfcPictureProcessingDlg::DoDataExchange(CDataExchange* pDX)
 60 {
 61     CDialogEx::DoDataExchange(pDX);
 62 }
 63 
 64 BEGIN_MESSAGE_MAP(CMfcPictureProcessingDlg, CDialogEx)//消息映射入口项
 65     ON_WM_SYSCOMMAND()
 66     ON_WM_PAINT()
 67     ON_WM_QUERYDRAGICON()
 68     ON_COMMAND(ID_32771, &CMfcPictureProcessingDlg::On32771)
 69 END_MESSAGE_MAP()
 70 
 71 
 72 // CMfcPictureProcessingDlg 消息处理程序
 73 
 74 BOOL CMfcPictureProcessingDlg::OnInitDialog()
 75 {
 76     CDialogEx::OnInitDialog();
 77 
 78     // 将“关于...”菜单项添加到系统菜单中。
 79     m_Menu.LoadMenuW(IDR_MENU1);//添加菜单
 80     SetMenu(&m_Menu);
 81 
 82     // IDM_ABOUTBOX 必须在系统命令范围内。
 83     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 84     ASSERT(IDM_ABOUTBOX < 0xF000);
 85 
 86     CMenu* pSysMenu = GetSystemMenu(FALSE);
 87     if (pSysMenu != NULL)
 88     {
 89         BOOL bNameValid;
 90         CString strAboutMenu;
 91         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
 92         ASSERT(bNameValid);
 93         if (!strAboutMenu.IsEmpty())
 94         {
 95             pSysMenu->AppendMenu(MF_SEPARATOR);
 96             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 97         }
 98     }
 99 
100     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
101     //  执行此操作
102     SetIcon(m_hIcon, TRUE);            // 设置大图标
103     SetIcon(m_hIcon, FALSE);        // 设置小图标
104 
105     // TODO: 在此添加额外的初始化代码
106 
107     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
108 }
109 
110 void CMfcPictureProcessingDlg::OnSysCommand(UINT nID, LPARAM lParam)
111 {
112     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
113     {
114         CAboutDlg dlgAbout;
115         dlgAbout.DoModal();
116     }
117     else
118     {
119         CDialogEx::OnSysCommand(nID, lParam);
120     }
121 }
122 
123 // 如果向对话框添加最小化按钮,则需要下面的代码
124 //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
125 //  这将由框架自动完成。
126 
127 void CMfcPictureProcessingDlg::OnPaint()
128 {
129     if (IsIconic())
130     {
131         CPaintDC dc(this); // 用于绘制的设备上下文
132 
133         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
134 
135         // 使图标在工作区矩形中居中
136         int cxIcon = GetSystemMetrics(SM_CXICON);
137         int cyIcon = GetSystemMetrics(SM_CYICON);
138         CRect rect;
139         GetClientRect(&rect);
140         int x = (rect.Width() - cxIcon + 1) / 2;
141         int y = (rect.Height() - cyIcon + 1) / 2;
142 
143         // 绘制图标
144         dc.DrawIcon(x, y, m_hIcon);
145     }
146     else
147     {
148         CDialogEx::OnPaint();
149     }
150 }
151 
152 //当用户拖动最小化窗口时系统调用此函数取得光标
153 //显示。
154 HCURSOR CMfcPictureProcessingDlg::OnQueryDragIcon()
155 {
156     return static_cast<HCURSOR>(m_hIcon);
157 }
158 //开始书本上加的函数
159 
160 //下面两个函数才是我加上的函数
161 CPalette* CMfcPictureProcessingDlg::CreateBitmapPalette(CDib* pBitmap) 162 { 163 struct mPalette//这里加上名字 164 { 165 WORD Version; 166 WORD NumberOfEntries; 167 PALETTEENTRY aEntries[256];//PALETTEENTRY指向一个逻辑调色板 168 }palette={0x300,256};//version是0x300 169 170 LPRGBQUAD pRGBTable=pBitmap->GetRGB();//LPRGBQUAD是调色板指针,只有前面是LP的都是指针 171 UINT numberOfColors=pBitmap->GetNumberOfColors(); 172 for(UINT x=0;x<numberOfColors;++x) 173 { 174 palette.aEntries[x].peRed=pRGBTable[x].rgbRed;//这是第二步,对数组元素和成员变量进行设置 175 palette.aEntries[x].peGreen=pRGBTable[x].rgbGreen; 176 palette.aEntries[x].peBlue=pRGBTable[x].rgbBlue; 177 palette.aEntries[x].peFlags=0;//指定调色板如何使用:PC_EXPLICIT(2) PC_NOCOLLAPSE(4) PC_RESERVED(1) 178 } 179 hPalette=new CPalette; 180 hPalette->CreatePalette((LPLOGPALETTE)&palette);//初始化调色板对象, 181 return hPalette; 182 } 183 184 void CMfcPictureProcessingDlg::OnDraw(CDC* pDC) 185 { 186 int m_scale=1;//控制缩放比例 187 BYTE* pBitmapData=http://www.mamicode.com/dib->GetData();"color: #008080">188 LPBITMAPINFO pBitmapInfo=dib->GetInfo(); 189 int bitmapHeight=dib->GetHeight(); 190 int bitmapWidth=dib->GetWidth(); 191 int scaledWidth=(int)(bitmapWidth* m_scale); 192 int scaledHeight=(int)(bitmapHeight* m_scale); 193 if(dib->GetRGB()) 194 { 195 CPalette* hPalette=CreateBitmapPalette(dib);//建立CPlalette对象并初始化调色板对象 196 CPalette* hOldPalette=pDC->SelectPalette(hPalette,true);//为true表示后台调色板,将已创建的调色板调用到设备上下文中 197 //上面这个SelectPalette返回的就是老的调色板 198 pDC->RealizePalette();//使调色板生效 199 //前面加::表面调用的是win api,是全局函数,不是局部继承的函数 200 ::StretchDIBits(pDC->GetSafeHdc(),0,0,scaledWidth,scaledHeight,0,0,bitmapWidth,bitmapHeight,pBitmapData,pBitmapInfo,DIB_RGB_COLORS,SRCCOPY); 201 //设备上下文句柄 202 pDC->SelectPalette(hOldPalette,true); 203 ::DeleteObject(hPalette);//释放关于hPalette调色板的一切资源 204 } 205 else//24位真彩色 206 { 207 ::StretchDIBits(pDC->GetSafeHdc(),0,0,scaledWidth,scaledHeight,0,0,bitmapWidth,bitmapHeight,pBitmapData,pBitmapInfo,DIB_RGB_COLORS,SRCCOPY); 208 } 209 210 } 211 212 213 void CMfcPictureProcessingDlg::On32771()//打开文件菜单 214 { 215 // TODO: Add your command handler code here 216 //MessageBox(_T("这不是位图文件!"));//_T使支持unincode编码 217 TCHAR szFilter[]=_T("所有文件(*.*)|*.*||");//设置过滤器 218 CFileDialog fileDlg(TRUE,NULL,NULL,0,szFilter,this);//这是一个文件打开对话框 219 CString strFilePath; 220 if(IDOK==fileDlg.DoModal()) 221 { 222 //const char* filename=(LPSTR)(LPCTSTR)fileDlg.GetPathName(); 223 //MessageBox(fileDlg.GetPathName()); 224 dib=new CDib;//初始化一个类指针 225 //memset(dib,0,sizeof(CDib));//不行,有中断出现 226 227 dib->LoadFile(fileDlg.GetPathName()); 228 CDC aCDC();//新建一个CDC类,并且调用显示函数 229 CDC *pDC=GetDC();//这里也是我自己想的 230 OnDraw(pDC); 231 232 } 233 }

技术分享

第二章:图像的显示 和运行完整程序代码