VC++图像处理程序设计(第1版)    杨淑莹 编著     边奠英 主审
第一章 位图基础
Joanna-In-Hdu&Hust 手工打,印象更深刻
使用工具 VS2010 mfc
 整本书的代码文件、测试图片和程序运行exe请在这里下载https://github.com/CaptainLYN/VCPictureProcessing
 
图形是矢量,显式地表示图画内容坐标值;图像是位图,适于表现大量细节,一般需要压缩。
 
红、绿、蓝,简称RGB三原色。每一个点都是由RGB三个分量的颜色来共同决定。
分辨率:单位长度内的像素数,单位是每英寸的点数DPI(dots per inch)。
图像分辨率是实际精度,显示分辨率是表现精度。
 
单色图像:0表示黑,1表示白。
灰度图像:带有颜色表,共256项,RGB三分量值相同;每个像素由8位组成,0~255,每个图像的的f(x,y)是颜色表的表项入口。
伪彩色图像:RGB三分量不全相等;像素8位,每个像素的像素值表示的不是颜色分量而是颜色表的表项入口,整个图像只有256种颜色。
24位真彩色:不带有颜色表;RGB三分量各占8位,0~255,,所以每个像素是24位,像素值就是颜色值;从左到右存储蓝、绿、红颜色值。
 
位图:位数据以行为单位存储,每行长度为4字节倍数,不足补0;
位图行的存储次序是颠倒的,即第一行对应位图最底行。
位图文件头结构 BITMAPFILEHEADER
位图信息头结构 BITMAPINFOHEADER
位图颜色表 RGBQUAD
位图像素数据
 
位图文件头:
 typedef struct tagBITMAPFILEHEADER
{
WORD bftype;//位图文件的类型,必须为BMP,0x4d42
DWORD bfsize;//位图文件的大小,以字节为单位
WORD bfReaserved1;//位图文件保留字,必须为0
WORD bfReaserved2;//位图文件保留字,必须为0
DWORD bfOffBits;//位图数据的起始位置,相对于位图文件头的偏移量表示,以字节为单位
}BITMAPFILEHEADER;
位图信息头:
 typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;//本结构所占用字节数
LONG biWidth;//位图的宽度,以像素为单位
LONG biHeight;//位图的高度,以像素为单位
WORD biPlanes;//目标设备的级别,必须为1
WORD biBitCount;//每个像素所需的位数,1、4、8、24
DWORD biCompression;/*位图压缩类型,必须为0(不压缩)、1(BI_RLE8压缩类型)、2(BI_RLE4压缩类型)之一*/
DWORD biSizeImage;//位图的大小,以字节为单位
LONG biXPelsPerMeter;//位图水平分辨率,每米像素数
LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数
DWORD biClrUsed;//位图实际使用的颜色表的颜色数
DWORD biClrImportant;//位图显示过程中重要的颜色数
}BITMAPINFOHEADER;
颜色表:
 typedef struct tagRGBQUAD
{
BYTE rgbBlue;//蓝色的亮度(0~255)
BYTE rgbGreen;//绿色
BYTE rgbRed;//红色
BYTE rgbReserved;//保留,必须为0
}RGBQUAD;
颜色表中RGBQUAD结构数据的个数由biBitCount来确定:biBitCount=1,4,8时,分别有2,16,256个表项;biBitCount=24时,没有表项。
 
typedef是用后面代替前面,define是前面代替后面。
 
接下来是CDib.h的代码:
 /*
#ifndef _CDIB_H_ //代表这个头文件里的变量只编译一次
#define _CDIB_H_
*/
#pragma once class CDib:public CObject
{
public:
RGBQUAD* m_pRGB;//颜色表指针
BYTE* m_pData,*m_pData2;//m_pData指向原数据,m_pData2指向灰度数据
UINT m_numberOfColors;//位图颜色数目
BOOL m_valid;//是否载入了位图文件
BITMAPFILEHEADER bitmapFileHeader;//位图文件头 BITMAPINFOHEADER* m_pBitmapInfoHeader;//位图信息头
BITMAPINFO* m_pBitmapInfo;//位图信息指针
int byBitCount;
DWORD dwWidthBytes;//DWORD 就是Double Word,4个字节,32位,位图的宽度字节数
BYTE* pDib;//文件中位图总数据指针,也就是读入内存所以数据的第一个
DWORD size;//位图总数据的长度 public:
CDib();
~CDib(); char m_fileName[];//文件名
char* GetFileName();
BOOL IsValid();//是否载入了位图文件
DWORD GetSize();
UINT GetWidth();
UINT GetHeight();
UINT GetNumberOfColors();
RGBQUAD* GetRGB();//获取颜色表指针
BYTE* GetData();
BYTE* GetData2();
DWORD GetDibWidthBytes();
BITMAPINFO* GetInfo();//获取位图信息结构的指针
WORD PaletteSize(LPBYTE IpDIB);//位图指针指向的位图调色板的大小
WORD DIBNumColors(LPBYTE IpDIB);//。。。。。。颜色的数目
void SaveFile(const CString filename);
//DWORD GetFilesize();
public:
void GradetoRGB();
void RGBtoGrade();
void LoadFile(CString dibFileName);
}; //#endif

然后是DIB.cpp实现文件:

 #include"stdafx.h"
#include"CDib.h"
#include<WindowsX.h>
#define WIDTHBYTES(bits) (((bits)+31)/32*4) //用前面一个代替后面的
CDib::CDib()
{ }
CDib::~CDib()
{
GlobalFreePtr(m_pBitmapInfo);//释放在loadfile函数中在堆中申请的资源
}
void CDib::LoadFile(CString m_filename)//静态不允许修改
{
//strcpy(m_fileName,dibFileName);
CFile dibFile(m_filename,CFile::modeRead);//构造函数初始化,制度打开文件,LPCTSTR就是const char*,unicode通用字符集
dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
if(bitmapFileHeader.bfType==0x4d42)//位图文件的类型,就是十进制19778
{
DWORD fileLength=dibFile.GetLength();
/*DWORD*/ size=fileLength-sizeof(BITMAPFILEHEADER);//图像内容的实际大小+颜色表+位图文件信息头
/*BYTE**/ pDib=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size);//从堆中分配属性为GMEM_MOVEABLE(win32平台和GMEM_FIXED固定的已经没有大区别)、size大小的可移动内存
dibFile.Read((void*)pDib,size);//从上述关联的文件中读取size大小的数据放入指针缓冲区,每读一次读取指针的位置移动size大小,文件头已经读取过了,这是包含信息头的数据
dibFile.Close(); m_pBitmapInfo=(BITMAPINFO*)pDib;//现在它指向的就是位图信息,也是位图信息的第一个成员的位置
m_pBitmapInfoHeader=(BITMAPINFOHEADER*)pDib;
m_pRGB=(RGBQUAD*)(pDib+m_pBitmapInfoHeader->biSize);//指向颜色表
int m_numberOfColors=GetNumberOfColors();//2、16、256或者是真彩色
if(m_pBitmapInfoHeader->biClrUsed==)//位图实际使用的颜色表中的颜色数是不对的,就修改
m_pBitmapInfoHeader->biClrUsed=m_numberOfColors;
DWORD colorTableSize=m_numberOfColors*sizeof(RGBQUAD);//调色板的大小
m_pData=pDib+m_pBitmapInfoHeader->biSize+colorTableSize;//颜色数据的真正起始位置
if(m_pRGB==(RGBQUAD*)m_pData)//如果没有调色板
m_pRGB=NULL;
m_pBitmapInfoHeader->biSizeImage=GetSize();//位图的大小,以字节为单位
m_valid=TRUE;
}
else
{
m_valid=FALSE;
MessageBox(NULL,_T("这不是位图文件!"),_T("提示"),MB_OK);//这里做了修改,关于书
}
} BOOL CDib::IsValid()
{
return m_valid;
} char*CDib::GetFileName()
{
return m_fileName;
} UINT CDib::GetWidth()
{
return (UINT)m_pBitmapInfoHeader->biWidth;
} UINT CDib::GetHeight()
{
return (UINT)m_pBitmapInfoHeader->biHeight;
} DWORD CDib::GetSize()
{
if(m_pBitmapInfoHeader->biSizeImage!=)//位图的大小
return m_pBitmapInfoHeader->biSizeImage;
else
{//不对就自己计算
DWORD height=(DWORD)GetHeight();
DWORD width=(DWORD)GetWidth();
return height*/*width */GetDibWidthBytes();
}
} //返回行字节数
DWORD CDib::GetDibWidthBytes()
{
byBitCount=m_pBitmapInfoHeader->biBitCount;//每个像素所需的位数:1、4、8、真彩色
LONG nWidth=m_pBitmapInfoHeader->biWidth;//位图的宽度,以像素为单位 dwWidthBytes=(DWORD)m_pBitmapInfoHeader->biWidth;//位图的宽度字节数
if(byBitCount==) dwWidthBytes=(nWidth+)/;//一位像素,那按字节计算就应该除8
else if(byBitCount==) dwWidthBytes=(nWidth+)/;
else if(byBitCount==) dwWidthBytes=nWidth*;//因为真彩色每个像素是24位 while((dwWidthBytes&)!=) dwWidthBytes++;//是否为4的倍数,因为位图每行为4的倍数,不足补0 return dwWidthBytes;
} //返回位图颜色数目
UINT CDib::GetNumberOfColors()
{
int numberOfColors; if((m_pBitmapInfoHeader->biClrUsed==)&&(m_pBitmapInfoHeader->biBitCount<))
{
switch(m_pBitmapInfoHeader->biBitCount)
{
case :numberOfColors=;break;
case :numberOfColors=;break;
case :numberOfColors=;
}
}
else
numberOfColors=(int)m_pBitmapInfoHeader->biClrUsed;//如果是真彩色,就是实际使用的颜色
return numberOfColors;
} BYTE* CDib::GetData()
{
return m_pData;
} BYTE* CDib::GetData2()
{
if(GetRGB())
m_pData2=m_pData;//有颜色表的情况下两个相同
return m_pData2;
} RGBQUAD* CDib::GetRGB()
{
return m_pRGB;
} BITMAPINFO* CDib::GetInfo()
{
return m_pBitmapInfo;//位图信息指针
} WORD CDib::PaletteSize(LPBYTE lpDIB)//LPBYTE是BYTE指针
{
return (DIBNumColors(lpDIB)*sizeof(RGBQUAD/*RGBTRIPLE*/));//位图指针指向的颜色的数目*每一个颜色的大小,颜色表的位总大小
} //应该是返回颜色表中的数据项数
WORD CDib::DIBNumColors(LPBYTE lpDIB)
{
WORD wBitCount;//设备无关图的位数
//wBitCount=((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;//每个颜色的位数
wBitCount=((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
switch(wBitCount)
{
case :return ;
case :return ;
case :return ;
default:return ;
}
} void CDib::SaveFile(const CString filename)
{
BITMAPFILEHEADER bmfHdr;
LPBITMAPINFOHEADER lpBI;
DWORD dwDIBSize; bmfHdr.bfType=0x4d42;//"BM"
lpBI=(LPBITMAPINFOHEADER)m_pBitmapInfoHeader; dwDIBSize=*(LPDWORD)lpBI+PaletteSize((LPBYTE)lpBI);//位图数据和信息头+颜色表的位大小,这里只有后两部分
// 本结构所占用字节数
if((lpBI->biCompression==BI_RLE8)||(lpBI->biCompression==BI_RLE4))
dwDIBSize+=lpBI->biSizeImage;//位图的大小字节
else
{
DWORD dwBmBitSize;//只表示位图的位的大小
dwBmBitSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))*lpBI->biHeight;//宽度的字节数*高度
dwDIBSize+=dwBmBitSize;
lpBI->biSizeImage=dwBmBitSize;//位图数据大小的字节数
}
bmfHdr.bfSize=dwDIBSize+sizeof(BITMAPFILEHEADER);//位图文件的大小,指的是整个文件
bmfHdr.bfReserved1=;
bmfHdr.bfReserved2=;
bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+lpBI->biSize+PaletteSize((LPBYTE)lpBI); CFile dibFile(filename,CFile::modeWrite|CFile::modeCreate);//|是位或,CFile::modeWrite|CFile::modeCreate??????
dibFile.Write(&bmfHdr,sizeof(BITMAPFILEHEADER));//这里必须要写两次,但是不知道为什么
dibFile.Write(lpBI,dwDIBSize);
dibFile.Close();
} //rgb转成灰度图
void CDib::RGBtoGrade()
{
if(GetRGB())//如果有颜色表,即不是真彩色24位
m_pData2=m_pData;//颜色组号就是颜色,rgb相等
else
{
BYTE r,g,b;
int height,wide,size;
height=GetHeight();
wide=GetWidth();
size=height*wide;
m_pData2=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size);
LONG lLineBytes=GetDibWidthBytes();
for(int j=;j<height;j++)
{
for(int i=;i<wide;i++)
{
b=m_pData[j*lLineBytes+*i];
g=m_pData[j*lLineBytes+*i+];
r=m_pData[j*lLineBytes+*i+];
m_pData2[j*wide+i]=(BYTE)(0.3*r+0.59*g+0.11*b);//wide是像素,一个像素是24位,所以三个rgb映射一个像素值,rgb给予不同的权重,一个值就代表了rgb三个值,因为是灰度图
}
}
}
} //灰度图转为rgb
void CDib::GradetoRGB()
{
if(GetRGB())
m_pData=m_pData2;//反正rgb相等就是了
else
{
//BYTE r,g,b;
int height,wide;
height=GetHeight();
wide=GetWidth();
LONG lLineBytes=GetDibWidthBytes();
for(int j=;j<height;j++)
{
for(int i=;i<wide;i++)//将一个灰度值赋值给三个rgb,从最后一行开始,从一开始应该也是一样的
{
m_pData[(height-j-)*lLineBytes+*i]=m_pData2[(height--j)*wide+i];
m_pData[(height-j-)*lLineBytes+*i+]=m_pData2[(height--j)*wide+i];
m_pData[(height-j-)*lLineBytes+*i+]=m_pData2[(height--j)*wide+i];
}
}
}
}

(上述代码已进行更新)

代码中的部分函数,不如灰度转换,没有用过,所以不确定是否能正确使用,但是绝大部分函数用过都是可以正确运行的。

现在给出一个测试的调用实例:

1、建立一个菜单,并在mfc的程序中实现这个菜单,如图:

2、在对话框类中建立一个变量,用于保存文件的路径:

 class CMfcPictureProcessingDlg : public CDialogEx
{ CMenu m_Menu;
CString filePath;//就是这个
。。。。。
};

3、对1中的菜单项“打开”,新建事件处理函数,到对话框类cpp文件中:

 void CMfcPictureProcessingDlg::On32771()//打开文件菜单
{
TCHAR szFilter[]=_T("所有文件(*.*)|*.*||");//设置过滤器
CFileDialog fileDlg(TRUE,NULL,NULL,,szFilter,this);//这是一个文件打开对话框
if(IDOK==fileDlg.DoModal())
{
GetFilePath(fileDlg.GetPathName()); CDib dib;//初始化一个类指针
//memset(dib,0,sizeof(CDib));//不行,有中断出现
dib.LoadFile(filePath);
if(dib.m_valid)//很重要,要记得判断
{
CDC *pDC=GetDC();
CViewImage imageview;//这是第二章的显示函数,可以不写
imageview.GetDib(&dib);//我给它加了一个函数,用于获取dib
imageview.OnDraw(pDC);
}
}
}

4、为菜单中的“保存”,添加事件处理函数:

 void CMfcPictureProcessingDlg::On32799()//保存文件
{
CDib dib;
dib.LoadFile(filePath);
if(dib.m_valid)
{
//------------------------
CDC* pDC=GetDC();
JHBHDib jdib;
jdib.GetDib(&dib);
jdib.JingXiang(false);
CViewImage imageview;
imageview.GetDib(&dib);
imageview.OnDraw2(pDC,dib.GetWidth()+,);
//这之间是我随便选的一个第三章的处理函数,也可以将这部分去掉,先试试是否能直接保存图片
//-------------------------
dib.SaveFile(_T("wod.bmp"));
//delete((BYTE*)dib.GetInfo());//不需要再释放了,释放函数在析构函数中
}
}

5、程序开启,试试效果:

(1)菜单中的“打开”:

(2)菜单中的保存:

(3)工程文件夹:

进去找到我们的图片,我取名是“wod.bmp”:

打开图片:

//-----------------------------------------------------------------结束

零零散散敲了两天真是酸爽啊,自己敲才能知道哪里不会~

  

http://blog.csdn.net/mad1989/article/details/7920173 讲#ifndef、头文件变量在cpp中重复定义
“其实并不难,是你太悲观。”看到了这样一句鸡汤,很对。(其实就是链接内博客的名字)

第一章:CDib类库的建立的更多相关文章

  1. 第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现

    第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现 开发环境搭建 使用自己的AppID新建小程序项目,后端服务选择小程序·云开发,点击新建,完成项目新建. 新建成功后跳转到开发者工具界面 ...

  2. 第一章ASP.NET SignalR简介

    第一章ASP.NET SignalR简介 1.1概述: ASP.NET SignalR是微软新开发的类库,为的是帮助ASP.NET开发人员很方便地开发实时网络功能. SignalR允许服务器端和客户端 ...

  3. OpenGL笔记<第一章> 构建 GLSL class

    恭喜,我们终于很扎实地完成了第一章——glsl 入门 不幸的是,it's not the basic of GLSL shader ,我们下一节开篇,basic of GLSL shader 在下一章 ...

  4. 16第一章 ASP.Net编程基础知识

    第一章        ASP.Net编程基础知识 第一章        ASP.Net编程基础知识 本章首先介绍用ASP.Net技术编制服务器端动态网页所需的网络和HTML标记语言方面的有关知识.然后 ...

  5. ASM学习笔记--ASM 4 user guide 第一章翻译

    ASM是什么? 借用别人的话 :ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能. ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机 ...

  6. 虚拟机--第一章走进java--(抄书)

    这是本人阅读周志明老师的<深入理解Java虚拟机>第二版抄写的,有很多省略,不适合直接阅读,需要阅读请出门左转淘宝,右转京东,支持周老师(侵权请联系删除) 第一章走近java 世界上并没有 ...

  7. 【读书笔记】《编程珠玑》第一章之位向量&位图

    此书的叙述模式是借由一个具体问题来引出的一系列算法,数据结构等等方面的技巧性策略.共分三篇,基础,性能,应用.每篇涵盖数章,章内案例都非常切实棘手,解说也生动有趣. 自个呢也是头一次接触编程技巧类的书 ...

  8. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  9. Asp.Net MVC4 + Oracle + EasyUI 学习 第一章

    Asp.Net MVC4 + Oracle + EasyUI  第一章 --操作数据和验证 本文链接:http://www.cnblogs.com/likeli/p/4234238.html 文章集合 ...

随机推荐

  1. windows上的mysql配置过程

    个人电脑的mysql配置,记录下来留作备忘 1. 首先去官网下载最新的mysql安装包,我下的是5.7.25,地址是 https://dev.mysql.com/downloads/windows/ ...

  2. Netty源码分析第6章(解码器)---->第2节: 固定长度解码器

    Netty源码分析第六章: 解码器 第二节: 固定长度解码器 上一小节我们了解到, 解码器需要继承ByteToMessageDecoder, 并重写decode方法, 将解析出来的对象放入集合中集合, ...

  3. 笨办法学Python - 习题11-12: Asking Questions & Prompting People

    目录 1.习题 11: 提问 2.习题 12: 提示别人 3.总结 1.习题 11: 提问 学习目标:了解人机交互场景,熟悉raw_input 的用法. 1.在 Python2.x 中 raw_inp ...

  4. nodejs 几篇有用的文章

    深入浅出Node.js(三):深入Node.js的模块机制 http://www.infoq.com/cn/articles/nodejs-module-mechanism Node.js简单介绍并实 ...

  5. React Native (0.57)开发环境搭建(注意:Node不要随便更新到最新版,更新完后莫名其妙的问题一大堆)

    搭建开发环境 一.安装依赖 必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. 1.首先安装 Homebrew 2.安装 Node, Watchm ...

  6. MySQL原生API、MySQLi面向过程、MySQLi面向对象、PDO操作MySQL

    [转载]http://www.cnblogs.com/52fhy/p/5352304.html 本文将举详细例子向大家展示PHP是如何使用MySQL原生API.MySQLi面向过程.MySQLi面向对 ...

  7. oracle将多个结果集用逗号拼接成字符串

    有两个函数wmsys.wm_concat和listagg 1,SELECT wmsys.wm_concat(CATALOG_NAME) FROM "DATASHARE"." ...

  8. Scurm Meeting 11.2

    成员 今日任务 明日计划 用时 徐越 写功能规格说明书,代码移植 创建数据库,代码移植 3h 赵庶宏 编写功能规格说明书,学习访问数据库代码,代码迁移 代码迁移 5h 武鑫 设计界面:独立完成一些简单 ...

  9. 20162314 《Program Design & Data Structures》Learning Summary Of The Fifth Week

    20162314 2017-2018-1 <Program Design & Data Structures>Learning Summary Of The Fifth Week ...

  10. web11 Struts处理表单数据

    电影网站:www.aikan66.com 项目网站:www.aikan66.com游戏网站:www.aikan66.com图片网站:www.aikan66.com书籍网站:www.aikan66.co ...