1*a67afe4dSAndroid Build Coastguard Worker /*- iccfrompng
2*a67afe4dSAndroid Build Coastguard Worker *
3*a67afe4dSAndroid Build Coastguard Worker * COPYRIGHT: Written by John Cunningham Bowler, 2011.
4*a67afe4dSAndroid Build Coastguard Worker * To the extent possible under law, the author has waived all copyright and
5*a67afe4dSAndroid Build Coastguard Worker * related or neighboring rights to this work. This work is published from:
6*a67afe4dSAndroid Build Coastguard Worker * United States.
7*a67afe4dSAndroid Build Coastguard Worker *
8*a67afe4dSAndroid Build Coastguard Worker * Extract any icc profiles found in the given PNG files. This is a simple
9*a67afe4dSAndroid Build Coastguard Worker * example of a program that extracts information from the header of a PNG file
10*a67afe4dSAndroid Build Coastguard Worker * without processing the image. Notice that some header information may occur
11*a67afe4dSAndroid Build Coastguard Worker * after the image data. Textual data and comments are an example; the approach
12*a67afe4dSAndroid Build Coastguard Worker * in this file won't work reliably for such data because it only looks for the
13*a67afe4dSAndroid Build Coastguard Worker * information in the section of the file that precedes the image data.
14*a67afe4dSAndroid Build Coastguard Worker *
15*a67afe4dSAndroid Build Coastguard Worker * Compile and link against libpng and zlib, plus anything else required on the
16*a67afe4dSAndroid Build Coastguard Worker * system you use.
17*a67afe4dSAndroid Build Coastguard Worker *
18*a67afe4dSAndroid Build Coastguard Worker * To use supply a list of PNG files containing iCCP chunks, the chunks will be
19*a67afe4dSAndroid Build Coastguard Worker * extracted to a similarly named file with the extension replaced by 'icc',
20*a67afe4dSAndroid Build Coastguard Worker * which will be overwritten without warning.
21*a67afe4dSAndroid Build Coastguard Worker */
22*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
23*a67afe4dSAndroid Build Coastguard Worker #include <setjmp.h>
24*a67afe4dSAndroid Build Coastguard Worker #include <string.h>
25*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
26*a67afe4dSAndroid Build Coastguard Worker
27*a67afe4dSAndroid Build Coastguard Worker #include <png.h>
28*a67afe4dSAndroid Build Coastguard Worker
29*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \
30*a67afe4dSAndroid Build Coastguard Worker defined (PNG_iCCP_SUPPORTED)
31*a67afe4dSAndroid Build Coastguard Worker
32*a67afe4dSAndroid Build Coastguard Worker
33*a67afe4dSAndroid Build Coastguard Worker static int verbose = 1;
34*a67afe4dSAndroid Build Coastguard Worker static png_byte no_profile[] = "no profile";
35*a67afe4dSAndroid Build Coastguard Worker
36*a67afe4dSAndroid Build Coastguard Worker static png_bytep
extract(FILE * fp,png_uint_32 * proflen)37*a67afe4dSAndroid Build Coastguard Worker extract(FILE *fp, png_uint_32 *proflen)
38*a67afe4dSAndroid Build Coastguard Worker {
39*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
40*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr = NULL;
41*a67afe4dSAndroid Build Coastguard Worker png_bytep result = NULL;
42*a67afe4dSAndroid Build Coastguard Worker
43*a67afe4dSAndroid Build Coastguard Worker /* Initialize for error or no profile: */
44*a67afe4dSAndroid Build Coastguard Worker *proflen = 0;
45*a67afe4dSAndroid Build Coastguard Worker
46*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL)
47*a67afe4dSAndroid Build Coastguard Worker {
48*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "iccfrompng: version library mismatch?\n");
49*a67afe4dSAndroid Build Coastguard Worker return 0;
50*a67afe4dSAndroid Build Coastguard Worker }
51*a67afe4dSAndroid Build Coastguard Worker
52*a67afe4dSAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(png_ptr)))
53*a67afe4dSAndroid Build Coastguard Worker {
54*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
55*a67afe4dSAndroid Build Coastguard Worker return 0;
56*a67afe4dSAndroid Build Coastguard Worker }
57*a67afe4dSAndroid Build Coastguard Worker
58*a67afe4dSAndroid Build Coastguard Worker png_init_io(png_ptr, fp);
59*a67afe4dSAndroid Build Coastguard Worker
60*a67afe4dSAndroid Build Coastguard Worker info_ptr = png_create_info_struct(png_ptr);
61*a67afe4dSAndroid Build Coastguard Worker if (info_ptr == NULL)
62*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "OOM allocating info structure");
63*a67afe4dSAndroid Build Coastguard Worker
64*a67afe4dSAndroid Build Coastguard Worker png_read_info(png_ptr, info_ptr);
65*a67afe4dSAndroid Build Coastguard Worker
66*a67afe4dSAndroid Build Coastguard Worker {
67*a67afe4dSAndroid Build Coastguard Worker png_charp name;
68*a67afe4dSAndroid Build Coastguard Worker int compression_type;
69*a67afe4dSAndroid Build Coastguard Worker png_bytep profile;
70*a67afe4dSAndroid Build Coastguard Worker
71*a67afe4dSAndroid Build Coastguard Worker if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
72*a67afe4dSAndroid Build Coastguard Worker proflen) & PNG_INFO_iCCP)
73*a67afe4dSAndroid Build Coastguard Worker {
74*a67afe4dSAndroid Build Coastguard Worker result = malloc(*proflen);
75*a67afe4dSAndroid Build Coastguard Worker if (result != NULL)
76*a67afe4dSAndroid Build Coastguard Worker memcpy(result, profile, *proflen);
77*a67afe4dSAndroid Build Coastguard Worker
78*a67afe4dSAndroid Build Coastguard Worker else
79*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "OOM allocating profile buffer");
80*a67afe4dSAndroid Build Coastguard Worker }
81*a67afe4dSAndroid Build Coastguard Worker
82*a67afe4dSAndroid Build Coastguard Worker else
83*a67afe4dSAndroid Build Coastguard Worker result = no_profile;
84*a67afe4dSAndroid Build Coastguard Worker }
85*a67afe4dSAndroid Build Coastguard Worker
86*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
87*a67afe4dSAndroid Build Coastguard Worker return result;
88*a67afe4dSAndroid Build Coastguard Worker }
89*a67afe4dSAndroid Build Coastguard Worker
90*a67afe4dSAndroid Build Coastguard Worker static int
extract_one_file(const char * filename)91*a67afe4dSAndroid Build Coastguard Worker extract_one_file(const char *filename)
92*a67afe4dSAndroid Build Coastguard Worker {
93*a67afe4dSAndroid Build Coastguard Worker int result = 0;
94*a67afe4dSAndroid Build Coastguard Worker FILE *fp = fopen(filename, "rb");
95*a67afe4dSAndroid Build Coastguard Worker
96*a67afe4dSAndroid Build Coastguard Worker if (fp != NULL)
97*a67afe4dSAndroid Build Coastguard Worker {
98*a67afe4dSAndroid Build Coastguard Worker png_uint_32 proflen = 0;
99*a67afe4dSAndroid Build Coastguard Worker png_bytep profile = extract(fp, &proflen);
100*a67afe4dSAndroid Build Coastguard Worker
101*a67afe4dSAndroid Build Coastguard Worker if (profile != NULL && profile != no_profile)
102*a67afe4dSAndroid Build Coastguard Worker {
103*a67afe4dSAndroid Build Coastguard Worker size_t len;
104*a67afe4dSAndroid Build Coastguard Worker char *output;
105*a67afe4dSAndroid Build Coastguard Worker
106*a67afe4dSAndroid Build Coastguard Worker {
107*a67afe4dSAndroid Build Coastguard Worker const char *ep = strrchr(filename, '.');
108*a67afe4dSAndroid Build Coastguard Worker
109*a67afe4dSAndroid Build Coastguard Worker if (ep != NULL)
110*a67afe4dSAndroid Build Coastguard Worker len = ep-filename;
111*a67afe4dSAndroid Build Coastguard Worker
112*a67afe4dSAndroid Build Coastguard Worker else
113*a67afe4dSAndroid Build Coastguard Worker len = strlen(filename);
114*a67afe4dSAndroid Build Coastguard Worker }
115*a67afe4dSAndroid Build Coastguard Worker
116*a67afe4dSAndroid Build Coastguard Worker output = malloc(len + 5);
117*a67afe4dSAndroid Build Coastguard Worker if (output != NULL)
118*a67afe4dSAndroid Build Coastguard Worker {
119*a67afe4dSAndroid Build Coastguard Worker FILE *of;
120*a67afe4dSAndroid Build Coastguard Worker
121*a67afe4dSAndroid Build Coastguard Worker memcpy(output, filename, len);
122*a67afe4dSAndroid Build Coastguard Worker strcpy(output+len, ".icc");
123*a67afe4dSAndroid Build Coastguard Worker
124*a67afe4dSAndroid Build Coastguard Worker of = fopen(output, "wb");
125*a67afe4dSAndroid Build Coastguard Worker if (of != NULL)
126*a67afe4dSAndroid Build Coastguard Worker {
127*a67afe4dSAndroid Build Coastguard Worker if (fwrite(profile, proflen, 1, of) == 1 &&
128*a67afe4dSAndroid Build Coastguard Worker fflush(of) == 0 &&
129*a67afe4dSAndroid Build Coastguard Worker fclose(of) == 0)
130*a67afe4dSAndroid Build Coastguard Worker {
131*a67afe4dSAndroid Build Coastguard Worker if (verbose)
132*a67afe4dSAndroid Build Coastguard Worker printf("%s -> %s\n", filename, output);
133*a67afe4dSAndroid Build Coastguard Worker /* Success return */
134*a67afe4dSAndroid Build Coastguard Worker result = 1;
135*a67afe4dSAndroid Build Coastguard Worker }
136*a67afe4dSAndroid Build Coastguard Worker
137*a67afe4dSAndroid Build Coastguard Worker else
138*a67afe4dSAndroid Build Coastguard Worker {
139*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: error writing profile\n", output);
140*a67afe4dSAndroid Build Coastguard Worker if (remove(output))
141*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: could not remove file\n", output);
142*a67afe4dSAndroid Build Coastguard Worker }
143*a67afe4dSAndroid Build Coastguard Worker }
144*a67afe4dSAndroid Build Coastguard Worker
145*a67afe4dSAndroid Build Coastguard Worker else
146*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: failed to open output file\n", output);
147*a67afe4dSAndroid Build Coastguard Worker
148*a67afe4dSAndroid Build Coastguard Worker free(output);
149*a67afe4dSAndroid Build Coastguard Worker }
150*a67afe4dSAndroid Build Coastguard Worker
151*a67afe4dSAndroid Build Coastguard Worker else
152*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: OOM allocating string!\n", filename);
153*a67afe4dSAndroid Build Coastguard Worker
154*a67afe4dSAndroid Build Coastguard Worker free(profile);
155*a67afe4dSAndroid Build Coastguard Worker }
156*a67afe4dSAndroid Build Coastguard Worker
157*a67afe4dSAndroid Build Coastguard Worker else if (verbose && profile == no_profile)
158*a67afe4dSAndroid Build Coastguard Worker printf("%s has no profile\n", filename);
159*a67afe4dSAndroid Build Coastguard Worker }
160*a67afe4dSAndroid Build Coastguard Worker
161*a67afe4dSAndroid Build Coastguard Worker else
162*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: could not open file\n", filename);
163*a67afe4dSAndroid Build Coastguard Worker
164*a67afe4dSAndroid Build Coastguard Worker return result;
165*a67afe4dSAndroid Build Coastguard Worker }
166*a67afe4dSAndroid Build Coastguard Worker
167*a67afe4dSAndroid Build Coastguard Worker int
main(int argc,char ** argv)168*a67afe4dSAndroid Build Coastguard Worker main(int argc, char **argv)
169*a67afe4dSAndroid Build Coastguard Worker {
170*a67afe4dSAndroid Build Coastguard Worker int i;
171*a67afe4dSAndroid Build Coastguard Worker int extracted = 0;
172*a67afe4dSAndroid Build Coastguard Worker
173*a67afe4dSAndroid Build Coastguard Worker for (i=1; i<argc; ++i)
174*a67afe4dSAndroid Build Coastguard Worker {
175*a67afe4dSAndroid Build Coastguard Worker if (strcmp(argv[i], "-q") == 0)
176*a67afe4dSAndroid Build Coastguard Worker verbose = 0;
177*a67afe4dSAndroid Build Coastguard Worker
178*a67afe4dSAndroid Build Coastguard Worker else if (extract_one_file(argv[i]))
179*a67afe4dSAndroid Build Coastguard Worker extracted = 1;
180*a67afe4dSAndroid Build Coastguard Worker }
181*a67afe4dSAndroid Build Coastguard Worker
182*a67afe4dSAndroid Build Coastguard Worker /* Exit code is true if any extract succeeds */
183*a67afe4dSAndroid Build Coastguard Worker return extracted == 0;
184*a67afe4dSAndroid Build Coastguard Worker }
185*a67afe4dSAndroid Build Coastguard Worker #endif /* READ && STDIO && iCCP */
186