Hello everyone,
I'm working on a program that reads a PNG and extracts a custom chunk from it (using libpng). But now I've got problems to actually register my callback function to handle unknown chunks. According to the official documentation I have to declare which chunk is "unknown" (by their name) and I need to use png_set_read_user_chunk_fn to register my callback. I've used a bit part of their code but it doesn't work, my callback isn't actually called and nothing happens except the width and heigh being printed.
Here is an entire working code which reproduces the problem :
#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fp;
png_structp png_ptr;
png_infop info_ptr, end_info;
png_byte magic[8];
png_byte custom_chunk[5] = { 116, 73, 77, 69, (png_byte)'\0' }; // tIME
png_byte unused_chunks[]=
{
104, 73, 83, 84, (png_byte) '\0', /* hIST */
105, 84, 88, 116, (png_byte) '\0', /* iTXt */
112, 67, 65, 76, (png_byte) '\0', /* pCAL */
115, 67, 65, 76, (png_byte) '\0', /* sCAL */
115, 80, 76, 84, (png_byte) '\0', /* sPLT */
'I', 'D', 'A', 'T', (png_byte) '\0' /* IDAT */
};
void readPNG(char *file);
void read_chunk_custom(png_structp ptr, png_unknown_chunkp chunk);
int main(int argc, char **argv);
void read_chunk_custom(png_structp ptr, png_unknown_chunkp chunk) {
printf("Reading custom chunk @ %p\n", chunk->data);
FILE *out = fopen("./out.jpg", "wb");
if (!out) {
fprintf(stderr, "Cannot write the chunk to ouput.\n");
return;
}
fwrite(chunk->data, 1, sizeof(chunk->data), out);
fclose(out);
return;
}
void readPNG(char *file) {
printf("read: %s\n", file);
fp = fopen(file, "rb");
if (!fp) {
fprintf(stderr, "Cannot open %s.\n", file);
return;
}
fread(magic, 1, sizeof(magic), fp);
if (!png_check_sig(magic, sizeof(magic))) {
fprintf(stderr, "error: %s isn't a valid PNG file.\n", file);
return;
}
//fseek(fp, 0, SEEK_SET);
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fprintf(stderr, "Cannot create read struct.\n");
return;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
fprintf(stderr, "Cannot create info struct.\n");
return;
}
end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fprintf(stderr, "Cannot create end info struct.\n");
return;
}
if (setjmp(png_jmpbuf(png_ptr))) {
fprintf(stderr, "Error: fatal.\n");
return;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, sizeof(magic));
png_read_info(png_ptr, info_ptr);
png_read_update_info (png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr),
height = png_get_image_height(png_ptr, info_ptr);
printf("Image %i x %i\n", width, height);
/* ignore all unknown chunks: */
png_set_keep_unknown_chunks(png_ptr, 1, NULL, 0);
/* except for our custom chunk: */
png_set_keep_unknown_chunks(png_ptr, 2, custom_chunk, sizeof(custom_chunk)/5);
/* also ignore unused known chunks: */
png_set_keep_unknown_chunks(png_ptr, 1, unused_chunks, sizeof(unused_chunks)/5);
png_set_read_user_chunk_fn(png_ptr, NULL, (png_user_chunk_ptr)read_chunk_custom);
// Throw an CRC error when commented out !
//png_read_end(png_ptr, end_info);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
}
int main(int argc, char **argv) {
if (strcmp(argv[1], "-r") || strcmp(argv[1], "--read")) {
readPNG(argv[2]);
}
return 0;
}
Output:
$ ./png-embedder -r file.png
read: file.png
Image 400 x 400
So the library is working, the file is correct and there is a tIME chunk in the file. I think this problem occurs because png_read_end is commented in my code. When I remove the comment signs the program gives me a CRC error and exit ! I don't get why it is happening ? Since the file is read without this line it shouldn't throw an error.
Can you give me a hand please ? Thank you in advance !