stm32显示bmp图片

目录

1.介绍

2.代码

2.1 定义

2.2 图片显示

2.3 格式转换

3.实现效果

4.源码地址


1.介绍

使用stm32单片机将bmp格式的图片显示在屏幕上,如果图片尺寸大于屏幕就将其缩放,图片文件存储在sd卡中,因此显示图片需要首先实现文件系统的移植及lcd屏幕的驱动(本文不涉及这一部分),本文主要实现图片处理这一部分。图片显示的原理就是通过文件系统打开图片文件,读取各像素点的颜色值进行处理后,使用屏幕显示出来。

注:文末给出的例程,部分驱动代码参考了正点原子的代码,例程仅供参考,如有问题,请自行修改。

2.代码

2.1 定义

主要定义了结构体Picture,用来存放图片的宽度,高度等相关信息。

#define P_LEN 240//屏幕宽度;
#define P_HEN 320//屏幕高度;

struct picture
{
	uint8_t 	bmphead[54];	//图片头信息;
	uint16_t  	offset;			//图像数据在文件中的偏移量;
	uint16_t  	hight;			//图片高度(像素点的个数);
	uint16_t  	weight;			//图片宽度;
	uint32_t  	size;			//图片的大小;
	uint32_t  	count;			//几位色彩;
	uint32_t  	color[P_LEN];	//处理后的像素的颜色值;
	uint8_t 	rgba[4 * P_LEN];//处理前的像素的颜色值;
}Picture;

2.2 图片显示

函数LCD_Show_Bmp,就是实现图片显示的主要函数,只需要在主函数中调用该函数传入图片名,就能将图片显示在屏幕上。

void LCD_Show_Bmp(char *pn)
{
	uint8_t kes = 0, ucRes;
	FIL ftp;//文件指针;
	char pname[100];//打开的图片文件名;
	int i = 0;
	uint32_t brt;
	
	uint32_t Pb = 0;//需要的像素点索引;
	uint32_t P_L = 0;//缩放后的图片宽度(即实际屏幕上显示的);
	uint32_t P_H = 0;//缩放后的图片高度;

	uint32_t P_X = 0;//显示图片的X起始坐标;
	uint32_t P_Y = 0;//显示图片的Y起始坐标;

	uint32_t pl = 0; //行像素;

	uint32_t len1 = 0, len2 = 0;//图片的宽度可能很宽,每次只取240个像素点,
								//len1表示取的次数,len2表示剩下不足240的像素数;
	
	float P_mag;//缩放比例;
	uint32_t mt1 = 0, mt2 = 0;//与缩放比例有关;
	
	pname[0] = '0';//存储的路径;
	pname[1] = ':';
	while(pn[i] != '\0')
	{
		pname[i + 2] = pn[i];
		i++;
	}
	
	pname[i + 2] = '\0';
	
	kes = PutGetFile_Sys(); //挂载文件系统;
	if(kes == 0)
	{
		printf("文件系统挂载失败!\n");
		return;
	}
	
	ucRes = f_open(&ftp, pname, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);//打开bmp格式的图片文件;
	if(ucRes != 0)
	{
		printf("图片文件打开失败!\n");
		return;
	}
	
	f_lseek(&ftp, 0);
	f_read(&ftp, Picture.bmphead, 54, &brt);//读取文件头信息;
		
	//计算偏移量,宽度,高度等;
	Picture.offset = Picture.bmphead[10] + Picture.bmphead[11] * 256 + Picture.bmphead[12] * 256 * 256 + Picture.bmphead[13] * 256 * 256 * 256;
	Picture.weight = Picture.bmphead[18] + Picture.bmphead[19] * 256 + Picture.bmphead[20] * 256 * 256 + Picture.bmphead[21] * 256 * 256 * 256;
	Picture.hight  = Picture.bmphead[22] + Picture.bmphead[23] * 256 + Picture.bmphead[24] * 256 * 256 + Picture.bmphead[25] * 256 * 256 * 256;
	Picture.size   = Picture.bmphead[2]  + Picture.bmphead[3]  * 256 + Picture.bmphead[4]  * 256 * 256 + Picture.bmphead[5]  * 256 * 256 * 256;
	Picture.count  = Picture.bmphead[28] / 8;
	
	len1 = Picture.weight / P_LEN;
	len2 = Picture.weight % P_LEN;
	
	if(Picture.weight > P_LEN || Picture.hight > P_HEN)
	{
		if(((float)Picture.weight / (float)P_LEN) >= ((float)Picture.hight / (float)P_HEN))
		{
			P_mag = ((float)Picture.weight / (float)P_LEN);
			P_L = P_LEN;
			P_H = P_rand((float)Picture.hight / P_mag);

			P_X = 0;
			P_Y = P_HEN - ((P_HEN - P_H) / 2);
			
			mt1 = Picture.weight;
			mt2 = P_LEN;
		}
		else
		{
			P_mag = ((float)Picture.hight / (float)P_HEN);
			P_H = P_HEN;
			P_L = P_rand((float)Picture.weight / P_mag);
			
			P_X = ((P_LEN - P_L) / 2);
			P_Y = P_HEN;
			
			mt1 = Picture.hight;
			mt2 = P_HEN;
		}

	}
	else
	{
		P_mag = 1;
		P_L = Picture.weight;
		P_H = Picture.hight;

		P_X = ((P_LEN - P_L) / 2);
		P_Y = P_HEN - ((P_HEN - P_H) / 2);
		
		mt1 = 1;
		mt2 = 1;
	}
	
	for(int k = P_H; k > 0; k --)
	{
		pl = 0;
		for(int m = 0; m < len1; m++)
		{
			f_lseek(&ftp, Picture.offset + (P_mand(mt1, mt2, (k - 1)) * Picture.weight + m * P_LEN)* Picture.count);
			f_read(&ftp, Picture.rgba, Picture.count * P_LEN, &brt);
			
			for(int j = pl; j < P_L; j ++)
			{
				Pb = P_mand(mt1, mt2, j);
				
				if(Pb < (m + 1) * P_LEN)
				{
					Picture.color[j] = P_TranColor(Picture.rgba[(Pb % P_LEN) * Picture.count + 0], Picture.rgba[(Pb % P_LEN) * Picture.count + 1 ], Picture.rgba[(Pb % P_LEN) * Picture.count + 2]);
				}
				else
				{
					pl = j;
					break;
				}
			}
		}

		f_lseek(&ftp, Picture.offset + (P_mand(mt1, mt2, (k - 1)) * Picture.weight + len1 * P_LEN) * Picture.count);
		f_read(&ftp, Picture.rgba, Picture.count * len2, &brt);
		
		for(int j = pl; j < P_L; j ++)
		{
			Pb = P_mand(mt1, mt2, j);

			if(Pb < (len1 * P_LEN + len2))
			{
				Picture.color[j] = P_TranColor(Picture.rgba[(Pb % P_LEN) * Picture.count + 0], Picture.rgba[(Pb % P_LEN) * Picture.count + 1 ], Picture.rgba[(Pb % P_LEN) * Picture.count + 2]);			
			}
			else
			{
				pl = j;
				break;
			}
		}
		
		LCD_SetCursor(P_X, P_Y - 1 - (k - 1));
		LCD_WriteRAM_Start();
		for(int kt = 0; kt < P_L; kt++)
		{
			LCD_SendData(Picture.color[kt]);
		}
	}
	
	f_close(&ftp);
}

2.3 格式转换

uint16_t P_TranColor(uint8_t P_Blue, uint8_t P_Green, uint8_t P_Red)//24位(RGBA格式实际为32位,最后8位舍弃)转为16位颜色;
{
    uint16_t P_Color = 0;
    P_Color = (uint16_t)(P_Blue >> 3) | ((uint16_t)(P_Green >> 2) << 5) | ((uint16_t)(P_Red >> 3) << 11);
    return P_Color;
}

/*缩放图片(通过四舍五入找出需要的像素点)*/
int P_mand(int len1, int len2, int num) //原始图片像素数/屏幕实际像素数 * 第几个像素;
{
    int sum = 0;
    sum = (len1 * num) / len2;
    
    if( 2 * ((len1 * num) % len2) >= len2)
    {
        sum += 1;
    }
    return sum;
}

int P_rand(float temp)//将小数四舍五入成整数;
{
    int kemp = 0;
    float memp = 0;
    kemp = (int)temp;
    memp = temp - kemp;
    if(memp >= 0.5)
    {
        kemp = kemp + 1;
    }

    return kemp;
}

3.实现效果

将图片拷贝到sd卡,插入开发板中,然后将程序下载到开发板中,本文中使用的正点原子的stm32mini板,其他开发板视情况自行修改,效果如下:

4.源码地址

百度网盘地址:https://pan.baidu.com/s/1eMTKy2vSxBybVcjuAfkY5Q?pwd=31ji 提取码: 31ji

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值