You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.6 KiB
185 lines
4.6 KiB
/*- 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 precedes 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 */
|
|
|