1 /*
2 * Copyright (c) 2001, 2002, Eric M. Johnston <emj@postal.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Eric M. Johnston.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: jpeg.c,v 1.5 2002/10/15 02:57:09 ejohnst Exp $
33 */
34
35 /*
36 * This module contains a minimal set of functions for parsing a JPEG
37 * file, specific for use in extracting EXIF information. Primarily, it
38 * reads the input file and looks for the markers which indicate the start
39 * of APP1 and APP2 sections.
40 *
41 * Portions of this code were developed while referencing the public domain
42 * 'Jhead' program (version 1.2) by Matthias Wandel <mwandel@rim.net>.
43 */
44
45 #include <stdio.h>
46
47 #include "jpeg.h"
48 #include "exif.h"
49
50
51 static FILE *infile;
52
53 /* Some data we collect from a start of frame. */
54
55 static int jpg_prcsn; /* Precision. */
56 static int jpg_cmpnts; /* Number of components. */
57 static unsigned int jpg_height; /* Image height. */
58 static unsigned int jpg_width; /* Image width. */
59 static const char *jpg_prcss; /* Process. */
60
61 static int seensof;
62
63
64 /* Process string lookup table. */
65
66 static struct jpgprocess {
67 int sof;
68 const char *str;
69 } process[] = {
70 { JPEG_M_SOF0, "Baseline" },
71 { JPEG_M_SOF1, "Extended sequential" },
72 { JPEG_M_SOF2, "Progressive" },
73 { JPEG_M_SOF3, "Lossless" },
74 { JPEG_M_SOF5, "Differential sequential" },
75 { JPEG_M_SOF6, "Differential progressive" },
76 { JPEG_M_SOF7, "Differential lossless" },
77 { JPEG_M_SOF9, "Extended sequential, arithmetic coding" },
78 { JPEG_M_SOF10, "Progressive, arithmetic coding" },
79 { JPEG_M_SOF11, "Lossless, arithmetic coding" },
80 { JPEG_M_SOF13, "Differential sequential, arithmetic coding" },
81 { JPEG_M_SOF14, "Differential progressive, arithmetic coding" },
82 { JPEG_M_SOF15, "Differential lossless, arithmetic coding" },
83 { JPEG_M_ERR, "Unknown" },
84 };
85
86
87 /*
88 * Fetch one byte of the JPEG file.
89 */
90 static int
jpg1byte(void)91 jpg1byte(void)
92 {
93 int b;
94
95 b = fgetc(infile);
96 if (b == EOF)
97 exifdie("invalid JPEG format");
98 return (b);
99 }
100
101
102 /*
103 * Fetch two bytes of the JPEG file.
104 */
105 static unsigned int
jpg2byte(void)106 jpg2byte(void)
107 {
108 unsigned int b1, b2;
109
110 b1 = fgetc(infile);
111 b2 = fgetc(infile);
112 if (b1 == EOF || b2 == EOF)
113 exifdie("invalid JPEG format");
114
115 return ((b1 << 8) | b2);
116 }
117
118
119 /*
120 * Fetch the length of a marker.
121 */
122 static unsigned int
mkrlen(void)123 mkrlen(void)
124 {
125 unsigned int l;
126
127 /* Length includes itself. */
128
129 if ((l = jpg2byte()) < 2)
130 exifdie("invalid JPEG marker (length mismatch)");
131 return (l - 2);
132 }
133
134
135 /*
136 * Skip over an uninteresting marker.
137 */
138 static void
skipmkr(void)139 skipmkr(void)
140 {
141 unsigned int l;
142
143 l = mkrlen();
144 while (l) {
145 jpg1byte();
146 l--;
147 }
148 }
149
150
151 /*
152 * Check the first bytes of the file for a marker.
153 */
154 static int
topmkr(void)155 topmkr(void)
156 {
157
158 if (jpg1byte() != JPEG_M_BEG)
159 return (JPEG_M_ERR);
160 return (jpg1byte());
161 }
162
163
164 /*
165 * Find the next JPEG marker in the file.
166 */
167 static int
nxtmkr(void)168 nxtmkr(void)
169 {
170 int b;
171 int bad = 0;
172
173 /* Read until we see JPEG_MARKER. */
174
175 while ((b = jpg1byte()) != JPEG_M_BEG)
176 bad++;
177
178 /* Read all JPEG_M_BEGs (which may be used for padding). */
179
180 while ((b = jpg1byte()) == JPEG_M_BEG);
181
182 if (bad)
183 exifwarn("skipped spurious bytes in JPEG");
184
185 return (b);
186 }
187
188
189 /*
190 * Collect image data from the start of frame.
191 * XXX Note that we clobber any previously collected info...
192 */
193 static void
sofmrk(int mark)194 sofmrk(int mark)
195 {
196 int i;
197 unsigned int l;
198
199 l = mkrlen();
200 jpg_prcsn = jpg1byte();
201 jpg_height = jpg2byte();
202 jpg_width = jpg2byte();
203 jpg_cmpnts = jpg1byte();
204
205 for (i = 0; process[i].sof < JPEG_M_ERR; i++)
206 if (process[i].sof == mark)
207 break;
208 jpg_prcss = process[i].str;
209
210 /* Verify length. */
211
212 if (l != (unsigned int)(6 + jpg_cmpnts * 3))
213 exifdie("invalid JPEG SOF marker (length mismatch)");
214
215 /* Skip over component info we don't care about. */
216
217 for (i = 0; i < jpg_cmpnts; i++) {
218 jpg1byte(); jpg1byte(); jpg1byte();
219 }
220
221 seensof = TRUE;
222 }
223
224
225 /*
226 * Scan through a JPEG file for markers, returning interesting ones.
227 * Returns false when it's done with the file.
228 */
229 int
jpegscan(FILE * fp,int * mark,unsigned int * len,int first)230 jpegscan(FILE *fp, int *mark, unsigned int *len, int first)
231 {
232 infile = fp;
233
234 /* First time through. */
235
236 if (first && topmkr() != JPEG_M_SOI) {
237 exifwarn("doesn't appear to be a JPEG file; "
238 "searching for start of image");
239 if (nxtmkr() != JPEG_M_SOI)
240 exifdie("start of image not found");
241 }
242
243 /* Look for interesting markers. */
244
245 for (;;) {
246 switch ((*mark = nxtmkr())) {
247 case JPEG_M_EOI:
248 case JPEG_M_SOS:
249 return (FALSE);
250
251 case JPEG_M_APP1:
252 case JPEG_M_APP2:
253 *len = mkrlen();
254 return (TRUE);
255
256 /* We might as well collect some useful info from SOFs. */
257
258 case JPEG_M_SOF0:
259 case JPEG_M_SOF1:
260 case JPEG_M_SOF3:
261 case JPEG_M_SOF5:
262 case JPEG_M_SOF6:
263 case JPEG_M_SOF7:
264 case JPEG_M_SOF9:
265 case JPEG_M_SOF10:
266 case JPEG_M_SOF11:
267 case JPEG_M_SOF13:
268 case JPEG_M_SOF14:
269 case JPEG_M_SOF15:
270 sofmrk(*mark);
271 break;
272
273 /* Just skip past markers we don't care about. */
274
275 default:
276 skipmkr();
277 }
278 }
279
280 return (FALSE);
281 }
282
283
284 /*
285 * Returns some basic image info about the JPEG, gleaned from start of
286 * frame sections.
287 */
288 int
jpeginfo(int * prcsn,int * cmpnts,unsigned int * height,unsigned int * width,const char * prcss)289 jpeginfo(int *prcsn, int *cmpnts, unsigned int *height, unsigned int *width,
290 const char *prcss)
291 {
292
293 *prcsn = jpg_prcsn;
294 *cmpnts = jpg_cmpnts;
295 *height = jpg_height;
296 *width = jpg_width;
297 prcss = jpg_prcss;
298
299 return (seensof);
300 }
301