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;
}
}
}