典型的BMP图像文件由四部分组成:
(1) 位图头文件数据结构,它包含BMP图像文件的类型、文件大小和位图起始位置等信息;
  

typedef struct tagBITMAPFILEHEADER {
WORD bfType;//位图文件的类型,必须为BM(1-2字节)
DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
} BITMAPFILEHEADER;
(2) 位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//本结构所占用字节数(15-18字节)
LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
LONG biHeight;//位图的高度,以像素为单位(23-26字节)
WORD biPlanes;
WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节) //4(16色),8(256色)16(高彩色)或24(真彩色)之一
DWORD biCompression;
DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
(3) 调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
(4) 位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。
 
1. 打开位图并显示
    BITMAPFILEHEADER bmpHeader;//文件头
BITMAPINFOHEADER bmpInfo;//信息头 CFileDialog dlg(TRUE, "*.BMP", NULL, NULL,"位图文件(*.BMP)|*.bmp;*.BMP|",this);
CFile bmpFile;//记录打开文件
CString strFileName;//记录选择文件路径
if (!dlg.DoModal() == IDOK) return;
strFileName = dlg.GetPathName(); //以只读的方式打开文件
if(!bmpFile.Open(strFileName, CFile::modeRead|CFile::typeBinary)) return; //读取文件头到bmpHeader
if (bmpFile.Read(&bmpHeader,sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER))
{
AfxMessageBox("read bmp header failed!");
return;
} /*0x4d42=’BM’,表示是Windows支持的BMP格式。
(注意:查ascii表B 0x42,M0x4d,bfType 为两个字节,B为low字节,M为high字节
所以bfType=0x4D42,而不是0x424D
*/
if (bmpHeader.bfType != 0x4d42)
{
AfxMessageBox("invalid file type!");
return;
} //读取文件信息头bmpInfo
if (bmpFile.Read(&bmpInfo,sizeof(BITMAPINFOHEADER)) != sizeof(BITMAPINFOHEADER))
{
AfxMessageBox("read bmp infor header failed!");
return;
}
//确认是24位位图
if (bmpInfo.biBitCount != )//图像的位数
{
AfxMessageBox("File is not 24 bit.Application doesn't support this kind of file!");
return;
}
/*
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
*/
pBmpInfo = (BITMAPINFO *)new char[sizeof(BITMAPINFOHEADER)];
if (!pBmpInfo)
{
AfxMessageBox("memory error!");
return;
}
//为图像数据申请空间
memcpy(pBmpInfo, &bmpInfo, sizeof(BITMAPINFOHEADER));
//计算颜色表区域大小:结构体的大小(包含颜色表)-颜色数据的偏移量
DWORD dataBytes = bmpHeader.bfSize - bmpHeader.bfOffBits;
pBmpData = (BYTE*)new char[dataBytes];
if (!pBmpData)
{
AfxMessageBox("memory error!");
delete pBmpData;
return;
}
if (bmpFile.Read(pBmpData,dataBytes) != dataBytes)
{
AfxMessageBox("Read bmp data failed!");
delete pBmpInfo;
delete pBmpData;
return;
}
//bmpFile.Close(); CWnd *pWnd=GetDlgItem(IDC_IMAGE);//获得pictrue控件窗口的句柄
CRect rect;
pWnd->GetClientRect(&rect);//获得pictrue控件所在的矩形区域
CDC *pDC=pWnd->GetDC();//获得pictrue控件的DC
//显示图片
pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->GetSafeHdc(),,,rect.Width(),rect.Height(),,,bmpInfo.biWidth,bmpInfo.biHeight,pBmpData,pBmpInfo,DIB_RGB_COLORS,SRCCOPY); iBmpWidth = bmpInfo.biWidth;
iBmpHeight = bmpInfo.biHeight;

2. 将24位图转化为16位位图(从RGB888到RGB565)

需要将原来的颜色表数据分离成R,G,B三组,然后R舍弃3位,G舍弃2位,B舍弃3位。

a. 分离,读取RGB数据存到三个BYTE*数组里m_pR, m_pG, m_pB;

     LARGE_INTEGER liSize;
liSize.QuadPart = ;
::GetFileSizeEx(bmpFile, &liSize); int nBitmapSize = abs(iBmpHeight) * WIDTHBYTES(iBmpWidth * bmpInfo.biBitCount);
if(bmpInfo.biPlanes != )
{
break;
}
if(bmpInfo.biBitCount != && bmpInfo.biBitCount != && bmpInfo.biBitCount != && bmpInfo.biBitCount != && bmpInfo.biBitCount != && bmpInfo.biBitCount != )
{
break;
}
if(bmpInfo.biCompression != BI_RGB && bmpInfo.biCompression != BI_BITFIELDS)
{
break;
}
if(bmpInfo.biWidth <= || bmpInfo.biHeight == )
{
break;
}
if(bmpHeader.bfOffBits + nBitmapSize > liSize.QuadPart)
{
break;
} //m_pR,m_pG,m_pB位BYTE *;
m_pR = new BYTE[bmpInfo.biWidth * abs(bmpInfo.biHeight)];
m_pG = new BYTE[bmpInfo.biWidth * abs(bmpInfo.biHeight)];
m_pB = new BYTE[bmpInfo.biWidth * abs(bmpInfo.biHeight)]; if(bmpInfo.biBitCount < )
{
//...
}
else if(bmpInfo.biBitCount == )
{
//...
}
else if(bmpInfo.biBitCount == )
{
::SetFilePointer(bmpFile, bmpHeader.bfOffBits, NULL, SEEK_SET); BYTE *pData;
pData = new BYTE[nBitmapSize]; DWORD dwByteRead = ;
dwByteRead = ;
::ReadFile(bmpFile, pData, nBitmapSize, &dwByteRead, NULL); //pR, pG, pB是临时指针
BYTE *pR = m_pR;
BYTE *pG = m_pG;
BYTE *pB = m_pB; for(int j = ; j < abs(bmpInfo.biHeight); j++)
{
BYTE *pTemp = pData + WIDTHBYTES(bmpInfo.biWidth * bmpInfo.biBitCount) * j;
for(int i = ; i < bmpInfo.biWidth; i++)
{
*pB++ = *pTemp++;
*pG++ = *pTemp++;
*pR++ = *pTemp++;
}
} delete[] pData;
}
else if(bmpInfo.biBitCount == )
{
//...
}

b. 转化,从24位转化成16位

//新文件的头信息
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih; memset(&bmfh, , sizeof(bmfh));
memset(&bmih, , sizeof(bmih)); int nBitmapSize = abs(bmpInfo.biHeight) * WIDTHBYTES(bmpInfo.biWidth * );
length = nBitmapSize;
bmfh.bfType = 'MB';
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih) + ;
bmfh.bfSize = bmfh.bfOffBits + nBitmapSize; bmih.biSize = sizeof(bmih);
bmih.biWidth = bmpInfo.biWidth;
bmih.biHeight = bmpInfo.biHeight;
bmih.biPlanes = ;
bmih.biBitCount = ;
bmih.biCompression = BI_BITFIELDS;
bmih.biSizeImage = nBitmapSize; /* 转化后的颜色表保存在pData中 */
BYTE *pData;
pData = new BYTE[nBitmapSize];
memset(pData, , nBitmapSize); myData = new char[nBitmapSize];
memset(myData,,nBitmapSize); char * inverseData = new char[nBitmapSize];
memset(inverseData, , nBitmapSize); BYTE *pR = m_pR;
BYTE *pG = m_pG;
BYTE *pB = m_pB; /* 以下是转化的核心代码 */
/* 转化过程图像的宽和高是不变的,变得是每个像素点从3个字节变成了2个字节 */
for(int j = ; j < abs(bmih.biHeight); j++)
{
/* 临时指针pTemp 每次从新的一行开始 */
WORD *pTemp = (WORD *)(pData + WIDTHBYTES(bmih.biWidth * ) * j); for(int i = ; i < bmih.biWidth; i++)
{
#if 0
*pTemp++ = ((WORD)(*pR++ << ) & 0xf800) | ((WORD)(*pG++ << ) & 0x07e0) | ((WORD)(*pB++ >> ) & 0x001f);
#else
/* 分别去掉低3,2,3位 */
int nR = (*pR++ + ) >> ;
int nG = (*pG++ + ) >> ;
int nB = (*pB++ + ) >> ;
/* nR位5位,不能超过31,nG为6位,不能超过63,nB同nR */
if(nR > ) nR = ;
if(nG > ) nG = ;
if(nB > ) nB = ;
/* 将新的R,G,B数据拼到2个字节里,比例为5:6:5 */
*pTemp++ = (nR << ) | (nG << ) | nB;
#endif
}
}
3. 将图片上下对称翻转。图像点阵是image_width * image_height 的大小,翻转时只需要将 上下两半对应的位置的点对换就行了。经上面的转换后,图像中每个点占2个字节了,所以每个点换两个字节就行。
  int image_width = bmih.biWidth;
int image_height = bmih.biHeight;
int index = ;//表示16色,占2个字节
for(int h = ; h < image_height/; h++)
for (int w = ; w < image_width; w++)
{
/* iCoordM 和 iCoordN分别是上下对称的点在颜色表字节数组中的坐标,
交换iCoordM位置和iCoordM+1位置2个字节就行了。
*/
const int iCoordM = index*(h*image_width + w);
const int iCoordN = index*((image_height - h -)*image_width + w);
BYTE Tmp = pData[iCoordM];
pData[iCoordM] = pData[iCoordN];
pData[iCoordN] = Tmp;
Tmp = pData[iCoordM+];
pData[iCoordM + ] = pData[iCoordN + ];
pData[iCoordN + ] = Tmp;
/*如果是24位图像,就加上下面的内容,就是再交换一个字节*/
/*Tmp = pData[iCoordM + 2];
pData[iCoordM + 2] = pData[iCoordN + 2];
pData[iCoordN + 2] = Tmp;*/
}

4.  缩放

/* new_heigth和new_width为目标图片的大小,可自定义 */
int new_height = ;
int new_width = ;
int newSize = new_width*new_height*;
length = newSize;
BYTE * newData = new BYTE[newSize];
/* 分配新的内存 */
memset(newData, , new_width*new_height*); for(int h = ; h < image_height; h++)
for (int w = ; w < image_width; w++)
{
/* 计算每个像素的起始位置 */
const int iCoordM = index * (h * image_width + w);
//const int iCoordN = index*((image_height - h -1)*image_width + w);
BYTE Tmp = pData[iCoordM];
int x = int( double(h)/image_height * new_height);//新行数
int y = int( double(w)/image_width * new_width);//新列数 /* 将原来图片的每个像素按比例位置映射到新的图片上
原来的位置是(w, h),通过比例就可以计算出新的位置是
(int(double(w)/image_width*new_width), int(double(h)/image_height*new_height)),
然后将新的位置开始的2个字节等于原来位置的2个字节,就完成了缩放。
*/
newData[(x*new_width + y)*] = Tmp;
newData[(x*new_width + y)* + ] = pData[iCoordM+];
}

(完)

BMP RGB888转RGB565 +上下翻转+缩放的更多相关文章

  1. 使用NEON指令加速RGB888和RGB565的相互转换

    最近在做一个项目需要将RGB888转换为RGB565,用C语言转换的代码很简单,这是从ffmpeg中摘抄的代码 static inline void rgb24to16_c(const uint8_t ...

  2. 19_Android中图片处理原理篇,关于人脸识别站点,图片载入到内存,图片缩放,图片翻转倒置,网上撕衣服游戏案例编写

    1载入图片到内存 (1).数码相机照片特别是大于3m以上的,内存吃不消,会报OutOfMemoryError,若是想仅仅显示原图片的1/8,能够通过BitmapFactory.Options来实现.详 ...

  3. 19_Android中图片处理原理篇,关于人脸识别网站,图片加载到内存,图片缩放,图片翻转倒置,网上撕衣服游戏案例编写

    1加载图片到内存 (1).数码相机照片特别是大于3m以上的,内存吃不消,会报OutOfMemoryError,若是想只显示原图片的1/8,可以通过BitmapFactory.Options来实现,具体 ...

  4. RGB565的理解

    一个彩色图像由R G B三个分量组成,一个RGB565的每一个像素点数据为2Byte,即16位,那么从名字上就可看出来这16位中,高5位为R分量,中间6位为G分量,低5位为B分量. 下面做了一个实验, ...

  5. Beginning SDL 2.0(3) SDL介绍及BMP渲染

    SDL是一个跨平台的多媒体库.为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface.SDL_Texture.SDL_Renderer ...

  6. RGB565的转换

    RGB色彩模式也就是“红绿蓝”模式是一种颜色标准,是通过对红(R).绿(G).蓝(B)三种颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红.绿.蓝三个通道的颜色,这个标准几 ...

  7. STM32单片机图片解码

    图片解码首先是最简单的bmp图片解码,关于bmp的结构可自行查阅,代码如下 #ifndef __BMPDECODE_H_ #define __BMPDECODE_H_ #include "f ...

  8. Linux LCD 显示图片【转】

    转自:https://blog.csdn.net/niepangu/article/details/50528190 BMP和JPEG图形显示程序1)  在LCD上显示BMP或JPEG图片的主流程图首 ...

  9. TJpgDec—轻量级JPEG解码器

    TJpgDec-轻量级JPEG解码器 本文由乌合之众lym瞎编,欢迎转载blog.cnblogs.net/oloroso 下文中解码一词皆由decompression/decompress翻译而来. ...

随机推荐

  1. java课后实验性问题3

    一 .生成随机数 import java.util.*; public class Test1 { public static void main(String[] args) { //建立一个生产随 ...

  2. 【SVN】彻底 svn 服务器上的 删除某一个文件或文件夹

    参考: CSDN1:https://blog.csdn.net/u011729865/article/details/78764523 CSDN2:https://blog.csdn.net/wyyo ...

  3. vue devtools无法使用

    vue devtools无法使用 一.总结 一句话总结: 没显示vue devtools调试工具的原因是用了生产环境的版本或是压缩的vue版本,或是没有勾选:允许访问文件网址 二.vue调试工具Dev ...

  4. python包中__init__.py文件的作用

    python包中__init__.py文件的作用 __init__.py文件最常用的作用是标识一个文件夹是一个 python包. __init__.py文件的另一个作用是定义模糊导入时要导入的内容. ...

  5. Flutter路由_fluro引入配置和使用

    Flutter本身提供了路由机制,作个人的小型项目,完全足够了.但是如果你要作企业级开发,可能就会把入口文件变得臃肿不堪.而再Flutter问世之初,就已经了企业级路由方案fluro. flutter ...

  6. 在win10上使用premake工具和vs2017编译运行Box2D源码和Testbed

    1.从github上下载Box2D源码的zip包 2.解压缩zip包 3.从premake网站下载premake5工具,解压后得到premake5.exe 4.将premake5.exe拷贝到Box2 ...

  7. 安卓运行linux应用程序

    安卓是可以运行linux应用程序的,安卓系统原来就基于Linux.但是安卓已经把linux改头换面了.具体方法是安装Termux软件,然后就可以运行pkg命令安装软件包了,希望可以帮助到大家.

  8. 【AMAD】django-reversion -- 为django的model实例带来版本控制

    动机 简介 个人评分 动机 有时候数据表的数据也需要版本控制.比如论坛的帖子,作者是可以改动的,但是你想要留下每个改动的版本. 简介 django-reversion1的特点: 可以回滚一个insta ...

  9. Elasticsearch 追加更新

    追加更新,学名不知道叫啥,我这里指在历史数据的基础上,追加数据更新.比如 价格数据,我在价格字段里面保存了一个每天价格的数组,追加更新的时候在数组的后面直接add,而不是像一般情况那样覆盖. ES追加 ...

  10. CentOS7.3安装Python3.6

    安装python3.6可能使用的依赖 # yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sql ...