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