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