BMP格式图像的显示

   使用多文档编程 也可以使用单文档编程

  建立一个DIB图像的显示类 ImageDib

  成员变量:

  4个指针:

    LPBYTE m_lpDib;      //指向DIB的指针
    LPBITMAPINFOHEADER m_lpBmpInfoHead;  //图像信息头指针

    LPRGBQUAD m_lpColorTable;     //图像颜色表指针
    unsigned char * m_pImgData;     //图像数据指针

  4个普通变量(存放图像的参数):
      int m_imgWidth;       //图像的宽,像素为单位
      int m_imgHeight;       //图像的高,像素为单位
    int m_nBitCount;      //每像素占的位数
     int m_nColorTableLength;      //颜色表长度(多少个表项)
  1个句柄:
       HPALETTE m_hPalette;     //逻辑调色板句柄

  成员函数:

  带参数构造函数  ImageDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData);           //带参数的构造函数

View Code
ImageDib::ImageDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable,unsigned char *pImgData)
{//如果没有位图数据传入,我们认为是空的DIB,此时不分配DIB内存if(pImgData==NULL){m_lpDib=NULL;m_lpColorTable=NULL;m_pImgData=NULL;  // 图像数据m_lpBmpInfoHead=NULL; //  图像信息头m_hPalette = NULL;}else{//如果有位图数据传入//可以通过调用ReplaceDib()来实现 代码一样的//ReplaceDib(size,nBitCount,lpColorTable,pImgData);//图像的宽、高、每像素位数等成员变量赋值m_imgWidth=size.cx;m_imgHeight=size.cy;m_nBitCount=nBitCount;//根据每像素位数,计算颜色表长度m_nColorTableLength=ComputeColorTabalLength(nBitCount);//每行像素所占字节数,必须扩展成4的倍数int lineByte=(m_imgWidth*nBitCount/8+3)/4*4;//位图数据缓冲区的大小(图像大小)int imgBufSize=m_imgHeight*lineByte;//为m_lpDib一次性分配内存,生成DIB结构m_lpDib=new BYTE [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableLength+imgBufSize];//填写BITMAPINFOHEADER结构m_lpBmpInfoHead = (LPBITMAPINFOHEADER) m_lpDib;m_lpBmpInfoHead->biSize = sizeof(BITMAPINFOHEADER);m_lpBmpInfoHead->biWidth = m_imgWidth;m_lpBmpInfoHead->biHeight = m_imgHeight;m_lpBmpInfoHead->biPlanes = 1;m_lpBmpInfoHead->biBitCount = m_nBitCount;m_lpBmpInfoHead->biCompression = BI_RGB;m_lpBmpInfoHead->biSizeImage = 0;m_lpBmpInfoHead->biXPelsPerMeter = 0;m_lpBmpInfoHead->biYPelsPerMeter = 0;m_lpBmpInfoHead->biClrUsed = m_nColorTableLength;m_lpBmpInfoHead->biClrImportant = m_nColorTableLength;//调色板句柄初始化为空,有颜色表时,MakePalette()函数要生成新的调色板m_hPalette = NULL;//如果有颜色表,则将颜色表拷贝进DIB的颜色表位置if(m_nColorTableLength!=0){//m_lpColorTable指向DIB颜色表的起始位置m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));//颜色表拷贝memcpy(m_lpColorTable,lpColorTable,sizeof(RGBQUAD) * m_nColorTableLength);//创建逻辑调色板
            MakePalette();}//m_pImgData指向DIB位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD) * m_nColorTableLength;//拷贝图像数据进DIB位图数据区
        memcpy(m_pImgData,pImgData,imgBufSize);}}

 

  读文件:      BOOL Read(LPCTSTR lpszPathName);   //DIB读函数

View Code
BOOL ImageDib::Read(LPCTSTR lpszPathName)
{//读模式打开图像文件
    CFile file;if (!file.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite))return FALSE;BITMAPFILEHEADER bmfh;//读取BITMAPFILEHEADER结构到变量bmfh中int nCount=file.Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));//为m_lpDib分配空间,读取DIB进内存if(m_lpDib!=NULL)    delete []m_lpDib;m_lpDib=new BYTE[file.GetLength() -sizeof(BITMAPFILEHEADER)];file.Read(m_lpDib, file.GetLength() -sizeof(BITMAPFILEHEADER));//m_lpBmpInfoHead位置为m_lpDib起始位置m_lpBmpInfoHead = (LPBITMAPINFOHEADER)m_lpDib;//为成员变量赋值m_imgWidth=m_lpBmpInfoHead->biWidth;m_imgHeight=m_lpBmpInfoHead->biHeight;m_nBitCount=m_lpBmpInfoHead->biBitCount; //计算颜色表长度m_nColorTableLength=    ComputeColorTabalLength(m_lpBmpInfoHead->biBitCount);//如果有颜色表,则创建逻辑调色板m_hPalette = NULL;if(m_nColorTableLength!=0){m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));MakePalette();}//m_pImgData指向DIB的位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * m_nColorTableLength;return TRUE;
}

 


      写文件:     BOOL Write(LPCTSTR lpszPathName);       //DIB写函数

View Code
BOOL ImageDib::Write(LPCTSTR lpszPathName)
{//写模式打开文件
    CFile file;if (!file.Open(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive))return FALSE;//填写文件头结构
    BITMAPFILEHEADER bmfh;bmfh.bfType = 0x4d42;  // 'BM'bmfh.bfSize = 0;bmfh.bfReserved1 = bmfh.bfReserved2 = 0;bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * m_nColorTableLength;    try {//文件头结构写进文件file.Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));//文件信息头结构写进文件file.Write(m_lpBmpInfoHead,  sizeof(BITMAPINFOHEADER));//如果有颜色表的话,颜色表写进文件if(m_nColorTableLength!=0)file.Write(m_lpColorTable, sizeof(RGBQUAD) * m_nColorTableLength);//位图数据写进文件int imgBufSize=(m_imgWidth*m_nBitCount/8+3)/4*4*m_imgHeight;file.Write(m_pImgData, imgBufSize);}catch(CException* pe) {pe->Delete();AfxMessageBox("write error");return FALSE;}//函数返回return TRUE;
}

 


  计算颜色表长度:  int ComputeColorTabalLength(int nBitCount); //计算颜色表的长度

View Code
int ImageDib::ComputeColorTabalLength(int nBitCount)
{int colorTableLength;switch(nBitCount) {case 1:colorTableLength = 2;break;case 4:colorTableLength = 16;break;case 8:colorTableLength = 256;break;case 16:case 24:case 32:colorTableLength = 0;break;default:ASSERT(FALSE);}ASSERT((colorTableLength >= 0) && (colorTableLength <= 256)); return colorTableLength;
}

 


  创建逻辑调色板:  void MakePalette();      //创建逻辑调色板

View Code
void ImageDib::MakePalette()
{//如果颜色表长度为0,则不创建逻辑调色板if(m_nColorTableLength == 0) return;//删除旧的逻辑调色板句柄if(m_hPalette != NULL) ::DeleteObject(m_hPalette);//申请空间,根据颜色表生成LOGPALETTE结构LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +m_nColorTableLength * sizeof(PALETTEENTRY)];pLogPal->palVersion = 0x300;pLogPal->palNumEntries = m_nColorTableLength;LPRGBQUAD m_lpDibQuad = (LPRGBQUAD) m_lpColorTable;for(int i = 0; i < m_nColorTableLength; i++) {pLogPal->palPalEntry[i].peRed = m_lpDibQuad->rgbRed;pLogPal->palPalEntry[i].peGreen = m_lpDibQuad->rgbGreen;pLogPal->palPalEntry[i].peBlue = m_lpDibQuad->rgbBlue;pLogPal->palPalEntry[i].peFlags = 0;m_lpDibQuad++;}    //创建逻辑调色板m_hPalette = ::CreatePalette(pLogPal);//释放空间
    delete pLogPal;
}

 


  读取图像维数:  CSize GetDimensions();     //读取图像维数

View Code
CSize ImageDib::GetDimensions()
{    if(m_lpDib == NULL) return CSize(0, 0);return CSize(m_imgWidth, m_imgHeight);
}

 


  图像绘制:      BOOL Draw(CDC* pDC, CPoint origin, CSize size); //图像绘制

View Code
BOOL ImageDib::Draw(CDC* pDC, CPoint origin, CSize size)
{HPALETTE hOldPal=NULL;                //旧的调色板句柄if(m_lpDib == NULL) return FALSE;            //如果DIB为空,则返回0if(m_hPalette != NULL) {                    //如果DIB有调色板//将调色板选进设备环境中hOldPal=::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);pDC->RealizePalette();            }pDC->SetStretchBltMode(COLORONCOLOR);  //设置位图伸缩模式//将DIB在pDC所指向的设备上进行显示::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy,0, 0, m_lpBmpInfoHead->biWidth, m_lpBmpInfoHead->biHeight,m_pImgData,(LPBITMAPINFO) m_lpBmpInfoHead, DIB_RGB_COLORS, SRCCOPY);if(hOldPal!=NULL)                        //恢复旧的调色板::SelectPalette(pDC->GetSafeHdc(), hOldPal, TRUE);return TRUE;
}

 


  用新的数据替代DIB:void ReplaceDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData);               //用新的数据替换DIB

View Code
void ImageDib::ReplaceDib(CSize size, int nBitCount,  LPRGBQUAD lpColorTable,unsigned char *pImgData)
{ //释放原DIB所占空间
    Empty();//成员变量赋值m_imgWidth=size.cx;m_imgHeight=size.cy;m_nBitCount=nBitCount;//计算颜色表的长度m_nColorTableLength=ComputeColorTabalLength(nBitCount);//每行像素所占字节数,扩展成4的倍数int lineByte=(m_imgWidth*nBitCount/8+3)/4*4;//位图数据的大小int imgBufSize=m_imgHeight*lineByte;//为m_lpDib重新分配空间,以存放新的DIBm_lpDib=new BYTE [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableLength+imgBufSize];//填写位图信息头BITMAPINFOHEADER结构m_lpBmpInfoHead = (LPBITMAPINFOHEADER) m_lpDib;m_lpBmpInfoHead->biSize = sizeof(BITMAPINFOHEADER);m_lpBmpInfoHead->biWidth = m_imgWidth;m_lpBmpInfoHead->biHeight = m_imgHeight;m_lpBmpInfoHead->biPlanes = 1;m_lpBmpInfoHead->biBitCount = m_nBitCount;m_lpBmpInfoHead->biCompression = BI_RGB;m_lpBmpInfoHead->biSizeImage = 0;m_lpBmpInfoHead->biXPelsPerMeter = 0;m_lpBmpInfoHead->biYPelsPerMeter = 0;m_lpBmpInfoHead->biClrUsed = m_nColorTableLength;m_lpBmpInfoHead->biClrImportant = m_nColorTableLength;//调色板置空m_hPalette = NULL;//如果有颜色表,则将颜色表拷贝至新生成的DIB,并创建逻辑调色板if(m_nColorTableLength!=0){m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));memcpy(m_lpColorTable,lpColorTable,sizeof(RGBQUAD) * m_nColorTableLength);MakePalette();}//m_pImgData指向DIB的位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD) * m_nColorTableLength;//将新位图数据拷贝至新的DIB中
    memcpy(m_pImgData,pImgData,imgBufSize);
}

 

  清理空间函数:  void Empty();                          //清理空间

View Code
void ImageDib::Empty()
{//释放DIB内存缓冲区if(m_lpDib != NULL) {delete [] m_lpDib;m_lpDib=NULL;m_lpColorTable=NULL;m_pImgData=NULL;  m_lpBmpInfoHead=NULL;}//释放逻辑调色板缓冲区if(m_hPalette != NULL){::DeleteObject(m_hPalette);m_hPalette = NULL;}
}

 

  默认构造函数:

View Code
ImageDib::ImageDib()
{m_lpDib=NULL;//初始化m_lpDib为空。m_lpColorTable=NULL;                //颜色表指针为空m_pImgData=NULL;                  //图像数据指针为空m_lpBmpInfoHead=NULL;                //图像信息头指针为空m_hPalette = NULL;                    //调色板为空
}

  默认析构函数:

View Code
ImageDib::~ImageDib()
{//释放m_lpDib所指向的内存缓冲区if(m_lpDib != NULL) delete [] m_lpDib; //如果有调色板,释放调色板缓冲区if(m_hPalette != NULL)::DeleteObject(m_hPalette);
}

  编写好ImageDib类后,在doc文件类中添加一个ImageDib类的指针,在构造函数中new出来,在析构函数中delete,然后重写OnOpenDocument()函数 在其中调用读函数打开图像 在View类的OnDraw()中调用ImageDib类的绘制函数 将图像绘制在打开的新文件中

总结:编程的关键在于几个指针的赋值,指向DIB的指针的分配空间,位图信息头等结构的赋值等等。

只要记住:

  BMP文件=位图头文件+位图信息头+颜色表+数据块    (等号后边的内容按顺序写的)

  DIB=位图信息头+颜色表+数据块

  位图信息=位图信息头+颜色表

这些图像文件的存储组成及顺序,万事OK!


       

转载于:https://www.cnblogs.com/Anidot/archive/2012/04/23/2466495.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入A*算法

一、前言 在这里我将对A*算法的实际应用进行一定的探讨&#xff0c;并且举一个有关A*算法在最短路径搜索的例子。 二、A*算法的程序编写原理 A*算法是最好优先算法的一种。只是有一些约束条件而已。我们先来看看最好优先算法是如何编写的吧。 如图有如下的状态空间&#xff1a;…

IOS中NSUserDefaults的用法

2019独角兽企业重金招聘Python工程师标准>>> IOS中NSUserDefaults的用法&#xff08;轻量级本地数据存储&#xff09; 分类&#xff1a; IOS开发 Object&#xff0d;C编程语言2012-09-09 10:58 65223人阅读 评论(13) 收藏 举报 存储iosfloatinterfaceintegerdate NS…

【Oracle 学习笔记】Day 1 常用函数整理(转换、DeCode),表的外键

select Convert(varchar,Convert(money,TaxExValue),1) from A--Result 2,794.87 58,119.66 1,367.52 对于SQL Server来说&#xff0c;进行金额的转换&#xff0c;可以按照上面的操作那样&#xff0c;会自动将金额处理为两位小数&#xff0c;并用逗号分隔小数点前面的数字。 当…

LOJ bitset+分块 大内存毒瘤题

题面 $ solution: $ 真的没有想到可以用分块。 但是可以发现一个性质&#xff0c;每个询问只关心这个点最后一次赋值操作&#xff0c;和这个赋值操作后的所有取 $ min $ 操作。这个感觉很有用&#xff0c;但是真的很难让人想到低于 $ n\times m $ 的做法。基于 $ DAG $ 的数据结…

Web开发编程实用手册

不要被这个名字吓到。这本手册&#xff0c;真的很实用。你能猜猜它有多少页么&#xff1f;只有62页&#xff0c;比起那些砖头书来&#xff0c;这本可以说是苗条得不能再苗条了。现在卓越搞活动&#xff0c;购买电子工业出版社图书&#xff0c;凡购买专题内图书满69元&#xff0…

C# 配置文件 自定義結點

1. 對於配置自定義結點&#xff0c;需要繼承ConfigurationSection類。 UrlsSection : ConfigurationSection 2. 配置文件中&#xff0c;需要如下引用&#xff1a; View Code <configSections><section name"orders" type"WebApplication4.UrlsS…

Stream流思想和常用方法

一、IO流用于读写&#xff1b;Stream流用于处理数组和集合数据&#xff1b; 1、传统集合遍历&#xff1a; 2、使用Stream流的方式过滤&#xff1a; 其中&#xff0c;链式编程&#xff08;返回值就是对象自己&#xff09;中&#xff0c;filter使用的是Predicate函数式接口&#…

Stream流方法引用

一、对象存在&#xff0c;方法也存在&#xff0c;双冒号引用 1、方法引用的概念&#xff1a; 使用实例&#xff1a; 1.1先定义i一个函数式接口&#xff1a; 1.2定义一个入参参数列表有函数式接口的方法&#xff1a; 1.3调用这个入参有函数式接口的方法&#xff1a; lambda表达式…

为什么要在定义抽象类时使用abstract关键字

本文为原创&#xff0c;如需转载&#xff0c;请注明作者和出处&#xff0c;谢谢&#xff01;众所周之&#xff0c;在任何面向对象的语言中&#xff08;包括Java、C#&#xff09;&#xff0c;在定义抽象类时必须使用abstract关键字。虽然这已经习已为常了&#xff0c;但实际上ab…

pku 3252 Round Numbers 组合数学 找规律+排列组合

http://poj.org/problem?id3252 看了discuss里面的解题报告才明白的&#xff0c;这个解题报告太强大了&#xff1a;http://poj.org/showmessage?message_id158333不多讲已经很详细了&#xff0c;不明白多看几遍肯定会明白的。 注意这里的公式c(i,j) c(i - 1,j -1) c(i - 1…

《The Coaching Booster》问与答

由Shirly Ronen-Harel和Jens R. Woinowski 编写的《The Coaching Booster》 一书探讨了不同的教练方法和实践&#xff0c;并介绍了一种教练框架&#xff0c;支持教练帮助人们达到他们的目标。\InfoQ 采访了Shirly Ronen-Harel 和 Jens R. Woinowski&#xff0c;谈论了他们的书为…

反射应用和获取Class对象的三种方式

一、写一个“框架”&#xff0c;可以创建任何对象运行任何方法 1、配置文件 2、使用类加载器ClassLoader&#xff0c;Properties集合是可以和IO流结合使用完成读取和写入数据的集合&#xff0c;方法参数列表是IO流&#xff1b; Class类的静态方法forName()创建Class对象&#x…

8 种有趣的用于 Web 品牌的动物

当 Mozilla 推出最新移动浏览器 Fennec 时&#xff0c;很多人需要借助 Wikipedia 才知道 Fennec 是什么意思&#xff0c;Web 2.0 产品以各种古怪的命名著称&#xff0c;要么非常拗口&#xff0c;象 Flickr&#xff0c;要么很 cute&#xff0c;象 Google&#xff0c;或者干脆不知…

注解使用案例

一、一个简易测试框架&#xff1a; 1、定义Check注解&#xff0c;无需添加属性 2、需要测试的类&#xff0c;添加Check注解 3、测试框架代码&#xff1a; for循环上创建一个文件输出流对象&#xff0c;记录方法测试记录&#xff1a; 捕捉异常&#xff1a; 其中&#xff0c;get…

Java Date Time 教程-时间测量

为什么80%的码农都做不了架构师&#xff1f;>>> 在Java中&#xff0c;用System.currentTimeMillis()来测量时间最方便。你要做的是在某些操作之前获取到时间&#xff0c;然后在这些操作之后你想要测量时间&#xff0c;算出时间差。下面是一个例子&#xff1a; 1lon…

企业使用RTX腾讯通2013

2019独角兽企业重金招聘Python工程师标准>>> 腾讯通基本上成为了公司的默认配置&#xff0c;确实缺不了&#xff0c;这里记录一篇配置RTX&#xff0c;包括服务端和客户端。 1.客户端的使用 1.1 一般使用人员不需要关心任何事&#xff0c;只需要登录管理员分配给你的…

Android中弹出对话框,AlertDialog关键代码

写在这里便于以后查看。 Android中弹出对话框的关键代码&#xff1a; 1 btn01.setOnClickListener(new OnClickListener() {2 3 Override4 public void onClick(View v) {5 Toast.makeText(musicActivity.this, "tanchu", 1…

poj 2226 Muddy Fields 最小顶点覆盖

题目链接&#xff1a;http://poj.org/problem?id2226 这道题跟上一道很相似不同之处在于这里不是整行或者整列的删&#xff0c;而是连续的几个可以一起删&#xff0c;不连的不能删&#xff0c;这就要对原图进行处理&#xff0c;对原有的图行由上到下&#xff0c;列由左到右进行…

python抓取网站URL小工具

1、安装Python requests模块&#xff08;通过pip&#xff09;&#xff1a; 环境搭建好了&#xff01; 2、测试一下抓取URL的过程&#xff1a; 抓取出来的URL有JavaScript代码&#xff0c;正则上还有待更加完善&#xff0c;有兴趣的可以研究下~&#xff01; 工具源代码: #coding…

二叉树特性及详细例子

二叉树的性质 一般二叉树性质&#xff1a; 在非空二叉树的k层上&#xff0c;至多有2k个节点(k>0)高度为k的二叉树中,最多有2k1-1个节点(k>0)对于任何一棵非空的二叉树,如果叶节点个数为n0&#xff0c;度数为2的节点个数为n2&#xff0c;则有: n0 n2 1完全二叉树性质:只…