/src/leptonica/src/jp2kheader.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001 Leptonica. All rights reserved. |
3 | | - |
4 | | - Redistribution and use in source and binary forms, with or without |
5 | | - modification, are permitted provided that the following conditions |
6 | | - are met: |
7 | | - 1. Redistributions of source code must retain the above copyright |
8 | | - notice, this list of conditions and the following disclaimer. |
9 | | - 2. Redistributions in binary form must reproduce the above |
10 | | - copyright notice, this list of conditions and the following |
11 | | - disclaimer in the documentation and/or other materials |
12 | | - provided with the distribution. |
13 | | - |
14 | | - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 | | - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 | | - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY |
18 | | - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | | - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | | - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | | - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | | - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
23 | | - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | *====================================================================*/ |
26 | | |
27 | | /*! |
28 | | * \file jp2kheader.c |
29 | | * <pre> |
30 | | * |
31 | | * Read header |
32 | | * l_int32 readHeaderJp2k() |
33 | | * l_int32 freadHeaderJp2k() |
34 | | * l_int32 readHeaderMemJp2k() |
35 | | * l_int32 fgetJp2kResolution() |
36 | | * l_int32 readResolutionMemJp2k() |
37 | | * |
38 | | * Note: these function read image metadata from a jp2k file, without |
39 | | * using any jp2k libraries. |
40 | | * |
41 | | * To read and write jp2k data, using the OpenJPEG library |
42 | | * (http://www.openjpeg.org), see jpegio.c. |
43 | | * </pre> |
44 | | */ |
45 | | |
46 | | #ifdef HAVE_CONFIG_H |
47 | | #include <config_auto.h> |
48 | | #endif /* HAVE_CONFIG_H */ |
49 | | |
50 | | #include <string.h> |
51 | | #include <math.h> |
52 | | #include "allheaders.h" |
53 | | |
54 | | #ifndef NO_CONSOLE_IO |
55 | | #define DEBUG_CODEC 0 |
56 | | #endif /* ~NO_CONSOLE_IO */ |
57 | | |
58 | | /* --------------------------------------------*/ |
59 | | #if USE_JP2KHEADER /* defined in environ.h */ |
60 | | /* --------------------------------------------*/ |
61 | | |
62 | | /* a sanity check on the size read from file */ |
63 | | static const l_int32 MAX_JP2K_WIDTH = 100000; |
64 | | static const l_int32 MAX_JP2K_HEIGHT = 100000; |
65 | | |
66 | | /*--------------------------------------------------------------------* |
67 | | * Stream interface * |
68 | | *--------------------------------------------------------------------*/ |
69 | | /*! |
70 | | * \brief readHeaderJp2k() |
71 | | * |
72 | | * \param[in] filename |
73 | | * \param[out] pw [optional] |
74 | | * \param[out] ph [optional] |
75 | | * \param[out] pbps [optional] bits/sample |
76 | | * \param[out] pspp [optional] samples/pixel |
77 | | * \param[out] pcodec [optional] L_JP2_CODEC or L_J2K_CODEC |
78 | | * \return 0 if OK, 1 on error |
79 | | */ |
80 | | l_ok |
81 | | readHeaderJp2k(const char *filename, |
82 | | l_int32 *pw, |
83 | | l_int32 *ph, |
84 | | l_int32 *pbps, |
85 | | l_int32 *pspp, |
86 | | l_int32 *pcodec) |
87 | 0 | { |
88 | 0 | l_int32 ret; |
89 | 0 | FILE *fp; |
90 | |
|
91 | 0 | if (!filename) |
92 | 0 | return ERROR_INT("filename not defined", __func__, 1); |
93 | | |
94 | 0 | if ((fp = fopenReadStream(filename)) == NULL) |
95 | 0 | return ERROR_INT_1("image file not found", filename, __func__, 1); |
96 | 0 | ret = freadHeaderJp2k(fp, pw, ph, pbps, pspp, pcodec); |
97 | 0 | fclose(fp); |
98 | 0 | return ret; |
99 | 0 | } |
100 | | |
101 | | |
102 | | /*! |
103 | | * \brief freadHeaderJp2k() |
104 | | * |
105 | | * \param[in] fp file stream opened for read |
106 | | * \param[out] pw [optional] |
107 | | * \param[out] ph [optional] |
108 | | * \param[out] pbps [optional] bits/sample |
109 | | * \param[out] pspp [optional] samples/pixel |
110 | | * \param[out] pcodec [optional] L_JP2_CODEC or L_J2K_CODEC |
111 | | * \return 0 if OK, 1 on error |
112 | | */ |
113 | | l_ok |
114 | | freadHeaderJp2k(FILE *fp, |
115 | | l_int32 *pw, |
116 | | l_int32 *ph, |
117 | | l_int32 *pbps, |
118 | | l_int32 *pspp, |
119 | | l_int32 *pcodec) |
120 | 0 | { |
121 | 0 | l_uint8 buf[120]; /* usually just need the first 80 bytes */ |
122 | 0 | l_int32 nread, ret; |
123 | |
|
124 | 0 | if (!fp) |
125 | 0 | return ERROR_INT("fp not defined", __func__, 1); |
126 | | |
127 | 0 | rewind(fp); |
128 | 0 | nread = fread(buf, 1, sizeof(buf), fp); |
129 | 0 | if (nread != sizeof(buf)) |
130 | 0 | return ERROR_INT("read failure", __func__, 1); |
131 | | |
132 | 0 | ret = readHeaderMemJp2k(buf, sizeof(buf), pw, ph, pbps, pspp, pcodec); |
133 | 0 | rewind(fp); |
134 | 0 | return ret; |
135 | 0 | } |
136 | | |
137 | | |
138 | | /*! |
139 | | * \brief readHeaderMemJp2k() |
140 | | * |
141 | | * \param[in] data |
142 | | * \param[in] size at least 80 |
143 | | * \param[out] pw [optional] |
144 | | * \param[out] ph [optional] |
145 | | * \param[out] pbps [optional] bits/sample |
146 | | * \param[out] pspp [optional] samples/pixel |
147 | | * \param[out] pcodec [optional] L_JP2_CODEC or L_J2K_CODEC |
148 | | * \return 0 if OK, 1 on error |
149 | | * |
150 | | * <pre> |
151 | | * Notes: |
152 | | * (1) The ISO/IEC reference for jpeg2000 is |
153 | | * http://www.jpeg.org/public/15444-1annexi.pdf |
154 | | * and the file format syntax begins at page 127. |
155 | | * (2) With a image file codec (L_JP2_CODEC), the Image Header Box |
156 | | * begins with 'ihdr' = 0x69686472 in big-endian order. This |
157 | | * typically, but not always, starts on byte 44, with the |
158 | | * big-endian data fields beginning at byte 48: |
159 | | * h: 4 bytes |
160 | | * w: 4 bytes |
161 | | * spp: 2 bytes |
162 | | * bps: 1 byte (contains bps - 1) |
163 | | * (3) With a codestream codec (L_J2K_CODEC), the first 4 bytes are |
164 | | * 0xff4fff51. The fields for w and h appear to start on byte 8, |
165 | | * and the fields for spp and bps appear to start on byte 40. |
166 | | * </pre> |
167 | | */ |
168 | | l_ok |
169 | | readHeaderMemJp2k(const l_uint8 *data, |
170 | | size_t size, |
171 | | l_int32 *pw, |
172 | | l_int32 *ph, |
173 | | l_int32 *pbps, |
174 | | l_int32 *pspp, |
175 | | l_int32 *pcodec) |
176 | 0 | { |
177 | 0 | l_int32 format, val, w, h, bps, spp, loc, found, index, codec; |
178 | 0 | l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */ |
179 | |
|
180 | 0 | if (pw) *pw = 0; |
181 | 0 | if (ph) *ph = 0; |
182 | 0 | if (pbps) *pbps = 0; |
183 | 0 | if (pspp) *pspp = 0; |
184 | 0 | if (pcodec) *pcodec = 0; |
185 | 0 | if (!data) |
186 | 0 | return ERROR_INT("data not defined", __func__, 1); |
187 | 0 | if (size < 120) |
188 | 0 | return ERROR_INT("size < 80", __func__, 1); |
189 | 0 | findFileFormatBuffer(data, &format); |
190 | 0 | if (format != IFF_JP2) |
191 | 0 | return ERROR_INT("not jp2 file", __func__, 1); |
192 | | |
193 | | /* Find beginning of the image metadata */ |
194 | 0 | if (!memcmp(data, "\xff\x4f\xff\x51", 4)) { /* codestream */ |
195 | 0 | index = 8; |
196 | 0 | codec = L_J2K_CODEC; |
197 | 0 | } else { /* file data with image header box 'ihdr' */ |
198 | 0 | arrayFindSequence(data, size, ihdr, 4, &loc, &found); |
199 | 0 | if (!found) |
200 | 0 | return ERROR_INT("image parameters not found", __func__, 1); |
201 | 0 | index = loc + 4; |
202 | 0 | codec = L_JP2_CODEC; |
203 | | #if DEBUG_CODEC |
204 | | if (loc != 44) |
205 | | L_INFO("Beginning of ihdr is at byte %d\n", __func__, loc); |
206 | | #endif /* DEBUG_CODEC */ |
207 | 0 | } |
208 | 0 | if (pcodec) *pcodec = codec; |
209 | |
|
210 | 0 | if (codec == L_JP2_CODEC) { |
211 | 0 | if (size < index + 4 * 3) |
212 | 0 | return ERROR_INT("header size is too small", __func__, 1); |
213 | 0 | val = *(l_uint32 *)(data + index); |
214 | 0 | h = convertOnLittleEnd32(val); |
215 | 0 | val = *(l_uint32 *)(data + index + 4); |
216 | 0 | w = convertOnLittleEnd32(val); |
217 | 0 | val = *(l_uint16 *)(data + index + 8); |
218 | 0 | spp = convertOnLittleEnd16(val); |
219 | 0 | bps = *(data + index + 10) + 1; |
220 | 0 | } else { /* codec == L_J2K_CODEC */ |
221 | 0 | if (size < index + 4 * 9) |
222 | 0 | return ERROR_INT("header size is too small", __func__, 1); |
223 | 0 | val = *(l_uint32 *)(data + index); |
224 | 0 | w = convertOnLittleEnd32(val); |
225 | 0 | val = *(l_uint32 *)(data + index + 4); |
226 | 0 | h = convertOnLittleEnd32(val); |
227 | 0 | val = *(l_uint16 *)(data + index + 32); |
228 | 0 | spp = convertOnLittleEnd16(val); |
229 | 0 | bps = *(data + index + 34) + 1; |
230 | 0 | } |
231 | | #if DEBUG_CODEC |
232 | | lept_stderr("h = %d, w = %d, codec: %s, spp = %d, bps = %d\n", h, w, |
233 | | (codec == L_JP2_CODEC ? "jp2" : "j2k"), spp, bps); |
234 | | #endif /* DEBUG_CODEC */ |
235 | | |
236 | 0 | if (w < 1 || h < 1) |
237 | 0 | return ERROR_INT("w and h must both be > 0", __func__, 1); |
238 | 0 | if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT) |
239 | 0 | return ERROR_INT("unrealistically large sizes", __func__, 1); |
240 | 0 | if (spp != 1 && spp != 3 && spp != 4) |
241 | 0 | return ERROR_INT("spp must be in 1, 3 or 4", __func__, 1); |
242 | 0 | if (bps != 8 && bps != 16) |
243 | 0 | return ERROR_INT("bps must be 8 or 16", __func__, 1); |
244 | 0 | if (pw) *pw = w; |
245 | 0 | if (ph) *ph = h; |
246 | 0 | if (pspp) *pspp = spp; |
247 | 0 | if (pbps) *pbps = bps; |
248 | 0 | return 0; |
249 | 0 | } |
250 | | |
251 | | |
252 | | /* |
253 | | * \brief fgetJp2kResolution() |
254 | | * |
255 | | * \param[in] fp file stream opened for read |
256 | | * \param[oui] pxres in ppi |
257 | | * \param[oui] pyres in ppi |
258 | | * \return 0 if found, 1 if not found or on error |
259 | | * |
260 | | * <pre> |
261 | | * Notes: |
262 | | * (1) If the capture resolution field is not set, this is not an error; |
263 | | * the returned resolution values are 0 (designating 'unknown'). |
264 | | * (2) Side-effect: this rewinds the stream. |
265 | | * (3) The capture resolution box is optional in the jp2 spec, and |
266 | | * it is usually not written. |
267 | | * (4) The big-endian data fields that follow the 4 bytes of 'resc' are: |
268 | | * ynum: 2 bytes |
269 | | * ydenom: 2 bytes |
270 | | * xnum: 2 bytes |
271 | | * xdenom: 2 bytes |
272 | | * yexp: 1 byte |
273 | | * xexp: 1 byte |
274 | | * </pre> |
275 | | */ |
276 | | l_int32 |
277 | | fgetJp2kResolution(FILE *fp, |
278 | | l_int32 *pxres, |
279 | | l_int32 *pyres) |
280 | 0 | { |
281 | 0 | l_uint8 *data; |
282 | 0 | size_t nbytes; |
283 | 0 | l_ok ok; |
284 | |
|
285 | 0 | if (!fp) |
286 | 0 | return ERROR_INT("stream not opened", __func__, 1); |
287 | | |
288 | 0 | rewind(fp); |
289 | 0 | data = l_binaryReadStream(fp, &nbytes); |
290 | 0 | rewind(fp); |
291 | |
|
292 | 0 | ok = readResolutionMemJp2k(data, nbytes, pxres, pyres); |
293 | |
|
294 | 0 | LEPT_FREE(data); |
295 | 0 | return ok; |
296 | 0 | } |
297 | | |
298 | | |
299 | | /*! |
300 | | * \brief readResolutionMemJp2k() |
301 | | * |
302 | | * \param[in] data const; jp2k-encoded |
303 | | * \param[in] nbytes of data |
304 | | * \param[out] pxres [optional] |
305 | | * \param[out] pyres [optional] |
306 | | * \return 0 if OK, 1 on error |
307 | | */ |
308 | | l_ok |
309 | | readResolutionMemJp2k(const l_uint8 *data, |
310 | | size_t nbytes, |
311 | | l_int32 *pxres, |
312 | | l_int32 *pyres) |
313 | 0 | { |
314 | 0 | l_uint8 xexp, yexp; |
315 | 0 | l_uint16 xnum, ynum, xdenom, ydenom; /* these jp2k fields are 2-byte */ |
316 | 0 | l_int32 loc, found; |
317 | 0 | l_uint8 resc[4] = {0x72, 0x65, 0x73, 0x63}; /* 'resc' */ |
318 | 0 | l_float64 xres, yres, maxres; |
319 | |
|
320 | 0 | if (pxres) *pxres = 0; |
321 | 0 | if (pyres) *pyres = 0; |
322 | 0 | if (!pxres || !pyres) |
323 | 0 | return ERROR_INT("&xres and &yres not both defined", __func__, 1); |
324 | | |
325 | | /* Search for the start of the first capture resolution box: 'resc' */ |
326 | 0 | arrayFindSequence(data, nbytes, resc, 4, &loc, &found); |
327 | 0 | if (!found) { |
328 | 0 | L_WARNING("image resolution not found\n", __func__); |
329 | 0 | return 1; |
330 | 0 | } |
331 | 0 | if (nbytes < 80 || loc >= nbytes - 13) { |
332 | 0 | L_WARNING("image resolution found without enough space\n", __func__); |
333 | 0 | return 1; |
334 | 0 | } |
335 | | |
336 | | /* Extract the fields and calculate the resolution in pixels/meter. |
337 | | * See section 1.5.3.7.1 of JPEG 2000 ISO/IEC 15444-1 spec. */ |
338 | 0 | ynum = data[loc + 5] << 8 | data[loc + 4]; |
339 | 0 | ynum = convertOnLittleEnd16(ynum); |
340 | 0 | ydenom = data[loc + 7] << 8 | data[loc + 6]; |
341 | 0 | ydenom = convertOnLittleEnd16(ydenom); |
342 | 0 | xnum = data[loc + 9] << 8 | data[loc + 8]; |
343 | 0 | xnum = convertOnLittleEnd16(xnum); |
344 | 0 | xdenom = data[loc + 11] << 8 | data[loc + 10]; |
345 | 0 | xdenom = convertOnLittleEnd16(xdenom); |
346 | 0 | if (ydenom == 0 || xdenom == 0) { |
347 | 0 | L_WARNING("bad data: ydenom or xdenom is 0\n", __func__); |
348 | 0 | return 1; |
349 | 0 | } |
350 | 0 | yexp = data[loc + 12]; |
351 | 0 | xexp = data[loc + 13]; |
352 | 0 | yres = ((l_float64)ynum / (l_float64)ydenom) * pow(10.0, (l_float64)yexp); |
353 | 0 | xres = ((l_float64)xnum / (l_float64)xdenom) * pow(10.0, (l_float64)xexp); |
354 | | |
355 | | /* Convert from pixels/meter to ppi */ |
356 | 0 | yres *= (300.0 / 11811.0); |
357 | 0 | xres *= (300.0 / 11811.0); |
358 | | |
359 | | /* Sanity check for bad data */ |
360 | 0 | maxres = 100000.0; /* ppi */ |
361 | 0 | if (xres > maxres || yres > maxres) { |
362 | 0 | L_WARNING("ridiculously large resolution\n", __func__); |
363 | 0 | } else { |
364 | 0 | *pyres = (l_int32)(yres + 0.5); |
365 | 0 | *pxres = (l_int32)(xres + 0.5); |
366 | 0 | } |
367 | |
|
368 | 0 | return 0; |
369 | 0 | } |
370 | | |
371 | | /* --------------------------------------------*/ |
372 | | #endif /* USE_JP2KHEADER */ |