嵌入式基于Linux、ARM的LCD的BMP图片的缩小、任意位置显示

更多资料请点击:我的目录
本篇仅用于记录自己所学知识及应用,代码仍可优化,仅供参考,如果发现有错误的地方,尽管留言于我,谢谢。

这一片是关于开发板800480的LCD显示屏显示BMP图片的,可以通过参数设置,将各种像素大小的BMP图片在任意位置显示,在800480像素范围内的BMP图像可以直接在任意位置显示,而大于800*480像素范围的则需要先将BMP图片先缩小,再设置位置。显示方式是使用内存映射方式(mmap),刷图显示速度比较快。

下面为封装好的BMP图像显示函数

//显示任意位置大小缩放的BMP图片
bool showbmp(char *bmppath, int n)							//调用函数传参,bmppath为路径名,n缩小倍数
{
	int w = 0;
	int h = 0;
	int src = open(bmppath , O_RDWR);						//打开BMP图片文件
	
	lseek(src, 18 ,SEEK_SET);								//获取BMP图片的宽w信息
	read(src, &w, 4);
	lseek(src, 22 ,SEEK_SET);								//获取BMP图片的高h信息
	read(src, &h, 4);
	
	char bmpbuf[w*h*3];
	int  lcdbuf[w*h];
	int  tempbuf[w*h];
	
	lseek(src, 54, SEEK_SET);								//跳过BMP图片头信息字节
	
	int rubbish = (4-(w*3)%4)%4;							//BMP图片字节不能被4整除时,加入的垃圾字节数
	for(int i = 0; i < h; i++)
	{
		read(src, &bmpbuf[w*i*3],w*3);
		lseek(src, rubbish, SEEK_CUR);						//在字节读入时,跳过垃圾字节
	}
		
	for(int i = 0; i < w*h; i++)							//将RGB转换成BGR
	{
		lcdbuf[i] = 0x00<<24 | bmpbuf[i*3+2]<<16 | bmpbuf[i*3+1]<<8 | bmpbuf[i*3];
	}
	
	for(int i = 0; i < w; i++)
	{
		for(int j = 0; j < h; j++)
		{
			tempbuf[(h-1-j)*w+i] = lcdbuf[j*w+i];			//BMP像素点上下反转
		}
	}
	
	//内存映射
	int *mmap_bmp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, dst, 0);

	for(int i=0; i<h/n; i++) 								//图片的高度h / 缩放倍数n
	{
		for(int j=w*n*i,k=0; j<(w*n*i+w);j+=n,k++) 			//循环决定每行该取的像素点
		{
			//任意位置(480-h/n)/2)、(800-w/n)/2)、缩小倍数n
			*(mmap_bmp+800*(((480-h/n)/2)+i)+((800-w/n)/2)+k) = tempbuf[j];
		}
	}

	//解除内存映射
	munmap(mmap_bmp, 800*480*4);
	close(src);
}

拆分注释:

这个部分是用于解决BMP像素宽度W3字节数不能被4整除时出现下图的情况,因为宽度W3字节数不能被4整除时,系统会在文件每一行的末尾加上无效字节,当我们读取(read)图片文件时就会把无效字节读入,导致出现下图的情况。解决这个问题,只需要计算出每一行加入的无效字节数,在读取文件每一行数据时用lseek跳过那几个无效字节。

	int rubbish = (4-(w*3)%4)%4;							//BMP图片字节不能被4整除时,加入的垃圾字节数
	for(int i = 0; i < h; i++)
	{
		read(src, &bmpbuf[w*i*3],w*3);
		lseek(src, rubbish, SEEK_CUR);						//在字节读入时,跳过垃圾字节
	}

在这里插入图片描述
原图:
在这里插入图片描述

这个部分是用于解决BMP图片显示时存在色差的问题,需要将颜色通道重新置位,才能显示正常的图片颜色

	for(int i = 0; i < w*h; i++)							//将RGB转换成BGR
	{
		lcdbuf[i] = 0x00<<24 | bmpbuf[i*3+2]<<16 | bmpbuf[i*3+1]<<8 | bmpbuf[i*3];
	}

这个部分是用于解决BMP图片显示时图片上下翻转的问题

for(int i = 0; i < w; i++)
{
	for(int j = 0; j < h; j++)
	{
		tempbuf[(h-1-j)*w+i] = lcdbuf[j*w+i];			//BMP像素点上下反转
	}
}

这个部分是用于设置任意位置、缩放倍数的,h为BMP图片的高度像素值,w为BMP图片的宽度像素值,n为缩小倍数,不需要缩小时给n传参1,即再下段代码

for(int i=0; i<h/n; i++) 								//图片的高度h / 缩放倍数n
{
	for(int j=w*n*i,k=0; j<(w*n*i+w);j+=n,k++) 			//循环决定每行该取的像素点
	{
		//任意位置(480-h/n)/2)、(800-w/n)/2)、缩小倍数n
		*(mmap_bmp+800*(((480-h/n)/2)+i)+((800-w/n)/2)+k) = tempbuf[j];
	}
}

不需要缩小:

for(int i=0; i<h; i++) 
{
	for(int j=w*i; j<(w*i+w); j++)
	{
		*(mmap_bmp+800*(((480-h)/2)+i)+((800-w)/2)+j) = tempbuf[j];
	}
}

移位则只需要对这两公式进行更改,可以加入变量,也可以设置为常数,如(480-h)/2),就是用显示屏480的高度像素值减去BMP图片的高度像素值再除以2,让图片刚好显示在纵轴的中间位置,同理(800-w)/2)就是让图片显示在横轴的中间位置。换成常数的话,就是图片的左上角坐标的起始点。

以下是嵌入式基于LinuxARMLCDBMP图片缩小的代码示例,使用了SDL图形库: ```c #include <stdio.h> #include <stdlib.h> #include "SDL/SDL.h" int main(int argc, char **argv) { SDL_Surface *image, *resized; SDL_Rect dest; if (SDL_Init(SDL_INIT_VIDEO) != 0) { fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); return 1; } image = SDL_LoadBMP("image.bmp"); if (image == NULL) { fprintf(stderr, "Unable to load image: %s\n", SDL_GetError()); SDL_Quit(); return 1; } resized = SDL_CreateRGBSurface(SDL_SWSURFACE, image->w / 2, image->h / 2, 24, 0xff0000, 0x00ff00, 0x0000ff, 0); if (resized == NULL) { fprintf(stderr, "Unable to create resized image: %s\n", SDL_GetError()); SDL_FreeSurface(image); SDL_Quit(); return 1; } if (SDL_SoftStretch(image, NULL, resized, NULL) != 0) { fprintf(stderr, "Unable to resize image: %s\n", SDL_GetError()); SDL_FreeSurface(image); SDL_FreeSurface(resized); SDL_Quit(); return 1; } SDL_FreeSurface(image); dest.x = 100; // x coordinate of top-left corner of the image dest.y = 100; // y coordinate of top-left corner of the image dest.w = resized->w; dest.h = resized->h; SDL_Surface *screen = SDL_SetVideoMode(640, 480, 24, SDL_SWSURFACE); if (screen == NULL) { fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError()); SDL_FreeSurface(resized); SDL_Quit(); return 1; } SDL_BlitSurface(resized, NULL, screen, &dest); SDL_Flip(screen); SDL_Delay(5000); // wait for 5 seconds before quitting SDL_FreeSurface(resized); SDL_Quit(); return 0; } ``` 这段代码中,先使用SDL_LoadBMP函数加载BMP图片,然后使用SDL_CreateRGBSurface函数创建一个新的Surface来存储缩小后的图像,使用SDL_SoftStretch函数对图像进行缩小,最后使用SDL_BlitSurface函数将缩小后的图像显示屏幕上。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佳佳鸽

若文章帮到你,能不能请我喝杯茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值