BMP RGB888转RGB565 +上下翻转+缩放
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;
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;
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
}
}
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 +上下翻转+缩放的更多相关文章
- 使用NEON指令加速RGB888和RGB565的相互转换
最近在做一个项目需要将RGB888转换为RGB565,用C语言转换的代码很简单,这是从ffmpeg中摘抄的代码 static inline void rgb24to16_c(const uint8_t ...
- 19_Android中图片处理原理篇,关于人脸识别站点,图片载入到内存,图片缩放,图片翻转倒置,网上撕衣服游戏案例编写
1载入图片到内存 (1).数码相机照片特别是大于3m以上的,内存吃不消,会报OutOfMemoryError,若是想仅仅显示原图片的1/8,能够通过BitmapFactory.Options来实现.详 ...
- 19_Android中图片处理原理篇,关于人脸识别网站,图片加载到内存,图片缩放,图片翻转倒置,网上撕衣服游戏案例编写
1加载图片到内存 (1).数码相机照片特别是大于3m以上的,内存吃不消,会报OutOfMemoryError,若是想只显示原图片的1/8,可以通过BitmapFactory.Options来实现,具体 ...
- RGB565的理解
一个彩色图像由R G B三个分量组成,一个RGB565的每一个像素点数据为2Byte,即16位,那么从名字上就可看出来这16位中,高5位为R分量,中间6位为G分量,低5位为B分量. 下面做了一个实验, ...
- Beginning SDL 2.0(3) SDL介绍及BMP渲染
SDL是一个跨平台的多媒体库.为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface.SDL_Texture.SDL_Renderer ...
- RGB565的转换
RGB色彩模式也就是“红绿蓝”模式是一种颜色标准,是通过对红(R).绿(G).蓝(B)三种颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红.绿.蓝三个通道的颜色,这个标准几 ...
- STM32单片机图片解码
图片解码首先是最简单的bmp图片解码,关于bmp的结构可自行查阅,代码如下 #ifndef __BMPDECODE_H_ #define __BMPDECODE_H_ #include "f ...
- Linux LCD 显示图片【转】
转自:https://blog.csdn.net/niepangu/article/details/50528190 BMP和JPEG图形显示程序1) 在LCD上显示BMP或JPEG图片的主流程图首 ...
- TJpgDec—轻量级JPEG解码器
TJpgDec-轻量级JPEG解码器 本文由乌合之众lym瞎编,欢迎转载blog.cnblogs.net/oloroso 下文中解码一词皆由decompression/decompress翻译而来. ...
随机推荐
- Flume-自定义 Source
Source 是负责接收数据到 Flume Agent 的组件. Source 组件可以处理各种类型.各种格式的日志数据,包括 avro.thrift.exec.jms.spooling direct ...
- php+mysql模糊查询功能
一般模糊查询语句如下: SELECT 字段 FROM 表 WHERE 某字段 Like 条件 其中关于条件,SQL提供了四种匹配模式: 1,% :表示任意0个或多个字符.可匹配任意类型和长度的字符,有 ...
- Qt编写自定义控件26-平铺背景控件
一.前言 平铺背景控件,主要的应用场景是作为画布出现,黑白相间的背景图,然后上面可以放置图片图形等,使得看起来更美观,比如PS软件新建图层以后的背景,FireWorks软件新建画布以后的透明背景,IC ...
- kafka-sparkstreaming---学习1
---恢复内容开始--- import java.util.*; import org.apache.spark.SparkConf; import org.apache.spark.TaskCont ...
- 使用sproto buff 的陷阱
当sproto协议包中的数组元素,长度为0时,会出现接收异常.在没有调试断点的情况下,会停止接收其它协议.
- Dart 语言简述
Dart是一种“结构化的web编程”语言,Dart编程语言在所有现代浏览器和环境中提供高性能.Dart是谷歌开发的计算机编程语言,后来被ECMA认定为标准. Dart重要的概念: 1.所有的东西都是对 ...
- JQuery Validate - 自定义js验证
(function (window, $) { var validResult = {}; var checkObjs = { /** * 检查输入的一串字符是否全部是数字 * 输入:str Stri ...
- 【Qt开发】QT4 升级到 QT5 改动
QT4 升级到 QT5 改动: PC部分: [改 QTDIR 变量] 在工程根目录下找到 .user 文件 , 如 InnoTabPlugin.vcxproj.user 修改指向你的 QT5 根目录 ...
- 最新 优刻得java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.优刻得等10家互联网公司的校招Offer,因为某些自身原因最终选择了优刻得.6.7月主要是做系统复习.项目复盘.LeetCo ...
- 最新 用友网络java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.用友网络等10家互联网公司的校招Offer,因为某些自身原因最终选择了用友网络.6.7月主要是做系统复习.项目复盘.Leet ...