图片播放器(七):PNG图片的显示函数

1.思路分析

(1)png更像是jpg而不像是bmp
(2)png和jpg都是压缩格式的图片,都是二进制文件,不同之处是压缩和解压缩的算法不同。
(3)通过libjpeg来编解码jpg图片,那么同样有一个libpng用来编解码png图片。
(4)工作思路和顺序:找到并移植并部署libpng,然后查readme和其他文档示例代码等来使用libpng提供的API来对png图片进行解码,并将解码出来的数据丢到framebuffer中去显示。


2.libpng移植

(1)下载源码包:
(2)解压、配置、修改Makefile、编译、部署
./configure --host=arm-linux --enable-shared --enable-static --prefix=/open_source/PNG/png_1.6.7/libdecode
(3)配置出错,报错信息:configure: error: zlib not installed
分析问题是因为libpng依赖于zlib库,所以要先移植zlib库才可以。
(4)转而去移植zlib,移植后再过来配置,还是报错,原因是因为没有导出相关环境变量,所以libpng在配置的时候找不到刚才移植的zlib库的库文件和头文件。
(5)解决方案就是使用epport临时性的导出,
# export LDFLAGS="-L/open_source/ZLIB/zlib-1.2.8/libdecode/lib"
# export CFLAGS="-I/open_source/ZLIB/zlib-1.2.8/libdecode/include"
# export CPPFLAGS="-I/open_source/ZLIB/zlib-1.2.8/libdecode/include"
(6)导出后再次配置./configure --host=arm-linux --enable-shared --enable-static --prefix=/open_source/PNG/png_1.6.7/libdecode
(7)make && make install

(8)得到Makefile

3.zlib移植

(1)下载:http://www.zlib.net/,并解压
(2)配置:export CC=arm-linux-gcc      
        ./configure -shared --prefix=/open_source/ZLIB/zlib-1.2.8/libdecode
(3)make

(4)make install
(5)make install后/opt/libdecode目录下的lib和include目录下就有了zlib的静态库动态库和头文件了

(6)回到libpng移植


4.解码显示png图片

1.参考源码包自带的资料
(1)readme
(2)libpng-manual.txt
(3)example.c 和 pngtest.c

 

重要结构体:

/* png 头信息 */
struct png_head_data
{
	unsigned short w;  /* 图片宽 */
	unsigned short h;  /* 图片高 */
	unsigned int   bpp;  /* 图片的BPP信息 */
	unsigned int   channels;  /* 获取通道数 */
	unsigned int   color_type;
};

全局变量和宏定义:

因为png可以检测文件头8个字节中的任意几个字节,所以可以自己设定。

#define SHOW_MAX_W  1920
#define SHOW_MAX_H  1080
#define PNG_BYTES_TO_CHECK 4   /* 要检查文件的前多少个字节 */

static unsigned char png_picture[SHOW_MAX_W * SHOW_MAX_H * 3] = {0};  /* 当前播放器正在显示的的图片的有效数据数组 (最大值)*/

 

png 显示的核心函数:

/* png 显示的核心函数 */
void fb_show_png(struct show_picture_set *set, unsigned int *pfb)
{
	struct png_head_data *st_pi = malloc(sizeof(struct png_head_data));
	const char *p_path = set->path;


	fb_file_to_png(p_path, st_pi);  /* 从bmp文件中读头信息 和有效信息 */

	switch (set->rotate){
	case ROTATE_FRONT:
		fb_png_front_show(set, st_pi, pfb);  /* bmp 图片正方向显示 */
		break;
	case ROTATE_180:
		fb_png_180_show(set, st_pi, pfb);  /* bmp 图片旋转180方向显示 */
		break;
	case ROTATE_MIRROR_180:
		fb_png_mirror_180_show(set, st_pi, pfb);
		break;
	case ROTATE_MIRROR:
		fb_png_mirror_show(set, st_pi, pfb);
		break;
	}

	free(st_pi);
}

判断是否为 png 文件:

/* 判断是否为 png 文件*/
char fb_is_png(const     char *path)
{
	unsigned char *buf = malloc(sizeof(PNG_BYTES_TO_CHECK));
	FILE *fp = NULL;

	if ((fp = fopen(path, "rb")) == NULL){
		DERROR("NO [%s] file\n", path);
		return 'O';
	}

	if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK){//读取4字节
		DERROR("read [%s] file error\n", path);
		fclose(fp);
		return 'R';
	}

	/*判断前 PNG_BYTES_TO_CHECK 个字节是否是 (89 50 4E 47 0D 0A 1A 0A 16进制) */
	if(png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)){ //判断前4字节
		DERROR("It's not a BMP file\n");
		fclose(fp);
		return 'N';
	}else{
		fclose(fp);
		return 'Y';
	}
}

 

从png文件中读头信息:

/* 从png文件中读头信息 */
int fb_file_to_png(const        char *path, void *st_pi)
{
	FILE *fp = NULL;
	png_structp png_ptr;
	png_infop info_ptr;
	struct png_head_data *head_data = st_pi;
	unsigned char **row_pointers = NULL;
	
	if ((fp = fopen(path, "rb")) == NULL){
		DERROR("open %s file fail\n", path);
		return -1;
	}
		   
	/* Allocate/initialize the memory for image information.  REQUIRED. */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);	
	if (png_ptr == NULL){
		fclose(fp);
		return -1;
	}
		
	
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL){
		fclose(fp);
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		return -1;
	}
		
	if (setjmp(png_jmpbuf(png_ptr))){
		/* Free all of the memory associated with the png_ptr and info_ptr */
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		fclose(fp);
		/* If we get here, we had a problem reading the file */
		return -1;
	}

	/* 第3步: 将要解码的png图片的文件指针和png解码器绑定起来 */
	png_init_io(png_ptr, fp);

	/* 第4步: 读取png图片信息 */
	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);


	/* 第5步: 相关图片信息打印出来看一看 */
	head_data->w = info_ptr->width;
	head_data->h = info_ptr->height;
	head_data->bpp = info_ptr->pixel_depth;
	head_data->channels = info_ptr->channels; /*获取通道数*/
	head_data->color_type = info_ptr->color_type;

	DEBUG("width = %u, height = %u, bpp = %u\n", info_ptr->width, info_ptr->height, info_ptr->pixel_depth);

	/* 第6步: 读取真正的图像信息 */
	row_pointers = png_get_rows(png_ptr,info_ptr);

	fb_png_read_file(path, st_pi, row_pointers); /* 从文件中读有效数据到 now_picture 中 */


	/* 第7步: 收尾处理 */
	png_destroy_read_struct(&png_ptr, &info_ptr, 0);
	// close file
	fclose(fp);

	return 0;

}

从文件中读有效数据到 png_picture 中:

/*  从文件中读有效数据到 png_picture 中*/
int fb_png_read_file(const         char *path, struct png_head_data *head_data, unsigned char **row_pointers)
{
	int temp, pos = 0;
	int i, j;

	/* 第7步: 图像数据移动到我们自己的buf中 */
	/* 只处理RGB24位真彩色图片 和 RGB24+ 透明度图片 */
	if(head_data->channels == 4 || head_data->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	{/*如果是RGB+alpha通道,或者RGB+其它字节*/ 
		temp = (4 * head_data->w);   /* 每行有4 * out->width个字节 */
		for(i = 0; i < head_data->h; i++)
		{
			for(j = 0; j < temp; j += 4)
			{/* 一个字节一个字节的赋值 */
				png_picture[pos++] = row_pointers[i][j]; // red
				png_picture[pos++] = row_pointers[i][j+1]; // green
				png_picture[pos++] = row_pointers[i][j+2];  // blue
				png_picture[pos++] = row_pointers[i][j+3]; // alpha
			}
		}
	}
	else if(head_data->channels == 3 || head_data->color_type == PNG_COLOR_TYPE_RGB)
	{/* 如果是RGB通道 */
		temp = (3 * head_data->w);/* 每行有3 * out->width个字节 */
		for(i = 0; i < head_data->h; i++)
		{
			for(j = 0; j < temp; j += 3)
			{/* 一个字节一个字节的赋值 */
				png_picture[pos++] = row_pointers[i][j]; // red
				png_picture[pos++] = row_pointers[i][j+1]; // green
				png_picture[pos++] = row_pointers[i][j+2];  // blue
			}
		}
	}
	else{
		DERROR("This [%s] file is not supported", path);
		return -1;
	}

	return 0;
}

图片显示函数:


/* png 图片正方向显示 */
void fb_png_front_show(struct show_picture_set *set, struct png_head_data *head_data, unsigned int *pfb)
{
	int x, y;
	unsigned int cont1 = 0, cont2 = 0;
	unsigned int *p_data = pfb;

	for(y = 0; y < head_data->h; y++)		
	{
		if((y + set->h) >= HEIGHT)
			break;
		for(x = 0; x < head_data->w; x++)
		{
			if((x + set->w) >= WIDTH){
				cont1 += 3;
				continue;
			}
			
			cont2 = (y + set->h) * WIDTH + x + set->w;

			*(p_data + cont2) = ((png_picture[cont1 + 0] << 16) | (png_picture[cont1 + 1] << 8) | (png_picture[cont1 + 2] << 0));
			cont1 += 3;
		}
	}
}


/* png 图片旋转180方向显示 (不是当前图片旋转 180,是绝对而不是相对)*/
void fb_png_180_show(struct show_picture_set *set, struct png_head_data *head_data, unsigned int *pfb)
{
	int x, y;
	unsigned int cont2 = 0, cont1 = ((head_data->h * head_data->w * 3) - 3);
	unsigned int *p_data = pfb;

	for(y = 0; y < head_data->h; y++)		
	{
		if((y + set->h) >= HEIGHT)
			break;
		for(x = 0; x < head_data->w; x++)
		{
			if((x + set->w) >= WIDTH){
				cont1 -= 3;
				continue;
			}
			
			cont2 = (y + set->h) * WIDTH + x + set->w;

			*(p_data + cont2) = ((png_picture[cont1 + 0] << 16) | (png_picture[cont1 + 1] << 8) | (png_picture[cont1 + 2] << 0));
			cont1 -= 3;
		}
	}
}


/* png 图片 ( 镜像翻转 + 旋转180方向 )显示 (不是当前图片旋转 180,是绝对而不是相对)*/
void fb_png_mirror_180_show(struct show_picture_set *set, struct png_head_data *head_data, unsigned int *pfb)
{
	int x, y;
	unsigned int cont2 = 0, cont1 = ((head_data->h * head_data->w * 3) - 3);
	unsigned int *p_data = pfb;

	for(y = 0; y < head_data->h; y++)		
	{
		if((y + set->h) >= HEIGHT)
			break;
		for(x = head_data->w -1 ; x >= 0; x--)
		{
			if((x + set->w) >= WIDTH){
				cont1 -= 3;
				continue;
			}
			
			cont2 = (y + set->h) * WIDTH + x + set->w;

			*(p_data + cont2) = ((png_picture[cont1 + 0] << 16) | (png_picture[cont1 + 1] << 8) | (png_picture[cont1 + 2] << 0));
			cont1 -= 3;
		}
	}
}

/* png 图片 ( 镜像翻转 )显示 (不是当前图片翻转,是绝对而不是相对)*/
void fb_png_mirror_show(struct show_picture_set *set, struct png_head_data *head_data, unsigned int *pfb)
{
	int x, y;
	unsigned int cont2 = 0, cont1 = 0;
	unsigned int *p_data = pfb;

	for(y = 0; y < head_data->h; y++)		
	{
		if((y + set->h) >= HEIGHT)
			break;
		for(x = head_data->w -1 ; x >= 0; x--)
		{
			if((x + set->w) >= WIDTH){
				cont1 += 3;
				continue;
			}
			
			cont2 = (y + set->h) * WIDTH + x + set->w;

			*(p_data + cont2) = ((png_picture[cont1 + 0] << 16) | (png_picture[cont1 + 1] << 8) | (png_picture[cont1 + 2] << 0));
			cont1 += 3;
		}
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值