Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
jp2kheader.c
Go to the documentation of this file.
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
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 */
63static const l_int32 MAX_JP2K_WIDTH = 100000;
64static const l_int32 MAX_JP2K_HEIGHT = 100000;
65
66/*--------------------------------------------------------------------*
67 * Stream interface *
68 *--------------------------------------------------------------------*/
80l_ok
81readHeaderJp2k(const char *filename,
82 l_int32 *pw,
83 l_int32 *ph,
84 l_int32 *pbps,
85 l_int32 *pspp,
86 l_int32 *pcodec)
87{
88l_int32 ret;
89FILE *fp;
90
91 if (!filename)
92 return ERROR_INT("filename not defined", __func__, 1);
93
94 if ((fp = fopenReadStream(filename)) == NULL)
95 return ERROR_INT_1("image file not found", filename, __func__, 1);
96 ret = freadHeaderJp2k(fp, pw, ph, pbps, pspp, pcodec);
97 fclose(fp);
98 return ret;
99}
100
101
113l_ok
115 l_int32 *pw,
116 l_int32 *ph,
117 l_int32 *pbps,
118 l_int32 *pspp,
119 l_int32 *pcodec)
120{
121l_uint8 buf[120]; /* usually just need the first 80 bytes */
122l_int32 nread, ret;
123
124 if (!fp)
125 return ERROR_INT("fp not defined", __func__, 1);
126
127 rewind(fp);
128 nread = fread(buf, 1, sizeof(buf), fp);
129 if (nread != sizeof(buf))
130 return ERROR_INT("read failure", __func__, 1);
131
132 ret = readHeaderMemJp2k(buf, sizeof(buf), pw, ph, pbps, pspp, pcodec);
133 rewind(fp);
134 return ret;
135}
136
137
168l_ok
169readHeaderMemJp2k(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{
177l_int32 format, val, w, h, bps, spp, loc, found, index, codec;
178l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */
179
180 if (pw) *pw = 0;
181 if (ph) *ph = 0;
182 if (pbps) *pbps = 0;
183 if (pspp) *pspp = 0;
184 if (pcodec) *pcodec = 0;
185 if (!data)
186 return ERROR_INT("data not defined", __func__, 1);
187 if (size < 120)
188 return ERROR_INT("size < 80", __func__, 1);
189 findFileFormatBuffer(data, &format);
190 if (format != IFF_JP2)
191 return ERROR_INT("not jp2 file", __func__, 1);
192
193 /* Find beginning of the image metadata */
194 if (!memcmp(data, "\xff\x4f\xff\x51", 4)) { /* codestream */
195 index = 8;
196 codec = L_J2K_CODEC;
197 } else { /* file data with image header box 'ihdr' */
198 arrayFindSequence(data, size, ihdr, 4, &loc, &found);
199 if (!found)
200 return ERROR_INT("image parameters not found", __func__, 1);
201 index = loc + 4;
202 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 }
208 if (pcodec) *pcodec = codec;
209
210 if (codec == L_JP2_CODEC) {
211 if (size < index + 4 * 3)
212 return ERROR_INT("header size is too small", __func__, 1);
213 val = *(l_uint32 *)(data + index);
214 h = convertOnLittleEnd32(val);
215 val = *(l_uint32 *)(data + index + 4);
216 w = convertOnLittleEnd32(val);
217 val = *(l_uint16 *)(data + index + 8);
218 spp = convertOnLittleEnd16(val);
219 bps = *(data + index + 10) + 1;
220 } else { /* codec == L_J2K_CODEC */
221 if (size < index + 4 * 9)
222 return ERROR_INT("header size is too small", __func__, 1);
223 val = *(l_uint32 *)(data + index);
224 w = convertOnLittleEnd32(val);
225 val = *(l_uint32 *)(data + index + 4);
226 h = convertOnLittleEnd32(val);
227 val = *(l_uint16 *)(data + index + 32);
228 spp = convertOnLittleEnd16(val);
229 bps = *(data + index + 34) + 1;
230 }
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 if (w < 1 || h < 1)
237 return ERROR_INT("w and h must both be > 0", __func__, 1);
238 if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT)
239 return ERROR_INT("unrealistically large sizes", __func__, 1);
240 if (spp != 1 && spp != 3 && spp != 4)
241 return ERROR_INT("spp must be in 1, 3 or 4", __func__, 1);
242 if (bps != 8 && bps != 16)
243 return ERROR_INT("bps must be 8 or 16", __func__, 1);
244 if (pw) *pw = w;
245 if (ph) *ph = h;
246 if (pspp) *pspp = spp;
247 if (pbps) *pbps = bps;
248 return 0;
249}
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 */
276l_int32
277fgetJp2kResolution(FILE *fp,
278 l_int32 *pxres,
279 l_int32 *pyres)
280{
281l_uint8 *data;
282size_t nbytes;
283l_ok ok;
284
285 if (!fp)
286 return ERROR_INT("stream not opened", __func__, 1);
287
288 rewind(fp);
289 data = l_binaryReadStream(fp, &nbytes);
290 rewind(fp);
291
292 ok = readResolutionMemJp2k(data, nbytes, pxres, pyres);
293
294 LEPT_FREE(data);
295 return ok;
296}
297
298
308l_ok
309readResolutionMemJp2k(const l_uint8 *data,
310 size_t nbytes,
311 l_int32 *pxres,
312 l_int32 *pyres)
313{
314l_uint8 xexp, yexp;
315l_uint16 xnum, ynum, xdenom, ydenom; /* these jp2k fields are 2-byte */
316l_int32 loc, found;
317l_uint8 resc[4] = {0x72, 0x65, 0x73, 0x63}; /* 'resc' */
318l_float64 xres, yres, maxres;
319
320 if (pxres) *pxres = 0;
321 if (pyres) *pyres = 0;
322 if (!pxres || !pyres)
323 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 arrayFindSequence(data, nbytes, resc, 4, &loc, &found);
327 if (!found) {
328 L_WARNING("image resolution not found\n", __func__);
329 return 1;
330 }
331 if (nbytes < 80 || loc >= nbytes - 13) {
332 L_WARNING("image resolution found without enough space\n", __func__);
333 return 1;
334 }
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 ynum = data[loc + 5] << 8 | data[loc + 4];
339 ynum = convertOnLittleEnd16(ynum);
340 ydenom = data[loc + 7] << 8 | data[loc + 6];
341 ydenom = convertOnLittleEnd16(ydenom);
342 xnum = data[loc + 9] << 8 | data[loc + 8];
343 xnum = convertOnLittleEnd16(xnum);
344 xdenom = data[loc + 11] << 8 | data[loc + 10];
345 xdenom = convertOnLittleEnd16(xdenom);
346 if (ydenom == 0 || xdenom == 0) {
347 L_WARNING("bad data: ydenom or xdenom is 0\n", __func__);
348 return 1;
349 }
350 yexp = data[loc + 12];
351 xexp = data[loc + 13];
352 yres = ((l_float64)ynum / (l_float64)ydenom) * pow(10.0, (l_float64)yexp);
353 xres = ((l_float64)xnum / (l_float64)xdenom) * pow(10.0, (l_float64)xexp);
354
355 /* Convert from pixels/meter to ppi */
356 yres *= (300.0 / 11811.0);
357 xres *= (300.0 / 11811.0);
358
359 /* Sanity check for bad data */
360 maxres = 100000.0; /* ppi */
361 if (xres > maxres || yres > maxres) {
362 L_WARNING("ridiculously large resolution\n", __func__);
363 } else {
364 *pyres = (l_int32)(yres + 0.5);
365 *pxres = (l_int32)(xres + 0.5);
366 }
367
368 return 0;
369}
370
371/* --------------------------------------------*/
372#endif /* USE_JP2KHEADER */
@ L_J2K_CODEC
Definition imageio.h:148
@ L_JP2_CODEC
Definition imageio.h:149
l_ok readHeaderJp2k(const char *filename, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec)
readHeaderJp2k()
Definition jp2kheader.c:81
l_ok readResolutionMemJp2k(const l_uint8 *data, size_t nbytes, l_int32 *pxres, l_int32 *pyres)
readResolutionMemJp2k()
Definition jp2kheader.c:309
l_ok freadHeaderJp2k(FILE *fp, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec)
freadHeaderJp2k()
Definition jp2kheader.c:114
l_ok readHeaderMemJp2k(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec)
readHeaderMemJp2k()
Definition jp2kheader.c:169