Coverage Report

Created: 2024-06-18 06:04

/src/leptonica/src/jpegio.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 jpegio.c
29
 * <pre>
30
 *
31
 *    Read jpeg from file
32
 *          PIX             *pixReadJpeg()  [special top level]
33
 *          PIX             *pixReadStreamJpeg()
34
 *
35
 *    Read jpeg metadata from file
36
 *          l_int32          readHeaderJpeg()
37
 *          l_int32          freadHeaderJpeg()
38
 *          l_int32          fgetJpegResolution()
39
 *          l_int32          fgetJpegComment()
40
 *
41
 *    Write jpeg to file
42
 *          l_int32          pixWriteJpeg()  [special top level]
43
 *          l_int32          pixWriteStreamJpeg()
44
 *
45
 *    Read/write to memory
46
 *          PIX             *pixReadMemJpeg()
47
 *          l_int32          readHeaderMemJpeg()
48
 *          l_int32          readResolutionMemJpeg()
49
 *          l_int32          pixWriteMemJpeg()
50
 *
51
 *    Setting special flag for chroma sampling on write
52
 *          l_int32          pixSetChromaSampling()
53
 *
54
 *    Static system helpers
55
 *          static void      jpeg_error_catch_all_1()
56
 *          static void      jpeg_error_catch_all_2()
57
 *          static l_uint8   jpeg_getc()
58
 *          static l_int32   jpeg_comment_callback()
59
 *
60
 *    Documentation: libjpeg.doc can be found, along with all
61
 *    source code, at ftp://ftp.uu.net/graphics/jpeg
62
 *    Download and untar the file:  jpegsrc.v6b.tar.gz
63
 *    A good paper on jpeg can also be found there: wallace.ps.gz
64
 *
65
 *    The functions in libjpeg make it very simple to compress
66
 *    and decompress images.  On input (decompression from file),
67
 *    3 component color images can be read into either an 8 bpp Pix
68
 *    with a colormap or a 32 bpp Pix with RGB components.  For output
69
 *    (compression to file), all color Pix, whether 8 bpp with a
70
 *    colormap or 32 bpp, are written compressed as a set of three
71
 *    8 bpp (rgb) images.
72
 *
73
 *    Low-level error handling
74
 *    ------------------------
75
 *    The default behavior of the jpeg library is to call exit.
76
 *    This is often undesirable, and the caller should make the
77
 *    decision when to abort a process.  To prevent the jpeg library
78
 *    from calling exit(), setjmp() has been inserted into all
79
 *    readers and writers, and the cinfo struct has been set up so that
80
 *    the low-level jpeg library will call a special error handler
81
 *    that doesn't exit, instead of the default function error_exit().
82
 *
83
 *    To avoid race conditions and make these functions thread-safe in
84
 *    the rare situation where calls to two threads are simultaneously
85
 *    failing on bad jpegs, we insert a local copy of the jmp_buf struct
86
 *    into the cinfo.client_data field, and use this on longjmp.
87
 *    For extracting the jpeg comment, we have the added complication
88
 *    that the client_data field must also return the jpeg comment,
89
 *    and we use a different error handler.
90
 *
91
 *    How to avoid subsampling the chroma channels
92
 *    --------------------------------------------
93
 *    By default, the U,V (chroma) channels use 2x2 subsampling (aka 4.2.0).
94
 *    Higher quality for color, using full resolution (4.4.4) for the chroma,
95
 *    is obtained by setting a field in the pix before writing:
96
 *        pixSetChromaSampling(pix, L_NO_CHROMA_SAMPLING_JPEG);
97
 *    The field can be reset for default 4.2.0 subsampling with
98
 *        pixSetChromaSampling(pix, 0);
99
 *
100
 *    How to extract just the luminance channel in reading RGB
101
 *    --------------------------------------------------------
102
 *    For higher resolution and faster decoding of an RGB image, you
103
 *    can extract just the 8 bpp luminance channel, using pixReadJpeg(),
104
 *    where you use L_JPEG_READ_LUMINANCE for the %hint arg.
105
 *
106
 *    How to continue to read if the data is corrupted
107
 *    ------------------------------------------------
108
 *    By default, if data is corrupted we make every effort to fail
109
 *    to return a pix.  (Failure is not always possible with bad
110
 *    data, because in some situations, such as during arithmetic
111
 *    decoding, the low-level jpeg library will not abort or raise
112
 *    a warning.)  To attempt to ignore warnings and get a pix when data
113
 *    is corrupted, use L_JPEG_CONTINUE_WITH_BAD_DATA in the %hint arg.
114
 *
115
 *    Compressing to memory and decompressing from memory
116
 *    ---------------------------------------------------
117
 *    On systems like Windows without fmemopen() and open_memstream(),
118
 *    we write data to a temp file and read it back for operations
119
 *    between pix and compressed-data, such as pixReadMemJpeg() and
120
 *    pixWriteMemJpeg().
121
 * </pre>
122
 */
123
124
#ifdef HAVE_CONFIG_H
125
#include <config_auto.h>
126
#endif  /* HAVE_CONFIG_H */
127
128
#include <string.h>
129
#include "allheaders.h"
130
#include "pix_internal.h"
131
132
/* --------------------------------------------*/
133
#if  HAVE_LIBJPEG   /* defined in environ.h */
134
/* --------------------------------------------*/
135
136
#include <setjmp.h>
137
138
    /* jconfig.h makes the error of setting
139
     *   #define HAVE_STDLIB_H
140
     * which conflicts with config_auto.h (where it is set to 1) and results
141
     * for some gcc compiler versions in a warning.  The conflict is harmless
142
     * but we suppress it by undefining the variable. */
143
#undef HAVE_STDLIB_H
144
#include "jpeglib.h"
145
146
static void jpeg_error_catch_all_1(j_common_ptr cinfo);
147
static void jpeg_error_catch_all_2(j_common_ptr cinfo);
148
static l_uint8 jpeg_getc(j_decompress_ptr cinfo);
149
150
    /* Note: 'boolean' is defined in jmorecfg.h.  We use it explicitly
151
     * here because for Windows where __MINGW32__ is defined,
152
     * the prototype for jpeg_comment_callback() is given as
153
     * returning a boolean.  */
154
static boolean jpeg_comment_callback(j_decompress_ptr cinfo);
155
156
    /* This is saved in the client_data field of cinfo, and used both
157
     * to retrieve the comment from its callback and to handle
158
     * exceptions with a longjmp. */
159
struct callback_data {
160
    jmp_buf   jmpbuf;
161
    l_uint8  *comment;
162
};
163
164
#ifndef  NO_CONSOLE_IO
165
#define  DEBUG_INFO      0
166
#endif  /* ~NO_CONSOLE_IO */
167
168
169
/*---------------------------------------------------------------------*
170
 *                 Read jpeg from file (special function)              *
171
 *---------------------------------------------------------------------*/
172
/*!
173
 * \brief   pixReadJpeg()
174
 *
175
 * \param[in]    filename
176
 * \param[in]    cmapflag   0 for no colormap in returned pix;
177
 *                          1 to return an 8 bpp cmapped pix if spp = 3 or 4
178
 * \param[in]    reduction  scaling factor: 1, 2, 4 or 8
179
 * \param[out]   pnwarn     [optional] number of warnings about
180
 *                          corrupted data
181
 * \param[in]    hint       a bitwise OR of L_JPEG_* values; 0 for default
182
 * \return  pix, or NULL on error
183
 *
184
 * <pre>
185
 * Notes:
186
 *      (1) This is a special function for reading jpeg files.
187
 *      (2) Use this if you want the jpeg library to create
188
 *          an 8 bpp colormapped image.
189
 *      (3) Images reduced by factors of 2, 4 or 8 can be returned
190
 *          significantly faster than full resolution images.
191
 *      (4) If the jpeg data is bad, depending on the severity of the
192
 *          data corruption one of two things will happen:
193
 *          (a) 0 or more warnings are generated, or
194
 *          (b) the library will immediately attempt to exit. This is
195
 *              caught by our error handler and no pix will be returned.
196
 *          If data corruption causes a warning, the default action
197
 *          is to abort the read. The reason is that malformed jpeg
198
 *          data sequences exist that prevent termination of the read.
199
 *          To allow the decoding to continue after corrupted data is
200
 *          encountered, include L_JPEG_CONTINUE_WITH_BAD_DATA in %hint.
201
 *      (5) The possible hint values are given in the enum in imageio.h:
202
 *            * L_JPEG_READ_LUMINANCE
203
 *            * L_JPEG_CONTINUE_WITH_BAD_DATA
204
 *          Default (0) is to do neither, and to fail on warning of data
205
 *          corruption.
206
 * </pre>
207
 */
208
PIX *
209
pixReadJpeg(const char  *filename,
210
            l_int32      cmapflag,
211
            l_int32      reduction,
212
            l_int32     *pnwarn,
213
            l_int32      hint)
214
0
{
215
0
l_int32   ret;
216
0
l_uint8  *comment;
217
0
FILE     *fp;
218
0
PIX      *pix;
219
220
0
    if (pnwarn) *pnwarn = 0;
221
0
    if (!filename)
222
0
        return (PIX *)ERROR_PTR("filename not defined", __func__, NULL);
223
0
    if (cmapflag != 0 && cmapflag != 1)
224
0
        cmapflag = 0;  /* default */
225
0
    if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
226
0
        return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
227
228
0
    if ((fp = fopenReadStream(filename)) == NULL)
229
0
        return (PIX *)ERROR_PTR_1("image file not found",
230
0
                                  filename, __func__, NULL);
231
0
    pix = pixReadStreamJpeg(fp, cmapflag, reduction, pnwarn, hint);
232
0
    if (pix) {
233
0
        ret = fgetJpegComment(fp, &comment);
234
0
        if (!ret && comment)
235
0
            pixSetText(pix, (char *)comment);
236
0
        LEPT_FREE(comment);
237
0
    }
238
0
    fclose(fp);
239
240
0
    if (!pix)
241
0
        return (PIX *)ERROR_PTR_1("image not returned",
242
0
                                  filename, __func__, NULL);
243
0
    return pix;
244
0
}
245
246
247
/*!
248
 * \brief   pixReadStreamJpeg()
249
 *
250
 * \param[in]    fp         file stream
251
 * \param[in]    cmapflag   0 for no colormap in returned pix;
252
 *                          1 to return an 8 bpp cmapped pix if spp = 3 or 4
253
 * \param[in]    reduction  scaling factor: 1, 2, 4 or 8
254
 * \param[out]   pnwarn     [optional] number of warnings
255
 * \param[in]    hint       a bitwise OR of L_JPEG_* values; 0 for default
256
 * \return  pix, or NULL on error
257
 *
258
 * <pre>
259
 * Notes:
260
 *      (1) For usage, see pixReadJpeg().
261
 *      (2) The jpeg comment, if it exists, is not stored in the pix.
262
 * </pre>
263
 */
264
PIX *
265
pixReadStreamJpeg(FILE     *fp,
266
                  l_int32   cmapflag,
267
                  l_int32   reduction,
268
                  l_int32  *pnwarn,
269
                  l_int32   hint)
270
0
{
271
0
l_int32                        cyan, yellow, magenta, black, nwarn;
272
0
l_int32                        i, j, k, rval, gval, bval;
273
0
l_int32                        nlinesread, abort_on_warning;
274
0
l_int32                        w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
275
0
l_uint32                      *data;
276
0
l_uint32                      *line, *ppixel;
277
0
JSAMPROW                       rowbuffer;
278
0
PIX                           *pix;
279
0
PIXCMAP                       *cmap;
280
0
struct jpeg_decompress_struct  cinfo = { 0 };
281
0
struct jpeg_error_mgr          jerr = { 0 };
282
0
jmp_buf                        jmpbuf;  /* must be local to the function */
283
284
0
    if (pnwarn) *pnwarn = 0;
285
0
    if (!fp)
286
0
        return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
287
0
    if (cmapflag != 0 && cmapflag != 1)
288
0
        cmapflag = 0;  /* default */
289
0
    if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
290
0
        return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
291
292
0
    if (BITS_IN_JSAMPLE != 8)  /* set in jmorecfg.h */
293
0
        return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", __func__, NULL);
294
295
0
    rewind(fp);
296
0
    pix = NULL;
297
0
    rowbuffer = NULL;
298
299
        /* Modify the jpeg error handling to catch fatal errors  */
300
0
    cinfo.err = jpeg_std_error(&jerr);
301
0
    jerr.error_exit = jpeg_error_catch_all_1;
302
0
    cinfo.client_data = (void *)&jmpbuf;
303
0
    if (setjmp(jmpbuf)) {
304
0
        jpeg_destroy_decompress(&cinfo);
305
0
        pixDestroy(&pix);
306
0
        LEPT_FREE(rowbuffer);
307
0
        return (PIX *)ERROR_PTR("internal jpeg error", __func__, NULL);
308
0
    }
309
310
        /* Initialize jpeg structs for decompression */
311
0
    jpeg_create_decompress(&cinfo);
312
0
    jpeg_stdio_src(&cinfo, fp);
313
0
    jpeg_read_header(&cinfo, TRUE);
314
0
    cinfo.scale_denom = reduction;
315
0
    cinfo.scale_num = 1;
316
0
    jpeg_calc_output_dimensions(&cinfo);
317
0
    if (hint & L_JPEG_READ_LUMINANCE) {
318
0
        cinfo.out_color_space = JCS_GRAYSCALE;
319
0
        spp = 1;
320
0
        L_INFO("reading luminance channel only\n", __func__);
321
0
    } else {
322
0
        spp = cinfo.out_color_components;
323
0
    }
324
325
        /* Allocate the image and a row buffer */
326
0
    w = cinfo.output_width;
327
0
    h = cinfo.output_height;
328
0
    ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0);
329
0
    cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0);
330
0
    if (spp != 1 && spp != 3 && !ycck && !cmyk) {
331
0
        jpeg_destroy_decompress(&cinfo);
332
0
        return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK",
333
0
                                __func__, NULL);
334
0
    }
335
0
    if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {  /* rgb or 4 bpp color */
336
0
        rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), (size_t)spp * w);
337
0
        pix = pixCreate(w, h, 32);
338
0
    } else {  /* 8 bpp gray or colormapped */
339
0
        rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), w);
340
0
        pix = pixCreate(w, h, 8);
341
0
    }
342
0
    if (!rowbuffer || !pix) {
343
0
        LEPT_FREE(rowbuffer);
344
0
        rowbuffer = NULL;
345
0
        pixDestroy(&pix);
346
0
        jpeg_destroy_decompress(&cinfo);
347
0
        return (PIX *)ERROR_PTR("rowbuffer or pix not made", __func__, NULL);
348
0
    }
349
0
    pixSetInputFormat(pix, IFF_JFIF_JPEG);
350
351
        /* Initialize decompression.
352
         * Set up a colormap for color quantization if requested.
353
         * Arithmetic coding is rarely used on the jpeg data, but if it
354
         * is, jpeg_start_decompress() handles the decoding.
355
         * With corrupted encoded data, this can take an arbitrarily
356
         * long time, and fuzzers are finding examples.  Unfortunately,
357
         * there is no way to get a callback from an error in this phase. */
358
0
    if (spp == 1) {  /* Grayscale or colormapped */
359
0
        jpeg_start_decompress(&cinfo);
360
0
    } else {        /* Color; spp == 3 or YCCK or CMYK */
361
0
        if (cmapflag == 0) {   /* 24 bit color in 32 bit pix or YCCK/CMYK */
362
0
            cinfo.quantize_colors = FALSE;
363
0
            jpeg_start_decompress(&cinfo);
364
0
        } else {      /* Color quantize to 8 bits */
365
0
            cinfo.quantize_colors = TRUE;
366
0
            cinfo.desired_number_of_colors = 256;
367
0
            jpeg_start_decompress(&cinfo);
368
369
                /* Construct a pix cmap */
370
0
            cmap = pixcmapCreate(8);
371
0
            ncolors = cinfo.actual_number_of_colors;
372
0
            for (cindex = 0; cindex < ncolors; cindex++) {
373
0
                rval = cinfo.colormap[0][cindex];
374
0
                gval = cinfo.colormap[1][cindex];
375
0
                bval = cinfo.colormap[2][cindex];
376
0
                pixcmapAddColor(cmap, rval, gval, bval);
377
0
            }
378
0
            pixSetColormap(pix, cmap);
379
0
        }
380
0
    }
381
0
    wpl  = pixGetWpl(pix);
382
0
    data = pixGetData(pix);
383
384
        /* Decompress.  It appears that jpeg_read_scanlines() always
385
         * returns 1 when you ask for one scanline, but we test anyway.
386
         * During decoding of scanlines, warnings are issued if corrupted
387
         * data is found.  The default behavior is to abort reading
388
         * when a warning is encountered.  By setting the hint to have
389
         * the same bit set as in L_JPEG_CONTINUE_WITH_BAD_DATA, e.g.,
390
         *       hint = hint | L_JPEG_CONTINUE_WITH_BAD_DATA
391
         * reading will continue after warnings, in an attempt to return
392
         * the (possibly corrupted) image. */
393
0
    abort_on_warning = (hint & L_JPEG_CONTINUE_WITH_BAD_DATA) ? 0 : 1;
394
0
    for (i = 0; i < h; i++) {
395
0
        nlinesread = jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1);
396
0
        nwarn = cinfo.err->num_warnings;
397
0
        if (nlinesread == 0 || (abort_on_warning && nwarn > 0)) {
398
0
            L_ERROR("read error at scanline %d; nwarn = %d\n",
399
0
                    __func__, i, nwarn);
400
0
            pixDestroy(&pix);
401
0
            jpeg_destroy_decompress(&cinfo);
402
0
            LEPT_FREE(rowbuffer);
403
0
            rowbuffer = NULL;
404
0
            if (pnwarn) *pnwarn = nwarn;
405
0
            return (PIX *)ERROR_PTR("bad data", __func__, NULL);
406
0
        }
407
408
            /* -- 24 bit color -- */
409
0
        if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {
410
0
            ppixel = data + i * wpl;
411
0
            if (spp == 3) {
412
0
                for (j = k = 0; j < w; j++) {
413
0
                    SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]);
414
0
                    SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]);
415
0
                    SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]);
416
0
                    ppixel++;
417
0
                }
418
0
            } else {
419
                    /* This is a conversion from CMYK -> RGB that ignores
420
                       color profiles, and is invoked when the image header
421
                       claims to be in CMYK or YCCK colorspace.  If in YCCK,
422
                       libjpeg may be doing YCCK -> CMYK under the hood.
423
                       To understand why the colors need to be inverted on
424
                       read-in for the Adobe marker, see the "Special
425
                       color spaces" section of "Using the IJG JPEG
426
                       Library" by Thomas G. Lane:
427
                         http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1
428
                       The non-Adobe conversion is equivalent to:
429
                           rval = black - black * cyan / 255
430
                           ...
431
                       The Adobe conversion is equivalent to:
432
                           rval = black - black * (255 - cyan) / 255
433
                           ...
434
                       Note that cyan is the complement to red, and we
435
                       are subtracting the complement color (weighted
436
                       by black) from black.  For Adobe conversions,
437
                       where they've already inverted the CMY but not
438
                       the K, we have to invert again.  The results
439
                       must be clipped to [0 ... 255]. */
440
0
                for (j = k = 0; j < w; j++) {
441
0
                    cyan = rowbuffer[k++];
442
0
                    magenta = rowbuffer[k++];
443
0
                    yellow = rowbuffer[k++];
444
0
                    black = rowbuffer[k++];
445
0
                    if (cinfo.saw_Adobe_marker) {
446
0
                        rval = (black * cyan) / 255;
447
0
                        gval = (black * magenta) / 255;
448
0
                        bval = (black * yellow) / 255;
449
0
                    } else {
450
0
                        rval = black * (255 - cyan) / 255;
451
0
                        gval = black * (255 - magenta) / 255;
452
0
                        bval = black * (255 - yellow) / 255;
453
0
                    }
454
0
                    rval = L_MIN(L_MAX(rval, 0), 255);
455
0
                    gval = L_MIN(L_MAX(gval, 0), 255);
456
0
                    bval = L_MIN(L_MAX(bval, 0), 255);
457
0
                    composeRGBPixel(rval, gval, bval, ppixel);
458
0
                    ppixel++;
459
0
                }
460
0
            }
461
0
        } else {    /* 8 bpp grayscale or colormapped pix */
462
0
            line = data + i * wpl;
463
0
            for (j = 0; j < w; j++)
464
0
                SET_DATA_BYTE(line, j, rowbuffer[j]);
465
0
        }
466
0
    }
467
468
        /* If the pixel density is neither 1 nor 2, it may not be defined.
469
         * In that case, don't set the resolution.  */
470
0
    if (cinfo.density_unit == 1) {  /* pixels per inch */
471
0
        pixSetXRes(pix, cinfo.X_density);
472
0
        pixSetYRes(pix, cinfo.Y_density);
473
0
    } else if (cinfo.density_unit == 2) {  /* pixels per centimeter */
474
0
        pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5));
475
0
        pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5));
476
0
    }
477
478
0
    if (cinfo.output_components != spp)
479
0
        lept_stderr("output spp = %d, spp = %d\n",
480
0
                    cinfo.output_components, spp);
481
482
0
    jpeg_finish_decompress(&cinfo);
483
0
    jpeg_destroy_decompress(&cinfo);
484
0
    LEPT_FREE(rowbuffer);
485
0
    rowbuffer = NULL;
486
0
    if (pnwarn) *pnwarn = nwarn;
487
0
    if (nwarn > 0)
488
0
        L_WARNING("%d warning(s) of bad data\n", __func__, nwarn);
489
0
    return pix;
490
0
}
491
492
493
/*---------------------------------------------------------------------*
494
 *                     Read jpeg metadata from file                    *
495
 *---------------------------------------------------------------------*/
496
/*!
497
 * \brief   readHeaderJpeg()
498
 *
499
 * \param[in]    filename
500
 * \param[out]   pw     [optional]
501
 * \param[out]   ph     [optional]
502
 * \param[out]   pspp   [optional] samples/pixel
503
 * \param[out]   pycck  [optional] 1 if ycck color space; 0 otherwise
504
 * \param[out]   pcmyk  [optional] 1 if cmyk color space; 0 otherwise
505
 * \return  0 if OK, 1 on error
506
 */
507
l_ok
508
readHeaderJpeg(const char  *filename,
509
               l_int32     *pw,
510
               l_int32     *ph,
511
               l_int32     *pspp,
512
               l_int32     *pycck,
513
               l_int32     *pcmyk)
514
0
{
515
0
l_int32  ret;
516
0
FILE    *fp;
517
518
0
    if (pw) *pw = 0;
519
0
    if (ph) *ph = 0;
520
0
    if (pspp) *pspp = 0;
521
0
    if (pycck) *pycck = 0;
522
0
    if (pcmyk) *pcmyk = 0;
523
0
    if (!filename)
524
0
        return ERROR_INT("filename not defined", __func__, 1);
525
0
    if (!pw && !ph && !pspp && !pycck && !pcmyk)
526
0
        return ERROR_INT("no results requested", __func__, 1);
527
528
0
    if ((fp = fopenReadStream(filename)) == NULL)
529
0
        return ERROR_INT_1("image file not found", filename, __func__, 1);
530
0
    ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
531
0
    fclose(fp);
532
0
    return ret;
533
0
}
534
535
536
/*!
537
 * \brief   freadHeaderJpeg()
538
 *
539
 * \param[in]    fp     file stream
540
 * \param[out]   pw     [optional]
541
 * \param[out]   ph     [optional]
542
 * \param[out]   pspp   [optional]  samples/pixel
543
 * \param[out]   pycck  [optional]  1 if ycck color space; 0 otherwise
544
 * \param[out]   pcmyk  [optional]  1 if cmyk color space; 0 otherwise
545
 * \return  0 if OK, 1 on error
546
 */
547
l_ok
548
freadHeaderJpeg(FILE     *fp,
549
                l_int32  *pw,
550
                l_int32  *ph,
551
                l_int32  *pspp,
552
                l_int32  *pycck,
553
                l_int32  *pcmyk)
554
0
{
555
0
l_int32                        spp, w, h;
556
0
struct jpeg_decompress_struct  cinfo = { 0 };
557
0
struct jpeg_error_mgr          jerr = { 0 };
558
0
jmp_buf                        jmpbuf;  /* must be local to the function */
559
560
0
    if (pw) *pw = 0;
561
0
    if (ph) *ph = 0;
562
0
    if (pspp) *pspp = 0;
563
0
    if (pycck) *pycck = 0;
564
0
    if (pcmyk) *pcmyk = 0;
565
0
    if (!fp)
566
0
        return ERROR_INT("stream not defined", __func__, 1);
567
0
    if (!pw && !ph && !pspp && !pycck && !pcmyk)
568
0
        return ERROR_INT("no results requested", __func__, 1);
569
570
0
    rewind(fp);
571
572
        /* Modify the jpeg error handling to catch fatal errors  */
573
0
    cinfo.err = jpeg_std_error(&jerr);
574
0
    cinfo.client_data = (void *)&jmpbuf;
575
0
    jerr.error_exit = jpeg_error_catch_all_1;
576
0
    if (setjmp(jmpbuf))
577
0
        return ERROR_INT("internal jpeg error", __func__, 1);
578
579
        /* Initialize the jpeg structs for reading the header */
580
0
    jpeg_create_decompress(&cinfo);
581
0
    jpeg_stdio_src(&cinfo, fp);
582
0
    jpeg_read_header(&cinfo, TRUE);
583
0
    jpeg_calc_output_dimensions(&cinfo);
584
0
    spp = cinfo.out_color_components;
585
0
    w = cinfo.output_width;
586
0
    h = cinfo.output_height;
587
0
    if (w < 1 || h < 1 || spp < 1 || spp > 4) {
588
0
        jpeg_destroy_decompress(&cinfo);
589
0
        rewind(fp);
590
0
        return ERROR_INT("bad jpeg image parameters", __func__, 1);
591
0
    }
592
593
0
    if (pspp) *pspp = spp;
594
0
    if (pw) *pw = cinfo.output_width;
595
0
    if (ph) *ph = cinfo.output_height;
596
0
    if (pycck) *pycck =
597
0
        (cinfo.jpeg_color_space == JCS_YCCK && spp == 4);
598
0
    if (pcmyk) *pcmyk =
599
0
        (cinfo.jpeg_color_space == JCS_CMYK && spp == 4);
600
601
0
    jpeg_destroy_decompress(&cinfo);
602
0
    rewind(fp);
603
0
    return 0;
604
0
}
605
606
607
/*
608
 * \brief   fgetJpegResolution()
609
 *
610
 * \param[in]    fp             file stream
611
 * \param[out]   pxres, pyres   resolutions
612
 * \return   0 if OK; 1 on error
613
 *
614
 * <pre>
615
 * Notes:
616
 *      (1) If neither resolution field is set, this is not an error;
617
 *          the returned resolution values are 0 (designating 'unknown').
618
 *      (2) Side-effect: this rewinds the stream.
619
 * </pre>
620
 */
621
l_int32
622
fgetJpegResolution(FILE     *fp,
623
                   l_int32  *pxres,
624
                   l_int32  *pyres)
625
0
{
626
0
struct jpeg_decompress_struct  cinfo = { 0 };
627
0
struct jpeg_error_mgr          jerr = { 0 };
628
0
jmp_buf                        jmpbuf;  /* must be local to the function */
629
630
0
    if (pxres) *pxres = 0;
631
0
    if (pyres) *pyres = 0;
632
0
    if (!pxres || !pyres)
633
0
        return ERROR_INT("&xres and &yres not both defined", __func__, 1);
634
0
    if (!fp)
635
0
        return ERROR_INT("stream not opened", __func__, 1);
636
637
0
    rewind(fp);
638
639
        /* Modify the jpeg error handling to catch fatal errors  */
640
0
    cinfo.err = jpeg_std_error(&jerr);
641
0
    cinfo.client_data = (void *)&jmpbuf;
642
0
    jerr.error_exit = jpeg_error_catch_all_1;
643
0
    if (setjmp(jmpbuf))
644
0
        return ERROR_INT("internal jpeg error", __func__, 1);
645
646
        /* Initialize the jpeg structs for reading the header */
647
0
    jpeg_create_decompress(&cinfo);
648
0
    jpeg_stdio_src(&cinfo, fp);
649
0
    jpeg_read_header(&cinfo, TRUE);
650
651
        /* It is common for the input resolution to be omitted from the
652
         * jpeg file.  If density_unit is not 1 or 2, simply return 0. */
653
0
    if (cinfo.density_unit == 1) {  /* pixels/inch */
654
0
        *pxres = cinfo.X_density;
655
0
        *pyres = cinfo.Y_density;
656
0
    } else if (cinfo.density_unit == 2) {  /* pixels/cm */
657
0
        *pxres = (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5);
658
0
        *pyres = (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5);
659
0
    }
660
661
0
    jpeg_destroy_decompress(&cinfo);
662
0
    rewind(fp);
663
0
    return 0;
664
0
}
665
666
667
/*
668
 * \brief   fgetJpegComment()
669
 *
670
 * \param[in]    fp        file stream opened for read
671
 * \param[out]   pcomment  comment
672
 * \return   0 if OK; 1 on error
673
 *
674
 * <pre>
675
 * Notes:
676
 *      (1) Side-effect: this rewinds the stream.
677
 * </pre>
678
 */
679
l_int32
680
fgetJpegComment(FILE      *fp,
681
                l_uint8  **pcomment)
682
0
{
683
0
struct jpeg_decompress_struct  cinfo = { 0 };
684
0
struct jpeg_error_mgr          jerr = { 0 };
685
0
struct callback_data           cb_data = { 0 };  /* contains local jmp_buf */
686
687
0
    if (!pcomment)
688
0
        return ERROR_INT("&comment not defined", __func__, 1);
689
0
    *pcomment = NULL;
690
0
    if (!fp)
691
0
        return ERROR_INT("stream not opened", __func__, 1);
692
693
0
    rewind(fp);
694
695
        /* Modify the jpeg error handling to catch fatal errors  */
696
0
    cinfo.err = jpeg_std_error(&jerr);
697
0
    jerr.error_exit = jpeg_error_catch_all_2;
698
0
    cb_data.comment = NULL;
699
0
    cinfo.client_data = (void *)&cb_data;
700
0
    if (setjmp(cb_data.jmpbuf)) {
701
0
        LEPT_FREE(cb_data.comment);
702
0
        return ERROR_INT("internal jpeg error", __func__, 1);
703
0
    }
704
705
        /* Initialize the jpeg structs for reading the header */
706
0
    jpeg_create_decompress(&cinfo);
707
0
    jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback);
708
0
    jpeg_stdio_src(&cinfo, fp);
709
0
    jpeg_read_header(&cinfo, TRUE);
710
711
        /* Save the result */
712
0
    *pcomment = cb_data.comment;
713
0
    jpeg_destroy_decompress(&cinfo);
714
0
    rewind(fp);
715
0
    return 0;
716
0
}
717
718
719
/*---------------------------------------------------------------------*
720
 *                             Writing Jpeg                            *
721
 *---------------------------------------------------------------------*/
722
/*!
723
 * \brief   pixWriteJpeg()
724
 *
725
 * \param[in]    filename
726
 * \param[in]    pix           any depth; cmap is OK
727
 * \param[in]    quality       1 - 100; 75 is default
728
 * \param[in]    progressive   0 for baseline sequential; 1 for progressive
729
 * \return  0 if OK; 1 on error
730
 */
731
l_ok
732
pixWriteJpeg(const char  *filename,
733
             PIX         *pix,
734
             l_int32      quality,
735
             l_int32      progressive)
736
0
{
737
0
FILE  *fp;
738
739
0
    if (!pix)
740
0
        return ERROR_INT("pix not defined", __func__, 1);
741
0
    if (!filename)
742
0
        return ERROR_INT("filename not defined", __func__, 1);
743
744
0
    if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
745
0
        return ERROR_INT_1("stream not opened", filename, __func__, 1);
746
747
0
    if (pixWriteStreamJpeg(fp, pix, quality, progressive)) {
748
0
        fclose(fp);
749
0
        return ERROR_INT_1("pix not written to stream", filename, __func__, 1);
750
0
    }
751
752
0
    fclose(fp);
753
0
    return 0;
754
0
}
755
756
757
/*!
758
 * \brief   pixWriteStreamJpeg()
759
 *
760
 * \param[in]    fp           file stream
761
 * \param[in]    pixs         any depth; cmap is OK
762
 * \param[in]    quality      1 - 100; 75 is default value; 0 is also default
763
 * \param[in]    progressive  0 for baseline sequential; 1 for progressive
764
 * \return  0 if OK, 1 on error
765
 *
766
 * <pre>
767
 * Notes:
768
 *      (1) Progressive encoding gives better compression, at the
769
 *          expense of slower encoding and decoding.
770
 *      (2) Standard chroma subsampling is 2x2 on both the U and V
771
 *          channels.  For highest quality, use no subsampling; this
772
 *          option is set by pixSetChromaSampling(pix, 0).
773
 *      (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
774
 *          and 32 bpp.  However, it is possible, and in some cases desirable,
775
 *          to write out a jpeg file using an rgb pix that has 24 bpp.
776
 *          This can be created by appending the raster data for a 24 bpp
777
 *          image (with proper scanline padding) directly to a 24 bpp
778
 *          pix that was created without a data array.
779
 *      (4) There are two compression paths in this function:
780
 *          * Grayscale image, no colormap: compress as 8 bpp image.
781
 *          * rgb full color image: copy each line into the color
782
 *            line buffer, and compress as three 8 bpp images.
783
 *      (5) Under the covers, the jpeg library transforms rgb to a
784
 *          luminance-chromaticity triple, each component of which is
785
 *          also 8 bits, and compresses that.  It uses 2 Huffman tables,
786
 *          a higher resolution one (with more quantization levels)
787
 *          for luminosity and a lower resolution one for the chromas.
788
 * </pre>
789
 */
790
l_ok
791
pixWriteStreamJpeg(FILE    *fp,
792
                   PIX     *pixs,
793
                   l_int32  quality,
794
                   l_int32  progressive)
795
0
{
796
0
l_int32                      xres, yres;
797
0
l_int32                      i, j, k;
798
0
l_int32                      w, h, d, wpl, spp, colorflag, rowsamples;
799
0
l_uint32                    *ppixel, *line, *data;
800
0
JSAMPROW                     rowbuffer;
801
0
PIX                         *pix;
802
0
struct jpeg_compress_struct  cinfo = { 0 };
803
0
struct jpeg_error_mgr        jerr = { 0 };
804
0
char                        *text;
805
0
jmp_buf                      jmpbuf;  /* must be local to the function */
806
807
0
    if (!fp)
808
0
        return ERROR_INT("stream not open", __func__, 1);
809
0
    if (!pixs)
810
0
        return ERROR_INT("pixs not defined", __func__, 1);
811
0
    if (quality <= 0) quality = 75;  /* default */
812
0
    if (quality > 100) {
813
0
        L_ERROR("invalid jpeg quality; setting to 75\n", __func__);
814
0
        quality = 75;
815
0
    }
816
817
        /* If necessary, convert the pix so that it can be jpeg compressed.
818
         * The colormap is removed based on the source, so if the colormap
819
         * has only gray colors, the image will be compressed with spp = 1. */
820
0
    pixGetDimensions(pixs, &w, &h, &d);
821
0
    pix = NULL;
822
0
    if (pixGetColormap(pixs) != NULL) {
823
0
        L_INFO("removing colormap; may be better to compress losslessly\n",
824
0
               __func__);
825
0
        pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
826
0
    } else if (d >= 8 && d != 16) {  /* normal case; no rewrite */
827
0
        pix = pixClone(pixs);
828
0
    } else if (d < 8 || d == 16) {
829
0
        L_INFO("converting from %d to 8 bpp\n", __func__, d);
830
0
        pix = pixConvertTo8(pixs, 0);  /* 8 bpp, no cmap */
831
0
    } else {
832
0
        L_ERROR("unknown pix type with d = %d and no cmap\n", __func__, d);
833
0
        return 1;
834
0
    }
835
0
    if (!pix)
836
0
        return ERROR_INT("pix not made", __func__, 1);
837
0
    pixSetPadBits(pix, 0);
838
839
0
    rewind(fp);
840
0
    rowbuffer = NULL;
841
842
        /* Modify the jpeg error handling to catch fatal errors  */
843
0
    cinfo.err = jpeg_std_error(&jerr);
844
0
    cinfo.client_data = (void *)&jmpbuf;
845
0
    jerr.error_exit = jpeg_error_catch_all_1;
846
0
    if (setjmp(jmpbuf)) {
847
0
        LEPT_FREE(rowbuffer);
848
0
        pixDestroy(&pix);
849
0
        return ERROR_INT("internal jpeg error", __func__, 1);
850
0
    }
851
852
        /* Initialize the jpeg structs for compression */
853
0
    jpeg_create_compress(&cinfo);
854
0
    jpeg_stdio_dest(&cinfo, fp);
855
0
    cinfo.image_width  = w;
856
0
    cinfo.image_height = h;
857
858
        /* Set the color space and number of components */
859
0
    d = pixGetDepth(pix);
860
0
    if (d == 8) {
861
0
        colorflag = 0;    /* 8 bpp grayscale; no cmap */
862
0
        cinfo.input_components = 1;
863
0
        cinfo.in_color_space = JCS_GRAYSCALE;
864
0
    } else {  /* d == 32 || d == 24 */
865
0
        colorflag = 1;    /* rgb */
866
0
        cinfo.input_components = 3;
867
0
        cinfo.in_color_space = JCS_RGB;
868
0
    }
869
870
0
    jpeg_set_defaults(&cinfo);
871
872
        /* Setting optimize_coding to TRUE seems to improve compression
873
         * by approx 2-4 percent, and increases comp time by approx 20%. */
874
0
    cinfo.optimize_coding = FALSE;
875
876
        /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */
877
0
    xres = pixGetXRes(pix);
878
0
    yres = pixGetYRes(pix);
879
0
    if ((xres != 0) && (yres != 0)) {
880
0
        cinfo.density_unit = 1;  /* designates pixels per inch */
881
0
        cinfo.X_density = xres;
882
0
        cinfo.Y_density = yres;
883
0
    }
884
885
        /* Set the quality and progressive parameters */
886
0
    jpeg_set_quality(&cinfo, quality, TRUE);
887
0
    if (progressive)
888
0
        jpeg_simple_progression(&cinfo);
889
890
        /* Set the chroma subsampling parameters.  This is done in
891
         * YUV color space.  The Y (intensity) channel is never subsampled.
892
         * The standard subsampling is 2x2 on both the U and V channels.
893
         * Notation on this is confusing.  For a nice illustrations, see
894
         *   http://en.wikipedia.org/wiki/Chroma_subsampling
895
         * The standard subsampling is written as 4:2:0.
896
         * We allow high quality where there is no subsampling on the
897
         * chroma channels: denoted as 4:4:4.  */
898
0
    if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) {
899
0
        cinfo.comp_info[0].h_samp_factor = 1;
900
0
        cinfo.comp_info[0].v_samp_factor = 1;
901
0
        cinfo.comp_info[1].h_samp_factor = 1;
902
0
        cinfo.comp_info[1].v_samp_factor = 1;
903
0
        cinfo.comp_info[2].h_samp_factor = 1;
904
0
        cinfo.comp_info[2].v_samp_factor = 1;
905
0
    }
906
907
0
    jpeg_start_compress(&cinfo, TRUE);
908
909
        /* Cap the text the length limit, 65533, for JPEG_COM payload.
910
         * Just to be safe, subtract 100 to cover the Adobe name space.  */
911
0
    if ((text = pixGetText(pix)) != NULL) {
912
0
        if (strlen(text) > 65433) {
913
0
            L_WARNING("text is %zu bytes; clipping to 65433\n",
914
0
                   __func__, strlen(text));
915
0
            text[65433] = '\0';
916
0
        }
917
0
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));
918
0
    }
919
920
        /* Allocate row buffer */
921
0
    spp = cinfo.input_components;
922
0
    rowsamples = spp * w;
923
0
    if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples))
924
0
        == NULL) {
925
0
        pixDestroy(&pix);
926
0
        return ERROR_INT("calloc fail for rowbuffer", __func__, 1);
927
0
    }
928
929
0
    data = pixGetData(pix);
930
0
    wpl  = pixGetWpl(pix);
931
0
    for (i = 0; i < h; i++) {
932
0
        line = data + i * wpl;
933
0
        if (colorflag == 0) {        /* 8 bpp gray */
934
0
            for (j = 0; j < w; j++)
935
0
                rowbuffer[j] = GET_DATA_BYTE(line, j);
936
0
        } else {  /* colorflag == 1 */
937
0
            if (d == 24) {  /* See note 3 above; special case of 24 bpp rgb */
938
0
                jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
939
0
            } else {  /* standard 32 bpp rgb */
940
0
                ppixel = line;
941
0
                for (j = k = 0; j < w; j++) {
942
0
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
943
0
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
944
0
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
945
0
                    ppixel++;
946
0
                }
947
0
            }
948
0
        }
949
0
        if (d != 24)
950
0
            jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
951
0
    }
952
0
    jpeg_finish_compress(&cinfo);
953
954
0
    pixDestroy(&pix);
955
0
    LEPT_FREE(rowbuffer);
956
0
    rowbuffer = NULL;
957
0
    jpeg_destroy_compress(&cinfo);
958
0
    return 0;
959
0
}
960
961
962
/*---------------------------------------------------------------------*
963
 *                         Read/write to memory                        *
964
 *---------------------------------------------------------------------*/
965
966
/*!
967
 * \brief   pixReadMemJpeg()
968
 *
969
 * \param[in]    data       const; jpeg-encoded
970
 * \param[in]    size       of data
971
 * \param[in]    cmflag     colormap flag 0 means return RGB image if color;
972
 *                          1 means create a colormap and return
973
 *                          an 8 bpp colormapped image if color
974
 * \param[in]    reduction  scaling factor: 1, 2, 4 or 8
975
 * \param[out]   pnwarn     [optional] number of warnings
976
 * \param[in]    hint       a bitwise OR of L_JPEG_* values; 0 for default
977
 * \return  pix, or NULL on error
978
 *
979
 * <pre>
980
 * Notes:
981
 *      (1) The %size byte of %data must be a null character.
982
 *      (2) The only hint flag so far is L_JPEG_READ_LUMINANCE,
983
 *          given in the enum in imageio.h.
984
 *      (3) See pixReadJpeg() for usage.
985
 * </pre>
986
 */
987
PIX *
988
pixReadMemJpeg(const l_uint8  *data,
989
               size_t          size,
990
               l_int32         cmflag,
991
               l_int32         reduction,
992
               l_int32        *pnwarn,
993
               l_int32         hint)
994
0
{
995
0
l_int32   ret;
996
0
l_uint8  *comment;
997
0
FILE     *fp;
998
0
PIX      *pix;
999
1000
0
    if (pnwarn) *pnwarn = 0;
1001
0
    if (!data)
1002
0
        return (PIX *)ERROR_PTR("data not defined", __func__, NULL);
1003
1004
0
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
1005
0
        return (PIX *)ERROR_PTR("stream not opened", __func__, NULL);
1006
0
    pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint);
1007
0
    if (pix) {
1008
0
        ret = fgetJpegComment(fp, &comment);
1009
0
        if (!ret && comment) {
1010
0
            pixSetText(pix, (char *)comment);
1011
0
            LEPT_FREE(comment);
1012
0
        }
1013
0
    }
1014
0
    fclose(fp);
1015
0
    if (!pix) L_ERROR("pix not read\n", __func__);
1016
0
    return pix;
1017
0
}
1018
1019
1020
/*!
1021
 * \brief   readHeaderMemJpeg()
1022
 *
1023
 * \param[in]    data    const; jpeg-encoded
1024
 * \param[in]    size    of data
1025
 * \param[out]   pw      [optional] width
1026
 * \param[out]   ph      [optional] height
1027
 * \param[out]   pspp    [optional] samples/pixel
1028
 * \param[out]   pycck   [optional] 1 if ycck color space; 0 otherwise
1029
 * \param[out]   pcmyk   [optional] 1 if cmyk color space; 0 otherwise
1030
 * \return  0 if OK, 1 on error
1031
 */
1032
l_ok
1033
readHeaderMemJpeg(const l_uint8  *data,
1034
                  size_t          size,
1035
                  l_int32        *pw,
1036
                  l_int32        *ph,
1037
                  l_int32        *pspp,
1038
                  l_int32        *pycck,
1039
                  l_int32        *pcmyk)
1040
0
{
1041
0
l_int32  ret;
1042
0
FILE    *fp;
1043
1044
0
    if (pw) *pw = 0;
1045
0
    if (ph) *ph = 0;
1046
0
    if (pspp) *pspp = 0;
1047
0
    if (pycck) *pycck = 0;
1048
0
    if (pcmyk) *pcmyk = 0;
1049
0
    if (!data)
1050
0
        return ERROR_INT("data not defined", __func__, 1);
1051
0
    if (!pw && !ph && !pspp && !pycck && !pcmyk)
1052
0
        return ERROR_INT("no results requested", __func__, 1);
1053
1054
0
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
1055
0
        return ERROR_INT("stream not opened", __func__, 1);
1056
0
    ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
1057
0
    fclose(fp);
1058
0
    return ret;
1059
0
}
1060
1061
1062
/*!
1063
 * \brief   readResolutionMemJpeg()
1064
 *
1065
 * \param[in]   data    const; jpeg-encoded
1066
 * \param[in]   size    of data
1067
 * \param[out]  pxres   [optional]
1068
 * \param[out]  pyres   [optional]
1069
 * \return  0 if OK, 1 on error
1070
 */
1071
l_ok
1072
readResolutionMemJpeg(const l_uint8  *data,
1073
                      size_t          size,
1074
                      l_int32        *pxres,
1075
                      l_int32        *pyres)
1076
0
{
1077
0
l_int32  ret;
1078
0
FILE    *fp;
1079
1080
0
    if (pxres) *pxres = 0;
1081
0
    if (pyres) *pyres = 0;
1082
0
    if (!data)
1083
0
        return ERROR_INT("data not defined", __func__, 1);
1084
0
    if (!pxres && !pyres)
1085
0
        return ERROR_INT("no results requested", __func__, 1);
1086
1087
0
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
1088
0
        return ERROR_INT("stream not opened", __func__, 1);
1089
0
    ret = fgetJpegResolution(fp, pxres, pyres);
1090
0
    fclose(fp);
1091
0
    return ret;
1092
0
}
1093
1094
1095
/*!
1096
 * \brief   pixWriteMemJpeg()
1097
 *
1098
 * \param[out]   pdata        data of jpeg compressed image
1099
 * \param[out]   psize        size of returned data
1100
 * \param[in]    pix          any depth; cmap is OK
1101
 * \param[in]    quality      1 - 100; 75 is default value; 0 is also default
1102
 * \param[in]    progressive  0 for baseline sequential; 1 for progressive
1103
 * \return  0 if OK, 1 on error
1104
 *
1105
 * <pre>
1106
 * Notes:
1107
 *      (1) See pixWriteStreamJpeg() for usage.  This version writes to
1108
 *          memory instead of to a file stream.
1109
 * </pre>
1110
 */
1111
l_ok
1112
pixWriteMemJpeg(l_uint8  **pdata,
1113
                size_t    *psize,
1114
                PIX       *pix,
1115
                l_int32    quality,
1116
                l_int32    progressive)
1117
0
{
1118
0
l_int32  ret;
1119
0
FILE    *fp;
1120
1121
0
    if (pdata) *pdata = NULL;
1122
0
    if (psize) *psize = 0;
1123
0
    if (!pdata)
1124
0
        return ERROR_INT("&data not defined", __func__, 1 );
1125
0
    if (!psize)
1126
0
        return ERROR_INT("&size not defined", __func__, 1 );
1127
0
    if (!pix)
1128
0
        return ERROR_INT("&pix not defined", __func__, 1 );
1129
1130
0
#if HAVE_FMEMOPEN
1131
0
    if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1132
0
        return ERROR_INT("stream not opened", __func__, 1);
1133
0
    ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1134
0
    fputc('\0', fp);
1135
0
    fclose(fp);
1136
0
    *psize = *psize - 1;
1137
#else
1138
    L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1139
  #ifdef _WIN32
1140
    if ((fp = fopenWriteWinTempfile()) == NULL)
1141
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
1142
  #else
1143
    if ((fp = tmpfile()) == NULL)
1144
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
1145
  #endif  /* _WIN32 */
1146
    ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1147
    rewind(fp);
1148
    *pdata = l_binaryReadStream(fp, psize);
1149
    fclose(fp);
1150
#endif  /* HAVE_FMEMOPEN */
1151
0
    return ret;
1152
0
}
1153
1154
1155
/*---------------------------------------------------------------------*
1156
 *           Setting special flag for chroma sampling on write         *
1157
 *---------------------------------------------------------------------*/
1158
/*!
1159
 * \brief   pixSetChromaSampling()
1160
 *
1161
 * \param[in]    pix
1162
 * \param[in]    sampling    1 for subsampling; 0 for no subsampling
1163
 * \return  0 if OK, 1 on error
1164
 *
1165
 * <pre>
1166
 * Notes:
1167
 *      (1) The default is for 2x2 chroma subsampling because the files are
1168
 *          considerably smaller and the appearance is typically satisfactory.
1169
 *          To get full resolution output in the chroma channels for
1170
 *          jpeg writing, call this with %sampling == 0.
1171
 * </pre>
1172
 */
1173
l_ok
1174
pixSetChromaSampling(PIX     *pix,
1175
                     l_int32  sampling)
1176
0
{
1177
0
    if (!pix)
1178
0
        return ERROR_INT("pix not defined", __func__, 1 );
1179
0
    if (sampling)
1180
0
        pixSetSpecial(pix, 0);  /* default */
1181
0
    else
1182
0
        pixSetSpecial(pix, L_NO_CHROMA_SAMPLING_JPEG);
1183
0
    return 0;
1184
0
}
1185
1186
1187
/*---------------------------------------------------------------------*
1188
 *                        Static system helpers                        *
1189
 *---------------------------------------------------------------------*/
1190
/*!
1191
 * \brief   jpeg_error_catch_all_1()
1192
 *
1193
 *  Notes:
1194
 *      (1) The default jpeg error_exit() kills the process, but we
1195
 *          never want a call to leptonica to kill a process.  If you
1196
 *          do want this behavior, remove the calls to these error handlers.
1197
 *      (2) This is used where cinfo->client_data holds only jmpbuf.
1198
 */
1199
static void
1200
jpeg_error_catch_all_1(j_common_ptr cinfo)
1201
0
{
1202
0
    jmp_buf *pjmpbuf = (jmp_buf *)cinfo->client_data;
1203
0
    (*cinfo->err->output_message) (cinfo);
1204
0
    jpeg_destroy(cinfo);
1205
0
    longjmp(*pjmpbuf, 1);
1206
0
}
1207
1208
/*!
1209
 * \brief   jpeg_error_catch_all_2()
1210
 *
1211
 *  Notes:
1212
 *      (1) This is used where cinfo->client_data needs to hold both
1213
 *          the jmpbuf and the jpeg comment data.
1214
 *      (2) On error, the comment data will be freed by the caller.
1215
 */
1216
static void
1217
jpeg_error_catch_all_2(j_common_ptr cinfo)
1218
0
{
1219
0
struct callback_data  *pcb_data;
1220
1221
0
    pcb_data = (struct callback_data *)cinfo->client_data;
1222
0
    (*cinfo->err->output_message) (cinfo);
1223
0
    jpeg_destroy(cinfo);
1224
0
    longjmp(pcb_data->jmpbuf, 1);
1225
0
}
1226
1227
/* This function was borrowed from libjpeg */
1228
static l_uint8
1229
jpeg_getc(j_decompress_ptr cinfo)
1230
0
{
1231
0
struct jpeg_source_mgr *datasrc;
1232
1233
0
    datasrc = cinfo->src;
1234
0
    if (datasrc->bytes_in_buffer == 0) {
1235
0
        if (! (*datasrc->fill_input_buffer) (cinfo)) {
1236
0
            return 0;
1237
0
        }
1238
0
    }
1239
0
    datasrc->bytes_in_buffer--;
1240
0
    return GETJOCTET(*datasrc->next_input_byte++);
1241
0
}
1242
1243
/*!
1244
 * \brief   jpeg_comment_callback()
1245
 *
1246
 *  Notes:
1247
 *      (1) This is used to read the jpeg comment (JPEG_COM).
1248
 *          See the note above the declaration for why it returns
1249
 *          a "boolean".
1250
 */
1251
static boolean
1252
jpeg_comment_callback(j_decompress_ptr cinfo)
1253
0
{
1254
0
l_int32                length, i;
1255
0
l_uint8               *comment;
1256
0
struct callback_data  *pcb_data;
1257
1258
        /* Get the size of the comment */
1259
0
    length = jpeg_getc(cinfo) << 8;
1260
0
    length += jpeg_getc(cinfo);
1261
0
    length -= 2;
1262
0
    if (length <= 0)
1263
0
        return 1;
1264
1265
        /* Extract the comment from the file */
1266
0
    if ((comment = (l_uint8 *)LEPT_CALLOC(length + 1, sizeof(l_uint8))) == NULL)
1267
0
        return 0;
1268
0
    for (i = 0; i < length; i++)
1269
0
        comment[i] = jpeg_getc(cinfo);
1270
1271
        /* Save the comment and return */
1272
0
    pcb_data = (struct callback_data *)cinfo->client_data;
1273
0
    if (pcb_data->comment) {  /* clear before overwriting previous comment */
1274
0
        LEPT_FREE(pcb_data->comment);
1275
0
        pcb_data->comment = NULL;
1276
0
    }
1277
0
    pcb_data->comment = comment;
1278
0
    return 1;
1279
0
}
1280
1281
/* --------------------------------------------*/
1282
#endif  /* HAVE_LIBJPEG */
1283
/* --------------------------------------------*/