/*- iccfrompng * * COPYRIGHT: Written by John Cunningham Bowler, 2011. * To the extent possible under law, the author has waived all copyright and * related or neighboring rights to this work. This work is published from: * United States. * * Extract any icc profiles found in the given PNG files. This is a simple * example of a program that extracts information from the header of a PNG file * without processing the image. Notice that some header information may occur * after the image data. Textual data and comments are an example; the approach * in this file won't work reliably for such data because it only looks for the * information in the section of the file that preceeds the image data. * * Compile and link against libpng and zlib, plus anything else required on the * system you use. * * To use supply a list of PNG files containing iCCP chunks, the chunks will be * extracted to a similarly named file with the extension replaced by 'icc', * which will be overwritten without warning. */ #include <stdlib.h> #include <setjmp.h> #include <string.h> #include <stdio.h> #include <png.h> #if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \ defined (PNG_iCCP_SUPPORTED) static int verbose = 1; static png_byte no_profile[] = "no profile"; static png_bytep extract(FILE *fp, png_uint_32 *proflen) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); png_infop info_ptr = NULL; png_bytep result = NULL; /* Initialize for error or no profile: */ *proflen = 0; if (png_ptr == NULL) { fprintf(stderr, "iccfrompng: version library mismatch?\n"); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } png_init_io(png_ptr, fp); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) png_error(png_ptr, "OOM allocating info structure"); png_read_info(png_ptr, info_ptr); { png_charp name; int compression_type; png_bytep profile; if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, proflen) & PNG_INFO_iCCP) { result = malloc(*proflen); if (result != NULL) memcpy(result, profile, *proflen); else png_error(png_ptr, "OOM allocating profile buffer"); } else result = no_profile; } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return result; } static int extract_one_file(const char *filename) { int result = 0; FILE *fp = fopen(filename, "rb"); if (fp != NULL) { png_uint_32 proflen = 0; png_bytep profile = extract(fp, &proflen); if (profile != NULL && profile != no_profile) { size_t len; char *output; { const char *ep = strrchr(filename, '.'); if (ep != NULL) len = ep-filename; else len = strlen(filename); } output = malloc(len + 5); if (output != NULL) { FILE *of; memcpy(output, filename, len); strcpy(output+len, ".icc"); of = fopen(output, "wb"); if (of != NULL) { if (fwrite(profile, proflen, 1, of) == 1 && fflush(of) == 0 && fclose(of) == 0) { if (verbose) printf("%s -> %s\n", filename, output); /* Success return */ result = 1; } else { fprintf(stderr, "%s: error writing profile\n", output); if (remove(output)) fprintf(stderr, "%s: could not remove file\n", output); } } else fprintf(stderr, "%s: failed to open output file\n", output); free(output); } else fprintf(stderr, "%s: OOM allocating string!\n", filename); free(profile); } else if (verbose && profile == no_profile) printf("%s has no profile\n", filename); } else fprintf(stderr, "%s: could not open file\n", filename); return result; } int main(int argc, char **argv) { int i; int extracted = 0; for (i=1; i<argc; ++i) { if (strcmp(argv[i], "-q") == 0) verbose = 0; else if (extract_one_file(argv[i])) extracted = 1; } /* Exit code is true if any extract succeeds */ return extracted == 0; } #endif /* READ && STDIO && iCCP */