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 */
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  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 
114 l_ok
116  l_int32 *pw,
117  l_int32 *ph,
118  l_int32 *pbps,
119  l_int32 *pspp,
120  l_int32 *pcodec)
121 {
122 l_uint8 buf[80]; /* just need the first 80 bytes */
123 l_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 
171 l_ok
172 readHeaderMemJp2k(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 {
180 l_int32 format, val, w, h, bps, spp, loc, found, windex, codec;
181 l_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  */
278 l_int32
279 fgetJp2kResolution(FILE *fp,
280  l_int32 *pxres,
281  l_int32 *pyres)
282 {
283 l_uint8 xexp, yexp;
284 l_uint8 *data;
285 l_uint16 xnum, ynum, xdenom, ydenom; /* these jp2k fields are 2-byte */
286 l_int32 loc, found;
287 l_uint8 resc[4] = {0x72, 0x65, 0x73, 0x63}; /* 'resc' */
288 size_t nbytes;
289 l_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_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
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
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 findFileFormatBuffer(const l_uint8 *buf, l_int32 *pformat)
findFileFormatBuffer()
Definition: readfile.c:671
l_int32 w
Definition: jbclass.h:108
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
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_int32 h
Definition: jbclass.h:109
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