Coverage Report

Created: 2024-06-18 06:04

/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 */