数码相框——8、3 、1 程序编写_图片显示之bmp数据提取

1、bitmap格式分析

参考文件夹里:bitmap格式分析.htm
https://blog.51cto.com/redwolf/229096
1)位图文件(*.BMP)的格式
在这里插入图片描述
int 2字节 DWORD 4字节
LONG 4字节 WORD 2字节
在这里插入图片描述
在这里插入图片描述
以某bmp文件信息为例:
在这里插入图片描述
这里我们需要注意的是:
图片信息的第一个数据对应的是LCD左下角第一个像素,第二个数据对应的是左下角第一个像素的右边。(从左往右存完第一行, 再往上的从左往右存第
二行)

在这里插入图片描述
所以,LCD上第一个像素应该去图片信息的左下角提取。

2)实现加载

1、加载文件头
2、加载位图信息头
3、行对齐(由于Windows在进行行扫描的时候最小的单位为4个字节)
4、加载图片数据
5、绘制

2、编写代码
在render目录里建立format文件夹
在这里插入图片描述
在inlude里创建pic_operation.h
在这里插入图片描述
1)pic_operation.h


#ifndef _PIC_OPERATION_H
#define _PIC_OPERATION_H

typedef struct PixelDatas {
	int iWidth;
	int iHeight;
	int iBpp;
	int iLineBytes;
	unsigned char *aucPixelDatas;
}T_PixelDatas, *PT_PixelDatas;


typedef struct PicFileParser {
	char *name;
	int (*isSupport)(unsigned char *aFileHead);
	int (*GetPixelDatas)(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas);
	int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);//释放内存
}T_PicFileParser, *PT_PicFileParser;

#endif /* _PIC_OPERATION_H */


2)bitmap.c
在这里插入图片描述
注意结构体的字节对齐
#pragma pack(push) /* 将当前pack设置压栈保存*/
#pragma pack(1) /*必须在结构体定义之前使用 */
#pragma pack(pop) /*恢复先前的pack设置 */

#include <config.h>
#include <pic_operation.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1)    /* 必须在结构体定义之前使用 */
为什么要压栈呢? 因为结构体要字节对齐,所以  sizeof(BITMAPFILEHEADER))16字节,然而我们文件信息头为14字节。

typedef struct tagBITMAPFILEHEADER { /* bmfh */
	unsigned short bfType; 
	unsigned long  bfSize;
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned long  bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;
	unsigned long  biWidth;
	unsigned long  biHeight;
	unsigned short biPlanes;
	unsigned short biBitCount;
	unsigned long  biCompression;
	unsigned long  biSizeImage;
	unsigned long  biXPelsPerMeter;
	unsigned long  biYPelsPerMeter;
	unsigned long  biClrUsed;
	unsigned long  biClrImportant;
} BITMAPINFOHEADER;

#pragma pack(pop) /* 恢复先前的pack设置 */

static int isBMPFormat(unsigned char *aFileHead);
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas);

T_PicFileParser g_tBMPParser = {
	.name           = "bmp",
	.isSupport      = isBMPFormat,
	.GetPixelDatas  = GetPixelDatasFrmBMP,
	.FreePixelDatas = FreePixelDatasForBMP,	
};

static int isBMPFormat(unsigned char *aFileHead)
{
	if (aFileHead[0] != 0x42 || aFileHead[1] != 0x4d)
		return 0;
	else
		return 1;
}

static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
	unsigned int dwRed;
	unsigned int dwGreen;
	unsigned int dwBlue;
	unsigned int dwColor;

	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwBlue  = pudSrcDatas[pos++];
			dwGreen = pudSrcDatas[pos++];
			dwRed   = pudSrcDatas[pos++];
			if (iDstBpp == 32)
			{
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				/* 565 */
				dwRed   = dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;
}

/*
 * ptPixelDatas->iBpp 是输入的参数, 它决定从BMP得到的数据要转换为该格式
 */
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas)
{
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;

	int iWidth;
	int iHeight;
	int iBMPBpp;
	int y;

	unsigned char *pucSrc;
	unsigned char *pucDest;
	int iLineWidthAlign;
	int iLineWidthReal;
	
	//1、加载文件信息头
	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
	//2、加载位图信息头
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));

	iWidth = ptBITMAPINFOHEADER->biWidth;
	iHeight = ptBITMAPINFOHEADER->biHeight;
	iBMPBpp = ptBITMAPINFOHEADER->biBitCount;

	if (iBMPBpp != 24)
	{
		DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp);
		DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER));
		return -1;
	}

	ptPixelDatas->iWidth  = iWidth;
	ptPixelDatas->iHeight = iHeight;
	//ptPixelDatas->iBpp    = iBpp;
	ptPixelDatas->aucPixelDatas = malloc(iWidth * iHeight * ptPixelDatas->iBpp / 8);
	ptPixelDatas->iLineBytes    = iWidth * ptPixelDatas->iBpp / 8;
	if (NULL == ptPixelDatas->aucPixelDatas)
	{
		return -1;
	}

//由于Windows在进行行扫描的时候最小的单位为4个字节,所以当
//图片宽 X 每个像素的字节数 != 4的整数倍时要在每行的后面补上缺少的字节,以0填充
	iLineWidthReal = iWidth * iBMPBpp / 8;
	iLineWidthAlign = (iLineWidthReal + 3) & ~0x3;   /* 向4 向上取整 */ /* 与上 ~0x3 的意思是把低两位去掉 */
	
	//因为图片的左下角的对应的是LCD左上角	
	pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits; //指向图片的第一个像素
	pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign; //指向图片左下角

	pucDest = ptPixelDatas->aucPixelDatas;
	
	//一行一行赋值
	for (y = 0; y < iHeight; y++)
	{		
		//memcpy(pucDest, pucSrc, iLineWidthReal);不能直接用memset是因为LCD和bmp的 bpp可能不一样
		CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);
		pucSrc  -= iLineWidthAlign;
		pucDest += ptPixelDatas->iLineBytes;
	}
	return 0;	
}

static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
	free(ptPixelDatas->aucPixelDatas);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值