libpng的png_read_info和png_read_image使用实例分析

编译开源库以及使用官方例程

使用的是libpng-1.6.17

$ ./configure CC=gcc --prefix=$PWD/_install
$ make && make install 

官方例程:libpng-1.6.17\contrib\libtests
fakepng.c
makepng.c
pngimage.c
pngstest.c
pngunknown.c
pngvalid.c
readpng.c
timepng.c

libpng库读取文件常用接口

libpng库解析图片主要用的函数大致有:
(可以使用libpng-manual.txt手册查看库中提供的相关接口使用说明)

png_sig_cmp(sig, 0, 8):
it will return 0 (false) if the bytes match the corresponding bytes of the PNG signature;
验证PNG文件的正确性完整性;
如果你已经使用png_sig_cmp函数来检查了png数据,需要调用png_set_sig_bytes函数来告诉libpng库,这样库处理数据的时候将会跳过相应的数据

png_set_sig_bytes(png_ptr, 8);
Tell lib we have already handled the first “8” magic bytes.
Handling more than 8 bytes from the beginning of the file is an error.
设置读取PNG文件的指针偏移量,不能超过8位(用于配置png_sig_cmp的使用);

setjmp(png_jmpbuf(png_ptr))
When libpng encounters an error, it expects to longjmp back to your routine;
设置发生错误时返回错误时调用的位置;
用setjmp/longjmp函数来处理异常。libpng库默认集成这种机制来完成异常处理;
如果设置了用户自定义的错误处理函数,libpng将会调用用户自定义错误处理函数,而不会返回到这个设置了默认返回点的调用点上;

png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL);
If you want to use your own memory allocation routines,
use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use
png_create_read_struct_2() instead of png_create_read_struct():
创建读取文件的结构体,如果需要使用自定义内存段,则调用png_create_read_struct_2() 进行自定义创建结构体;

png_create_info_struct(png_ptr);
The preferred method of creating and initializing the libpng structures…
allow version error checking, and also allow the
use of custom error handling routines during the initialization, which
the old functions do not.
使用库内部函数创建结构体,有利于库内部对程序出现的错误进行相关检测;

png_init_io(png_ptr, trfile);
检查文件的完整性

png_read_info(png_ptr, info_ptr);
读取图片文件详细信息以及参数

png_get_rowbytes(png_ptr,info_ptr);
逐行读取图片文件数据

png_read_image(png_ptr, row_pointers);
读取整个图片的所有数据,如果不需要一次性全部读完,可以使用png_get_rowbytes逐行读取;
我将分别列举这两种方式解析图片数据的例程,往下看……

使用png_read_image读取图片数据

// readpngdemo.c
// gcc -I../include -I../.. -o readpngdemo readpngdemo.c ./libpng.a ./libz.a -lm
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <config.h>
#include <png.h>
#include "pngstruct.h"
#include "pnginfo.h"

int main(){
    FILE *fp;
    fp = fopen((char*)"pngread.png", "rb");

    png_byte sig[8];
    fread(sig, 1, 8, fp);
    if(png_sig_cmp(sig, 0, 8)){
            fclose(fp);
            return 0;
        }

    png_structp png_ptr;
        png_infop info_ptr;

    png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);
    setjmp(png_jmpbuf(png_ptr));
    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, 8); 
    png_read_info(png_ptr, info_ptr);

    printf("%s(%s)PNG INFO:\n", __FILE__, __FUNCTION__);
    printf("pixel_depth = %d\n", info_ptr->pixel_depth);
    printf("bit_depth = %d\n", info_ptr->bit_depth);
    printf("width = %d\n", info_ptr->width);
    printf("height = %d\n", info_ptr->height);

    png_bytep row_pointers[info_ptr->height];
    int row; 
    for (row = 0; row < info_ptr->height; row++){
            row_pointers[row] = NULL;
    }
    for (row = 0; row < info_ptr->height; row++){
            row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr,info_ptr));
    }
    png_read_image(png_ptr, row_pointers);     
    int i, j;
    int size = (info_ptr->width) * (info_ptr->height) * 4;
    printf("malloc(%d)\n", size);
    unsigned long *pDst = (unsigned long*)malloc(size);//因为sizeof(unsigned long)=8
    printf("sizeof(unsigned long) = %d\n", (int)sizeof(unsigned long));
    if(info_ptr->pixel_depth == 32){
        unsigned char* pSrc;
        unsigned long pixelR,pixelG,pixelB,pixelA;
        for(j=0; j<info_ptr->height; j++){
            pSrc = row_pointers[j];
            for(i=0; i<info_ptr->width; i++){
                pixelR = *pSrc++;
                pixelG = *pSrc++;
                pixelB = *pSrc++;
                pixelA = *pSrc++;
                pDst[i] = (pixelA<< 24) | (pixelR << 16) | (pixelG << 8) | pixelB;
                printf("%08x ", pDst[i]);
            }
            printf("\n");
            pDst += info_ptr->width;
        }
    }
    printf("%s(%s)END READ\n", __FILE__, __FUNCTION__);
    for (row = 0; row < info_ptr->height; row++){
        png_free(png_ptr,row_pointers[row]);
    }
    return 0;
}

运行结果

$ gcc -I../include -I../.. -o readpngdemo readpngdemo.c ./libpng.a ./libz.a -lm
gcc -I../include -I../.. -o readpngdemo readpngdemo.c ./libpng.a ./libz.a -lm
readpngdemo.c: In function ‘main’:
readpngdemo.c:61: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘long unsigned int’
$ ./readpngdemo
readpngdemo.c(main)PNG INFO:
pixel_depth = 32
bit_depth = 8
width = 10
height = 20
malloc(800)
sizeof(unsigned long) = 8
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
readpngdemo.c(main)END READ

看输出就猜得到图片的样子了吧
这里写图片描述
(pngread.png)
图片旁边的数字标识是我手动加进去的,实际图片大小只有10*20个像素点,这里放大来展示

使用png_read_rows逐行读取图片数据

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <config.h>
#include <png.h>
#include "pngstruct.h"
#include "pnginfo.h"

int main(){
    FILE *fp;
    fp = fopen((char*)"pngread.png", "rb");

    png_byte sig[8];
    fread(sig, 1, 8, fp);
    if(png_sig_cmp(sig, 0, 8)){
            fclose(fp);
            return 0;
        }

    png_structp png_ptr;
    png_infop info_ptr;

    png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);
    setjmp(png_jmpbuf(png_ptr));
    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, 8); 
    png_read_info(png_ptr, info_ptr);

    printf("%s(%s)PNG INFO:\n", __FILE__, __FUNCTION__);
    printf("pixel_depth = %d\n", info_ptr->pixel_depth);
    printf("bit_depth = %d\n", info_ptr->bit_depth);
    printf("width = %d\n", info_ptr->width);
    printf("height = %d\n", info_ptr->height);

    /*0:非隔行扫描(逐行扫描)1:7遍隔行扫描方法*/
    int num_pass = 1; 
    if(info_ptr->interlace_type == PNG_INTERLACE_NONE){
        num_pass = 1;
    }else if(info_ptr->interlace_type == PNG_INTERLACE_ADAM7){
        num_pass = 7;
    }

    int pass;
    png_bytep row_buf;

    unsigned char* pSrc;
    unsigned long pixelR,pixelG,pixelB,pixelA;

    int i, j;
    int size = (info_ptr->height) * 4;
    printf("malloc(%d)\n", size);
    unsigned long *pDst;

    printf("%s(%s)num_pass=%d\n", __FILE__, __FUNCTION__, num_pass);
    for (pass = 0; pass < num_pass; pass++) {
        if(info_ptr->pixel_depth == 32){
            for (i = 0; i < info_ptr->height; i++) {
                row_buf = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
                png_read_rows(png_ptr, (png_bytepp)&row_buf, NULL, 1);
                pDst = (unsigned long*)malloc(size);//因为sizeof(unsigned long)=8
                pSrc = row_buf;
                for(j=0; j<info_ptr->width; j++){
                    pixelR = *pSrc++;
                    pixelG = *pSrc++;
                    pixelB = *pSrc++;
                    pixelA = *pSrc++;
                    pDst[i] = (pixelA<< 24) | (pixelR << 16) | (pixelG << 8) | pixelB;
                    printf("%08x ", pDst[i]);
                }
                printf("\n");
                png_free(png_ptr, row_buf);
                row_buf = NULL;
            }
        }
        printf("\n");
    }
    printf("%s(%s)END READ\n", __FILE__, __FUNCTION__);
    return 0;
}

运行结果:

$ gcc -I../include -I../.. -o readrowdemo readrowdemo.c ./libpng.a ./libz.a -lm
gcc -I../include -I../.. -o readrowdemo readrowdemo.c ./libpng.a ./libz.a -lm
readrowdemo.c: In function ‘main’:
readrowdemo.c:69: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘long unsigned int’
$ ./readrowdemo
readrowdemo.c(main)PNG INFO:
pixel_depth = 32
bit_depth = 8
width = 10
height = 20
malloc(80)
readrowdemo.c(main)num_pass=1
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff ff0000ff 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 
ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 ffff0000 

readrowdemo.c(main)END READ 

这里38行info_ptr->interlace_type使用了识别图片是否为非逐行扫描方式存储像素点的方式(Adam7);
嗯,但是我写DEMO程序的时候仍然使用的是逐行扫描方式的位深度为32的PNG图片,主要是不会使用PHOTOSHOP制作Adam7隔行扫描方式的图片;
引用一张网上的图片说明一下Adam7的扫描方式:
这里写图片描述
来自于:http://www.warting.com/design/201507/85595.html

关于解码位深度为24位图片的写法

for (i = 0; i < info_ptr->height; i++) {
    //......
    for(j=0; j<info_ptr->width; j++){
        pixelR = *pSrc++;
        pixelG = *pSrc++;
        pixelB = *pSrc++;
        pDst[i] = 0xFF000000 | (pixelR << 16) | (pixelG << 8) | pixelB;
        printf("%08x ", pDst[i]);
    }
}

本文只总结了关于图片的读取部分,至于写图片,制作图片,其实官方例程已经给出来了,以后需要用到再做下一步分析

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值