2012-05-03 89 views
2

我正在嘗試使用libpng編寫一個漸進閱讀器。我試圖遵循lib提供的example.c中的代碼,但它不起作用。我也看過libpng doc。其中指示您使用png_set_progressive_read_fn()png_process_data()聯繫。按照文檔中的規定設置之後。當我開始讀取png文件的過程時,我從libpng中得到以下錯誤。libpng - 錯誤:不是PNG文件 - png_process_data()

Not a PNG file

逐步執行代碼顯示,當png_process_data()去檢查PNG文件的簽名,它標識,它不是一個PNG文件。這是非常奇怪的行爲,因爲在我調用我的讀函數之前,我使用以下代碼驗證文件是否爲PNG文件。

int check_png_sig(const char * file_name) 
{ 
    FILE *fp = fopen(file_name, "rb"); 
    if(!fp) { 
    return (0); 
    } 
    enum HeaderSize {Size = 8}; 
    png_byte header[Size]; 
    fread(header, 1, Size, fp); 
    int is_png = !png_sig_cmp(header, 0, Size); 
    if (!is_png) { 
    fclose(fp); 
    return (0); 
    } 
    fclose(fp); 
    return (1); 
} 

我關閉FILE*,然後重新打開在我讀功能一個新的,所以我沒有告訴libpng的,我已經讀8個字節png_set_sig_bytes(png_ptr, 8);。我的閱讀功能如下。

int read_png_file(const char * file_name) 
{ 
    fprintf(stdout, "Reading PNG File %s\n", file_name); 
    fflush(stdout); 

    if (!png_ptr || !info_ptr) { 
    return (0); 
    } 

    FILE *fp = fopen(file_name, "rb"); 
    if(!fp) { 
    return (0); 
    } 

    png_init_io(png_ptr, fp); 
    png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr); 

    /* 
    * Tell libpng to call read_chunk_callback if an unknown chunk is 
    * encountered 
    */ 
    png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback); 

    /* 
    * Tell libpng to call read_row_callback if an known chunk is 
    * encountered. 
    */ 
    png_set_read_status_fn(png_ptr, read_row_callback); 

    /* 
    * Tell libpng to call the specified functions on info, rows, or 
    * end. 
    */ 
    png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback, 
    row_callback, end_callback); 

    enum Size {DataSize = 8}; 
    unsigned char rawbuf[DataSize]; 
    int process = 1; 
    if (setjmp(png_jmpbuf(png_ptr))) { 
    free_png_resources(); 
    process = 0; 
    return process; 
    } 

    /* 
    * Check to see if libpng is confused 
    */ 
    //png_set_sig_bytes(png_ptr, 8); 

    while (process) { 
    memset(rawbuf, 0, DataSize); 
    png_process_data(png_ptr, info_ptr, rawbuf, DataSize); 
    } 

    fclose(fp); 
    return (process); 
} 

我也有在(non-progressive reader)非porgressive閱讀器的工作版本。它在我的文件上工作得很好。所以這不是我的文件的問題。


完整代碼

#include <png.h> 
#include <stdlib.h> 

static png_structp png_ptr; 
static png_infop info_ptr; 
static png_bytep old_row = NULL; 

/* Variable that loops untill data is read */ 
int run = 0; 

//------------------------------------------------------------------- 
// Callbacks 
int read_chunk_callback(png_structp png_ptr, png_unknown_chunkp chunk) 
{ 
    struct chunk 
    { 
    png_byte name[5]; 
    png_byte *data; 
    png_size_t size; 
    }; 

    return (0); /* did not recognize */ 
} 

/* 
* This method will be called each time a row is read 
* and differs from the row_callback in that ... 
*/ 
void read_row_callback(png_structp ptr, png_uint_32 row, int pass) 
{ 
    fprintf(stderr, "read_row_callback\n"); 
} 

int process_data(png_bytep buffer, png_uint_32 length) 
{ 
    fprintf(stderr, "process_data\n"); 
    png_process_data(png_ptr, info_ptr, buffer, length); 
    return 0; 
} 

void info_callback(png_structp png_ptr, png_infop info) 
{ 
    fprintf(stderr, "info_callback\n"); 
    png_uint_32 width; 
    png_uint_32 height; 
    int   bit_depth; 
    int   color_type; 
    int   interlace_type; 
    int   compression_type; 
    int   filter_type; 
    png_byte channels; 
    png_uint_32 rowbytes; 
    png_bytep signature; 

    /* 
    * This will get the information stored in the header 
    * of the PNG file. 
    */ 
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 
    &interlace_type, &compression_type, &filter_type); 

    /* 
    * Get the rest of the header information. 
    */ 
    channels = png_get_channels(png_ptr, info_ptr); 
    /* This is subject to change with transformations */ 
    rowbytes = png_get_rowbytes(png_ptr, info_ptr); 
    signature = png_get_signature(png_ptr, info_ptr); 

    fprintf(stdout, 
    "width: %u" 
    "height: %u" 
    "bit_depth: %d" 
    "color_type: %d" 
    "interlace_type: %d" 
    "compression_type: %d" 
    "filter_type: %d" 
    "channles: %d" 
    "rowbytes: %u" 
    "signature: %s", (unsigned int)width, (unsigned int)height, bit_depth, color_type, 
    interlace_type, compression_type, filter_type, channels, 
    (unsigned int)rowbytes, signature); 
} 

void row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, 
    int pass) 
{ 
    fprintf(stderr, "row_callback\n"); 
    png_progressive_combine_row(png_ptr, old_row, new_row); 
} 

void end_callback(png_structp png_ptr, png_infop info) 
{ 
    fprintf(stderr, "end_callback\n"); 
    run = 1; 
} 

/* 
* Error handler local to his translation unit 
* Used by png_create_read_struct function. 
*/ 
void progressive_reader_error_fn(png_structp png_ptr, png_const_charp msg) 
{ 
    fprintf(stderr, "error: %s\n", msg); 
    fflush(stderr); 
    longjmp(png_jmpbuf(png_ptr), 1); 
    exit(0); 
} 

//------------------------------------------------------------------- 

/* 
* Free PNG resources on close 
*/ 
void free_png_resources() 
{ 
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 
    png_ptr = NULL; 
    info_ptr = NULL; 

} 

/* 
* All strings to this function must 
* be null terminated -- return 0 if 
* file is not in png format 
*/ 
int check_png_sig(const char * file_name) 
{ 
    FILE *fp = fopen(file_name, "rb"); 
    if(!fp) { 
    return (0); 
    } 
    enum HeaderSize {Size = 8}; 
    png_byte header[Size]; 
    fread(header, 1, Size, fp); 
    int is_png = !png_sig_cmp(header, 0, Size); 
    if (!is_png) { 
    fclose(fp); 
    return (0); 
    } 
    fclose(fp); 
    return (1); 
} 

/* 
* Create the png_structp and png_infop 
*/ 
int create_png_structs() 
{ 
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 
    progressive_reader_error_fn, NULL); 
    if (!png_ptr) { 
    return 0; 
    } 

    info_ptr = png_create_info_struct(png_ptr); 
    if (!info_ptr) { 
    png_destroy_read_struct(&png_ptr, NULL, NULL); 
    return 0; 
    } 

    if (setjmp(png_jmpbuf(png_ptr))) { 
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 
    return 0; 
    } 

    return 1; 
} 

/* 
* This method does all the work 
*/ 
int read_png_file(const char * file_name) 
{ 
    fprintf(stdout, "Reading PNG File %s\n", file_name); 
    fflush(stdout); 

    if (!png_ptr || !info_ptr) { 
    return (0); 
    } 

    FILE *fp = fopen(file_name, "rb"); 
    if(!fp) { 
    return (0); 
    } 

    png_init_io(png_ptr, fp); 
    png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr); 

    /* 
    * Tell libpng to call read_chunk_callback if an unknown chunk is 
    * encountered 
    */ 
    png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback); 

    /* 
    * Tell libpng to call read_row_callback if an known chunk is 
    * encountered. 
    */ 
    png_set_read_status_fn(png_ptr, read_row_callback); 

    /* 
    * Tell libpng to call the specified functions on info, rows, or 
    * end. 
    */ 
    png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback, 
    row_callback, end_callback); 

    enum Size {DataSize = 8}; 
    unsigned char rawbuf[DataSize]; 
    int process = 1; 
    if (setjmp(png_jmpbuf(png_ptr))) { 
    free_png_resources(); 
    process = 0; 
    return process; 
    } 

    /* 
    * Check to see if libpng is confused 
    */ 
    //png_set_sig_bytes(png_ptr, 8); 

    while (process) { 
    memset(rawbuf, 0, DataSize); 
    png_process_data(png_ptr, info_ptr, rawbuf, DataSize); 
    } 

    fclose(fp); 
    return (process); 
} 

int main(int argc, char *argv[]) 
{ 
    if (check_png_sig("/home/matt6809/Downloads/png_image.png")) { 
    if (create_png_structs()) { 
     if (read_png_file("/home/matt6809/Downloads/png_image.png")) { 
     fprintf(stderr, "SUCCESS!!!\n"); 
     } 
    } 
    } 
    return 0; 
} 

的Makefile

CC = /usr/bin/gcc 
LD = /usr/bin/gcc 
CFLAGS = -c -Wall -g 
LDFLAGS = -lpng 

SRC = $(wildcard *.c) 
OBJ = $(SRC:%.c=%.o) 

TARGET = progressive 

all : $(TARGET) 

$(TARGET) : $(OBJ) 
     $(LD) $(LDFLAGS) $^ -o $(TARGET) 

%.o : %.c 
     $(CC) $(CFLAGS) -o [email protected] $< 

clean : 
     rm -rf *.o $(TARGET) 

回答

1

你忘了來讀取文件的內容。

更換:

while (process) { 
    memset(rawbuf, 0, DataSize); 
    png_process_data(png_ptr, info_ptr, rawbuf, DataSize); 
} 

size_t read; 
while ((read = fread(rawbuf, 1, DataSize, fp))) { 
    png_process_data(png_ptr, info_ptr, rawbuf, read); 
} 

是足以讓解碼繼續進行。

我注意到一兩件事:傳遞給png_set_read_user_chunk_fn()png_set_progressive_read_fn()應該是回調函數可以(通過png_get_user_chunk_ptr()png_get_progressive_ptr(),分別)獲得後保持任意值第二個參數。

這些可以設置爲任何你喜歡的值(或者如果你不需要它們,可以設置爲NULL),但是你不應該自己調用png_get_*_ptr()函數來得到一個值來傳遞給png_set_*_fn()。 (我認爲它是無害的,因爲它們會返回NULL開始,但它充其量也是令人困惑的。)

相關問題