Leptonica 1.82.0
Image processing and image analysis suite
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
45#ifdef HAVE_CONFIG_H
46#include <config_auto.h>
47#endif /* HAVE_CONFIG_H */
48
49#include <string.h>
50#include <math.h>
51#include "allheaders.h"
52
53#ifndef NO_CONSOLE_IO
54#define DEBUG_CODEC 0
55#endif /* ~NO_CONSOLE_IO */
56
57/* --------------------------------------------*/
58#if USE_JP2KHEADER /* defined in environ.h */
59/* --------------------------------------------*/
60
61 /* a sanity check on the size read from file */
62static const l_int32 MAX_JP2K_WIDTH = 100000;
63static const l_int32 MAX_JP2K_HEIGHT = 100000;
64
65/*--------------------------------------------------------------------*
66 * Stream interface *
67 *--------------------------------------------------------------------*/
79l_ok
80readHeaderJp2k(const char *filename,
81 l_int32 *pw,
82 l_int32 *ph,
83 l_int32 *pbps,
84 l_int32 *pspp,
85 l_int32 *pcodec)
86{
87l_int32 ret;
88FILE *fp;
89
90 PROCNAME("readHeaderJp2k");
91
92 if (!filename)
93 return ERROR_INT("filename not defined", procName, 1);
94
95 if ((fp = fopenReadStream(filename)) == NULL)
96 return ERROR_INT("image file not found", procName, 1);
97 ret = freadHeaderJp2k(fp, pw, ph, pbps, pspp, pcodec);
98 fclose(fp);
99 return ret;
100}
101
102
114l_ok
116 l_int32 *pw,
117 l_int32 *ph,
118 l_int32 *pbps,
119 l_int32 *pspp,
120 l_int32 *pcodec)
121{
122l_uint8 buf[80]; /* just need the first 80 bytes */
123l_int32 nread, ret;
124
125 PROCNAME("freadHeaderJp2k");
126
127 if (!fp)
128 return ERROR_INT("fp not defined", procName, 1);
129
130 rewind(fp);
131 nread = fread(buf, 1, sizeof(buf), fp);
132 if (nread != sizeof(buf))
133 return ERROR_INT("read failure", procName, 1);
134
135 ret = readHeaderMemJp2k(buf, sizeof(buf), pw, ph, pbps, pspp, pcodec);
136 rewind(fp);
137 return ret;
138}
139
140
171l_ok
172readHeaderMemJp2k(const l_uint8 *data,
173 size_t size,
174 l_int32 *pw,
175 l_int32 *ph,
176 l_int32 *pbps,
177 l_int32 *pspp,
178 l_int32 *pcodec)
179{
180l_int32 format, val, w, h, bps, spp, loc, found, windex, codec;
181l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */
182
183 PROCNAME("readHeaderMemJp2k");
184
185 if (pw) *pw = 0;
186 if (ph) *ph = 0;
187 if (pbps) *pbps = 0;
188 if (pspp) *pspp = 0;
189 if (pcodec) *pcodec = 0;
190 if (!data)
191 return ERROR_INT("data not defined", procName, 1);
192 if (size < 80)
193 return ERROR_INT("size < 80", procName, 1);
194 findFileFormatBuffer(data, &format);
195 if (format != IFF_JP2)
196 return ERROR_INT("not jp2 file", procName, 1);
197
198 /* Find beginning of the image metadata */
199 if (!memcmp(data, "\xff\x4f\xff\x51", 4)) { /* codestream */
200 windex = 2;
201 codec = L_J2K_CODEC;
202 } else { /* file data with image header box 'ihdr' */
203 arrayFindSequence(data, size, ihdr, 4, &loc, &found);
204 if (!found)
205 return ERROR_INT("image parameters not found", procName, 1);
206 windex = loc / 4 + 1; /* expect 12 */
207 codec = L_JP2_CODEC;
208#if DEBUG_CODEC
209 if (loc != 44)
210 L_INFO("Beginning of ihdr is at byte %d\n", procName, loc);
211#endif /* DEBUG_CODEC */
212 }
213 if (pcodec) *pcodec = codec;
214
215 if (codec == L_JP2_CODEC) {
216 if (size < 4 * (windex + 3))
217 return ERROR_INT("header size is too small", procName, 1);
218 val = *((l_uint32 *)data + windex);
219 h = convertOnLittleEnd32(val);
220 val = *((l_uint32 *)data + windex + 1);
221 w = convertOnLittleEnd32(val);
222 val = *((l_uint16 *)data + 2 * (windex + 2));
223 spp = convertOnLittleEnd16(val);
224 bps = *(data + 4 * (windex + 2) + 2) + 1;
225 } else { /* codec == L_J2K_CODEC */
226 if (size < 4 * (windex + 9))
227 return ERROR_INT("header size is too small", procName, 1);
228 val = *((l_uint32 *)data + windex);
229 w = convertOnLittleEnd32(val);
230 val = *((l_uint32 *)data + windex + 1);
231 h = convertOnLittleEnd32(val);
232 val = *((l_uint16 *)data + 2 * (windex + 8));
233 spp = convertOnLittleEnd16(val);
234 bps = *(data + 4 * (windex + 8) + 2) + 1;
235 }
236#if DEBUG_CODEC
237 lept_stderr("h = %d, w = %d, codec: %s, spp = %d, bps = %d\n", h, w,
238 (codec == L_JP2_CODEC ? "jp2" : "j2k"), spp, bps);
239#endif /* DEBUG_CODEC */
240
241 if (w < 1 || h < 1)
242 return ERROR_INT("w and h must both be > 0", procName, 1);
243 if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT)
244 return ERROR_INT("unrealistically large sizes", procName, 1);
245 if (spp != 1 && spp != 3 && spp != 4)
246 return ERROR_INT("spp must be in 1, 3 or 4", procName, 1);
247 if (bps != 8 && bps != 16)
248 return ERROR_INT("bps must be 8 or 16", procName, 1);
249 if (pw) *pw = w;
250 if (ph) *ph = h;
251 if (pspp) *pspp = spp;
252 if (pbps) *pbps = bps;
253 return 0;
254}
255
256
257/*
258 * fgetJp2kResolution()
259 *
260 * Input: fp (file stream opened for read)
261 * &xres, &yres (<return> resolution in ppi)
262 * Return: 0 if found; 1 if not found or on error
263 *
264 * Notes:
265 * (1) If the capture resolution field is not set, this is not an error;
266 * the returned resolution values are 0 (designating 'unknown').
267 * (2) Side-effect: this rewinds the stream.
268 * (3) The capture resolution box is optional in the jp2 spec, and
269 * it is usually not written.
270 * (4) The big-endian data fields that follow the 4 bytes of 'resc' are:
271 * ynum: 2 bytes
272 * ydenom: 2 bytes
273 * xnum: 2 bytes
274 * xdenom: 2 bytes
275 * yexp: 1 byte
276 * xexp: 1 byte
277 */
278l_int32
279fgetJp2kResolution(FILE *fp,
280 l_int32 *pxres,
281 l_int32 *pyres)
282{
283l_uint8 xexp, yexp;
284l_uint8 *data;
285l_uint16 xnum, ynum, xdenom, ydenom; /* these jp2k fields are 2-byte */
286l_int32 loc, found;
287l_uint8 resc[4] = {0x72, 0x65, 0x73, 0x63}; /* 'resc' */
288size_t nbytes;
289l_float64 xres, yres, maxres;
290
291 PROCNAME("fgetJp2kResolution");
292
293 if (pxres) *pxres = 0;
294 if (pyres) *pyres = 0;
295 if (!pxres || !pyres)
296 return ERROR_INT("&xres and &yres not both defined", procName, 1);
297 if (!fp)
298 return ERROR_INT("stream not opened", procName, 1);
299
300 rewind(fp);
301 data = l_binaryReadStream(fp, &nbytes);
302 rewind(fp);
303
304 /* Search for the start of the first capture resolution box: 'resc' */
305 arrayFindSequence(data, nbytes, resc, 4, &loc, &found);
306 if (!found) {
307 L_WARNING("image resolution not found\n", procName);
308 LEPT_FREE(data);
309 return 1;
310 }
311 if (nbytes < 80 || loc >= nbytes - 13) {
312 L_WARNING("image resolution found without enough space\n", procName);
313 LEPT_FREE(data);
314 return 1;
315 }
316
317 /* Extract the fields and calculate the resolution in pixels/meter.
318 * See section 1.5.3.7.1 of JPEG 2000 ISO/IEC 15444-1 spec. */
319 ynum = data[loc + 5] << 8 | data[loc + 4];
320 ynum = convertOnLittleEnd16(ynum);
321 ydenom = data[loc + 7] << 8 | data[loc + 6];
322 ydenom = convertOnLittleEnd16(ydenom);
323 xnum = data[loc + 9] << 8 | data[loc + 8];
324 xnum = convertOnLittleEnd16(xnum);
325 xdenom = data[loc + 11] << 8 | data[loc + 10];
326 xdenom = convertOnLittleEnd16(xdenom);
327 if (ydenom == 0 || xdenom == 0) {
328 L_WARNING("bad data: ydenom or xdenom is 0\n", procName);
329 LEPT_FREE(data);
330 return 1;
331 }
332 yexp = data[loc + 12];
333 xexp = data[loc + 13];
334 yres = ((l_float64)ynum / (l_float64)ydenom) * pow(10.0, (l_float64)yexp);
335 xres = ((l_float64)xnum / (l_float64)xdenom) * pow(10.0, (l_float64)xexp);
336
337 /* Convert from pixels/meter to ppi */
338 yres *= (300.0 / 11811.0);
339 xres *= (300.0 / 11811.0);
340
341 /* Sanity check for bad data */
342 maxres = 100000.0; /* ppi */
343 if (xres > maxres || yres > maxres) {
344 L_WARNING("ridiculously large resolution\n", procName);
345 } else {
346 *pyres = (l_int32)(yres + 0.5);
347 *pxres = (l_int32)(xres + 0.5);
348 }
349
350 LEPT_FREE(data);
351 return 0;
352}
353
354/* --------------------------------------------*/
355#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:80
l_ok freadHeaderJp2k(FILE *fp, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec)
freadHeaderJp2k()
Definition: jp2kheader.c:115
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:172
l_ok findFileFormatBuffer(const l_uint8 *buf, l_int32 *pformat)
findFileFormatBuffer()
Definition: readfile.c:671
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402
l_ok arrayFindSequence(const l_uint8 *data, size_t datalen, const l_uint8 *sequence, size_t seqlen, l_int32 *poffset, l_int32 *pfound)
arrayFindSequence()
Definition: utils2.c:1233