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
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我不确定您具体的应用场景,但是 PNG_jmpbuf 通常是在使用 libpng 库时需要加入的。 PNG_jmpbuf 是一个跳转缓冲区,用于处理 PNG 图像解码过程中的错误。在程序运行过程中,如果遇到错误需要跳转到错误处理代码,PNG_jmpbuf 会保存当前执行的状态以便在错误处理代码中恢复。在 libpng 库中,PNG_jmpbuf 通常定义为一个结构体类型。 以下是一个使用 libpng 库解码 PNG 图像的示例,其中包含了 PNG_jmpbuf 的定义和使用: ``` #include <png.h> void read_png_file(char* file_name) { png_structp png_ptr; png_infop info_ptr; png_bytep* row_pointers; FILE* fp = fopen(file_name, "rb"); png_byte header[8]; if (!fp) { printf("[read_png_file] File %s could not be opened for reading", file_name); return; } fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { printf("[read_png_file] File %s is not a valid PNG", file_name); fclose(fp); return; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("[read_png_file] png_create_read_struct failed"); fclose(fp); return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("[read_png_file] png_create_info_struct failed"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return; } if (setjmp(png_jmpbuf(png_ptr))) { printf("[read_png_file] Error during png_read_image"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } if (bit_depth == 16) { png_set_strip_16(png_ptr); } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) { png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_read_update_info(png_ptr, info_ptr); row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); for (int y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, row_pointers); for (int y = 0; y < height; y++) { png_bytep row = row_pointers[y]; for (int x = 0; x < width; x++) { png_bytep px = &(row[x * 4]); // process pixel } } for (int y = 0; y < height; y++) { free(row_pointers[y]); } free(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); } ``` 在此示例中,PNG_jmpbuf 在 `if (setjmp(png_jmpbuf(png_ptr)))` 中被使用。如果 `png_read_image` 函数执行过程中出现错误,程序会跳转到 `setjmp` 处,并执行由 `if` 语句内的代码块处理错误。在处理完成后,程序会继续执行 `png_read_image` 函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值