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