Coverage Report

Created: 2026-09-28 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgd/src/gd_jpeg.c
Line
Count
Source
1
/*
2
 * gd_jpeg.c: Read and write JPEG (JFIF) format image files using the
3
 * gd graphics library (https://libgd.github.io).
4
 *
5
 * This software is based in part on the work of the Independent JPEG
6
 * Group.  For more information on the IJG JPEG software (and JPEG
7
 * documentation, etc.), see ftp://ftp.uu.net/graphics/jpeg/.
8
 *
9
 * NOTE: IJG 12-bit JSAMPLE (BITS_IN_JSAMPLE == 12) mode is not
10
 * supported at all on read in gd 2.0, and is not supported on write
11
 * except for palette images, which is sort of pointless (TBB). Even that
12
 * has never been tested according to DB.
13
 *
14
 * Copyright 2000 Doug Becker, mailto:thebeckers@home.com
15
 *
16
 * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG,
17
 * so VC++ builds don't spew to standard output, causing
18
 * major CGI brain damage
19
 *
20
 * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to
21
 * Christian Aberger
22
 */
23
24
/**
25
 * File: JPEG IO
26
 *
27
 * Read and write JPEG images.
28
 */
29
30
#ifdef HAVE_CONFIG_H
31
#include "config.h"
32
#endif
33
34
#include <limits.h>
35
#include <setjmp.h>
36
#include <stdlib.h>
37
#include <string.h>
38
39
#include "gd.h"
40
#include "gd_errors.h"
41
#include "gd_intern.h"
42
/* TBB: move this up so include files are not brought in */
43
/* JCE: arrange HAVE_LIBJPEG so that it can be set in gd.h */
44
#ifdef HAVE_LIBJPEG
45
#include "gdhelpers.h"
46
47
#if defined(_WIN32) && defined(__MINGW32__)
48
#define HAVE_BOOLEAN
49
#endif
50
51
/* 1.8.1: remove dependency on jinclude.h */
52
#include "jerror.h"
53
#include "jpeglib.h"
54
55
static const char *const GD_JPEG_VERSION = "1.0";
56
57
typedef struct _jmpbuf_wrapper {
58
    jmp_buf jmpbuf;
59
    int ignore_warning;
60
} jmpbuf_wrapper;
61
62
static void jpeg_gdIOCtx_src(j_decompress_ptr cinfo, gdIOCtx *infile);
63
64
static void jpeg_emit_message(j_common_ptr jpeg_info, int level)
65
{
66
    char message[JMSG_LENGTH_MAX];
67
    jmpbuf_wrapper *jmpbufw;
68
    int ignore_warning = 0;
69
70
    jmpbufw = (jmpbuf_wrapper *)jpeg_info->client_data;
71
72
    if (jmpbufw != 0) {
73
        ignore_warning = jmpbufw->ignore_warning;
74
    }
75
76
    (jpeg_info->err->format_message)(jpeg_info, message);
77
78
    /* It is a warning message */
79
    if (level < 0) {
80
        /* display only the 1st warning, as would do a default libjpeg
81
         * unless strace_level >= 3
82
         */
83
        if ((jpeg_info->err->num_warnings == 0) || (jpeg_info->err->trace_level >= 3)) {
84
            if (!ignore_warning) {
85
                gd_error("gd-jpeg, libjpeg: recoverable error: %s\n", message);
86
            }
87
        }
88
89
        jpeg_info->err->num_warnings++;
90
    } else {
91
        /* strace msg, Show it if trace_level >= level. */
92
        if (jpeg_info->err->trace_level >= level) {
93
            if (!ignore_warning) {
94
                gd_error("gd-jpeg, libjpeg: strace message: %s\n", message);
95
            }
96
        }
97
    }
98
}
99
100
/* Called by the IJG JPEG library upon encountering a fatal error */
101
static void fatal_jpeg_error(j_common_ptr cinfo)
102
{
103
    jmpbuf_wrapper *jmpbufw;
104
    char buffer[JMSG_LENGTH_MAX];
105
106
    (*cinfo->err->format_message)(cinfo, buffer);
107
    gd_error_ex(GD_WARNING, "gd-jpeg: JPEG library reports unrecoverable error: %s", buffer);
108
109
    jmpbufw = (jmpbuf_wrapper *)cinfo->client_data;
110
    jpeg_destroy(cinfo);
111
112
    if (jmpbufw != 0) {
113
        longjmp(jmpbufw->jmpbuf, 1);
114
        gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp "
115
                              "returned control; terminating\n");
116
    } else {
117
        gd_error_ex(GD_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf "
118
                              "unrecoverable; terminating\n");
119
    }
120
121
    exit(99);
122
}
123
124
BGD_DECLARE(const char *) gdJpegGetVersionString()
125
{
126
    switch (JPEG_LIB_VERSION) {
127
    case 62:
128
        return "6b";
129
        break;
130
131
    case 70:
132
        return "7";
133
        break;
134
135
    case 80:
136
        return "8";
137
        break;
138
139
    case 90:
140
        return "9 compatible";
141
        break;
142
143
    case 100:
144
        return "10 compatible";
145
        break;
146
147
    default:
148
        return "unknown";
149
    }
150
}
151
152
BGD_DECLARE(void) gdJpegInfoInit(gdJpegInfo *info)
153
{
154
    if (info == NULL) {
155
        return;
156
    }
157
    memset(info, 0, sizeof(*info));
158
    info->width = 0;
159
    info->height = 0;
160
    info->bits_per_sample = 0;
161
    info->components = 0;
162
    info->color_space = GD_JPEG_COLOR_SPACE_UNKNOWN;
163
    info->progressive = 0;
164
    info->density_unit = GD_JPEG_DENSITY_UNIT_NONE;
165
    info->x_density = -1;
166
    info->y_density = -1;
167
}
168
169
BGD_DECLARE(void) gdJpegReadOptionsInit(gdJpegReadOptions *options)
170
{
171
    if (options == NULL) {
172
        return;
173
    }
174
    memset(options, 0, sizeof(*options));
175
    options->ignore_warning = 1;
176
    options->scale_num = 1;
177
    options->scale_denom = 1;
178
    options->dct_method = GD_JPEG_DCT_DEFAULT;
179
}
180
181
static int gdJpegMapColorSpace(J_COLOR_SPACE color_space)
182
{
183
    switch (color_space) {
184
    case JCS_GRAYSCALE:
185
        return GD_JPEG_COLOR_SPACE_GRAYSCALE;
186
    case JCS_RGB:
187
        return GD_JPEG_COLOR_SPACE_RGB;
188
    case JCS_YCbCr:
189
        return GD_JPEG_COLOR_SPACE_YCBCR;
190
    case JCS_CMYK:
191
        return GD_JPEG_COLOR_SPACE_CMYK;
192
    case JCS_YCCK:
193
        return GD_JPEG_COLOR_SPACE_YCCK;
194
    case JCS_UNKNOWN:
195
    default:
196
        return GD_JPEG_COLOR_SPACE_UNKNOWN;
197
    }
198
}
199
200
static int gdJpegMarkerStartsWith(jpeg_saved_marker_ptr marker, const unsigned char *prefix,
201
                                  size_t prefix_size);
202
203
BGD_DECLARE(int) gdJpegGetInfoCtx(gdIOCtxPtr infile, gdJpegInfo *info)
204
{
205
    struct jpeg_decompress_struct cinfo;
206
    struct jpeg_error_mgr jerr;
207
    jmpbuf_wrapper jmpbufw;
208
    int retval;
209
210
    if (infile == NULL || info == NULL) {
211
        return 1;
212
    }
213
214
    gdJpegInfoInit(info);
215
216
    memset(&cinfo, 0, sizeof(cinfo));
217
    memset(&jerr, 0, sizeof(jerr));
218
    memset(&jmpbufw, 0, sizeof(jmpbufw));
219
    jmpbufw.ignore_warning = 1;
220
221
    cinfo.err = jpeg_std_error(&jerr);
222
    cinfo.client_data = &jmpbufw;
223
    cinfo.err->emit_message = jpeg_emit_message;
224
225
    if (setjmp(jmpbufw.jmpbuf) != 0) {
226
        jpeg_destroy_decompress(&cinfo);
227
        return 1;
228
    }
229
230
    cinfo.err->error_exit = fatal_jpeg_error;
231
232
    jpeg_create_decompress(&cinfo);
233
    jpeg_gdIOCtx_src(&cinfo, infile);
234
235
    retval = jpeg_read_header(&cinfo, TRUE);
236
    if (retval != JPEG_HEADER_OK) {
237
        jpeg_destroy_decompress(&cinfo);
238
        return 1;
239
    }
240
241
    if (cinfo.image_width > INT_MAX || cinfo.image_height > INT_MAX ||
242
        cinfo.data_precision > INT_MAX || cinfo.num_components > INT_MAX) {
243
        jpeg_destroy_decompress(&cinfo);
244
        return 1;
245
    }
246
247
    info->width = (int)cinfo.image_width;
248
    info->height = (int)cinfo.image_height;
249
    info->bits_per_sample = (int)cinfo.data_precision;
250
    info->components = cinfo.num_components;
251
    info->color_space = gdJpegMapColorSpace(cinfo.jpeg_color_space);
252
    info->progressive = cinfo.progressive_mode != 0;
253
    info->density_unit = cinfo.density_unit;
254
    info->x_density = (int)cinfo.X_density;
255
    info->y_density = (int)cinfo.Y_density;
256
    jpeg_destroy_decompress(&cinfo);
257
    return 0;
258
}
259
260
BGD_DECLARE(int) gdJpegGetInfo(FILE *infile, gdJpegInfo *info)
261
{
262
    gdIOCtx *in;
263
    int result;
264
265
    if (infile == NULL || info == NULL) {
266
        return 1;
267
    }
268
269
    in = gdNewFileCtx(infile);
270
    if (in == NULL) {
271
        return 1;
272
    }
273
    result = gdJpegGetInfoCtx(in, info);
274
    in->gd_free(in);
275
    return result;
276
}
277
278
BGD_DECLARE(int) gdJpegGetInfoPtr(int size, const void *data, gdJpegInfo *info)
279
{
280
    gdIOCtx *in;
281
    int result;
282
283
    if (size <= 0 || data == NULL || info == NULL) {
284
        return 1;
285
    }
286
    in = gdNewDynamicCtxEx(size, (void *)data, 0);
287
    if (in == NULL) {
288
        return 1;
289
    }
290
    result = gdJpegGetInfoCtx(in, info);
291
    in->gd_free(in);
292
    return result;
293
}
294
295
static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality,
296
                           const gdImageMetadata *metadata, int force_no_subsampling,
297
                           int progressive);
298
299
BGD_DECLARE(void) gdImageJpeg(gdImagePtr im, FILE *outFile, int quality)
300
{
301
    gdIOCtx *out = gdNewFileCtx(outFile);
302
    if (out == NULL)
303
        return;
304
    gdImageJpegCtx(im, out, quality);
305
    out->gd_free(out);
306
}
307
308
BGD_DECLARE(void *) gdImageJpegPtr(gdImagePtr im, int *size, int quality)
309
{
310
    void *rv;
311
    gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
312
    if (out == NULL)
313
        return NULL;
314
    if (!_gdImageJpegCtx(im, out, quality, NULL, 0, -1)) {
315
        rv = gdDPExtractData(out, size);
316
    } else {
317
        rv = NULL;
318
    }
319
    out->gd_free(out);
320
    return rv;
321
}
322
323
BGD_DECLARE(void) gdJpegWriteOptionsInit(gdJpegWriteOptions *options)
324
{
325
    if (options == NULL) {
326
        return;
327
    }
328
    memset(options, 0, sizeof(*options));
329
    options->quality = -1;
330
    options->progressive = 0;
331
    options->force_no_subsampling = 0;
332
    options->metadata = NULL;
333
}
334
335
BGD_DECLARE(int)
336
gdImageJpegWithOptions(gdImagePtr im, FILE *outFile, const gdJpegWriteOptions *options)
337
{
338
    gdIOCtx *out;
339
    int result;
340
341
    out = gdNewFileCtx(outFile);
342
    if (out == NULL) {
343
        return 1;
344
    }
345
    result = gdImageJpegCtxWithOptions(im, out, options);
346
    out->gd_free(out);
347
    return result;
348
}
349
350
BGD_DECLARE(int)
351
gdImageJpegCtxWithOptions(gdImagePtr im, gdIOCtx *outfile, const gdJpegWriteOptions *options)
352
{
353
    gdJpegWriteOptions default_options;
354
355
    if (options == NULL) {
356
        gdJpegWriteOptionsInit(&default_options);
357
        options = &default_options;
358
    }
359
360
    return _gdImageJpegCtx(im, outfile, options->quality, options->metadata,
361
                           options->force_no_subsampling, options->progressive);
362
}
363
364
BGD_DECLARE(void *)
365
gdImageJpegPtrWithOptions(gdImagePtr im, int *size, const gdJpegWriteOptions *options)
366
{
367
    void *rv;
368
    gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
369
    if (out == NULL) {
370
        return NULL;
371
    }
372
    if (!gdImageJpegCtxWithOptions(im, out, options)) {
373
        rv = gdDPExtractData(out, size);
374
    } else {
375
        rv = NULL;
376
    }
377
    out->gd_free(out);
378
    return rv;
379
}
380
381
static void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile);
382
383
BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
384
{
385
    _gdImageJpegCtx(im, outfile, quality, NULL, 0, -1);
386
}
387
388
static int gdJpegWriteProfileMarker(j_compress_ptr cinfo, int marker,
389
                                    const unsigned char *prefix, size_t prefix_size,
390
                                    const unsigned char *data, size_t size)
391
{
392
    unsigned char *payload;
393
394
    if (data == NULL || size > 65533 - prefix_size) {
395
        return size == 0 ? 0 : 1;
396
    }
397
    payload = (unsigned char *)gdMalloc(prefix_size + size);
398
    if (payload == NULL) {
399
        return 1;
400
    }
401
    memcpy(payload, prefix, prefix_size);
402
    memcpy(payload + prefix_size, data, size);
403
    jpeg_write_marker(cinfo, marker, payload, (unsigned int)(prefix_size + size));
404
    gdFree(payload);
405
    return 0;
406
}
407
408
static int gdJpegWriteIptcMarker(j_compress_ptr cinfo, const unsigned char *data, size_t size)
409
{
410
    static const unsigned char photoshop[] = "Photoshop 3.0\0";
411
    size_t payload_size = sizeof(photoshop) - 1 + 4 + 2 + 1 + 1 + 4 + size + (size & 1);
412
    unsigned char *payload;
413
    size_t offset = sizeof(photoshop) - 1;
414
415
    if (data == NULL || size > 65533 || payload_size > 65533 || size > UINT_MAX) {
416
        return size == 0 ? 0 : 1;
417
    }
418
    payload = (unsigned char *)gdCalloc(1, payload_size);
419
    if (payload == NULL) {
420
        return 1;
421
    }
422
    memcpy(payload, photoshop, sizeof(photoshop) - 1);
423
    memcpy(payload + offset, "8BIM", 4);
424
    offset += 4;
425
    payload[offset++] = 0x04;
426
    payload[offset++] = 0x04;
427
    payload[offset++] = 0;
428
    payload[offset++] = 0;
429
    payload[offset++] = (unsigned char)(size >> 24);
430
    payload[offset++] = (unsigned char)(size >> 16);
431
    payload[offset++] = (unsigned char)(size >> 8);
432
    payload[offset++] = (unsigned char)size;
433
    memcpy(payload + offset, data, size);
434
    jpeg_write_marker(cinfo, JPEG_APP0 + 13, payload, (unsigned int)payload_size);
435
    gdFree(payload);
436
    return 0;
437
}
438
439
static int gdJpegWriteMetadata(j_compress_ptr cinfo, const gdImageMetadata *metadata)
440
{
441
    static const unsigned char xmp_prefix[] = "http://ns.adobe.com/xap/1.0/\0";
442
    const unsigned char *data;
443
    size_t size;
444
445
    if (metadata == NULL) {
446
        return 0;
447
    }
448
449
    data = gdImageMetadataGetProfile(metadata, "exif", &size);
450
    if (data != NULL) {
451
        static const unsigned char exif_signature[] = {'E', 'x', 'i', 'f', '\0', '\0'};
452
        const unsigned char *tiff;
453
        size_t tiff_size;
454
455
        if (gdMetadataGetExifTiff(data, size, &tiff, &tiff_size) != GD_META_OK ||
456
            gdJpegWriteProfileMarker(cinfo, JPEG_APP0 + 1, exif_signature,
457
                                     sizeof(exif_signature), tiff, tiff_size)) {
458
            return 1;
459
        }
460
    }
461
    data = gdImageMetadataGetProfile(metadata, "xmp", &size);
462
    if (data != NULL && gdJpegWriteProfileMarker(cinfo, JPEG_APP0 + 1,
463
                                                  xmp_prefix, sizeof(xmp_prefix) - 1,
464
                                                  data, size)) {
465
        return 1;
466
    }
467
    data = gdImageMetadataGetProfile(metadata, "iptc", &size);
468
    if (data != NULL && gdJpegWriteIptcMarker(cinfo, data, size)) {
469
        return 1;
470
    }
471
472
    return 0;
473
}
474
475
static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality,
476
                           const gdImageMetadata *metadata, int force_no_subsampling,
477
                           int progressive)
478
{
479
    struct jpeg_compress_struct cinfo;
480
    struct jpeg_error_mgr jerr;
481
    int i, j, jidx;
482
    /* volatile so we can gdFree it on return from longjmp */
483
    volatile JSAMPROW row = 0;
484
    JSAMPROW rowptr[1];
485
    jmpbuf_wrapper jmpbufw;
486
    JDIMENSION nlines;
487
    char comment[255];
488
489
#ifdef JPEG_DEBUG
490
    gd_error_ex(GD_DEBUG, "gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
491
    gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG library version %d, %d-bit sample values\n",
492
                JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
493
    if (!im->trueColor) {
494
        for (i = 0; i < im->colorsTotal; i++) {
495
            if (!im->open[i]) {
496
                gd_error_ex(GD_DEBUG, "gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i,
497
                            im->red[i], im->green[i], im->blue[i]);
498
            }
499
        }
500
    }
501
#endif /* JPEG_DEBUG */
502
503
    memset(&cinfo, 0, sizeof(cinfo));
504
    memset(&jerr, 0, sizeof(jerr));
505
506
    cinfo.err = jpeg_std_error(&jerr);
507
    cinfo.client_data = &jmpbufw;
508
509
    if (setjmp(jmpbufw.jmpbuf) != 0) {
510
        /* we're here courtesy of longjmp */
511
        if (row) {
512
            gdFree(row);
513
        }
514
        return 1;
515
    }
516
517
    cinfo.err->emit_message = jpeg_emit_message;
518
    cinfo.err->error_exit = fatal_jpeg_error;
519
520
    jpeg_create_compress(&cinfo);
521
522
    cinfo.image_width = im->sx;
523
    cinfo.image_height = im->sy;
524
    cinfo.input_components = 3;     /* # of color components per pixel */
525
    cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
526
527
    jpeg_set_defaults(&cinfo);
528
529
    cinfo.density_unit = 1;
530
    cinfo.X_density = im->res_x;
531
    cinfo.Y_density = im->res_y;
532
533
    if (quality >= 0) {
534
        jpeg_set_quality(&cinfo, quality, TRUE);
535
    }
536
    if (force_no_subsampling || quality >= 90) {
537
        for (i = 0; i < cinfo.num_components; i++) {
538
            cinfo.comp_info[i].h_samp_factor = 1;
539
            cinfo.comp_info[i].v_samp_factor = 1;
540
        }
541
    }
542
543
    /* If user requests interlace, translate that to progressive JPEG */
544
    if ((progressive >= 0 && progressive) || (progressive < 0 && gdImageGetInterlaced(im))) {
545
#ifdef JPEG_DEBUG
546
        gd_error_ex(GD_DEBUG, "gd-jpeg: interlace set, outputting progressive JPEG image\n");
547
#endif
548
        jpeg_simple_progression(&cinfo);
549
    }
550
551
    jpeg_gdIOCtx_dest(&cinfo, outfile);
552
553
    row = (JSAMPROW)gdCalloc(1, cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE));
554
    if (row == 0) {
555
        gd_error("gd-jpeg: error: unable to allocate JPEG row structure: "
556
                 "gdCalloc returns NULL\n");
557
        jpeg_destroy_compress(&cinfo);
558
        return 1;
559
    }
560
561
    rowptr[0] = row;
562
563
    jpeg_start_compress(&cinfo, TRUE);
564
565
    if (gdJpegWriteMetadata(&cinfo, metadata)) {
566
        gd_error("gd-jpeg: error: unable to write metadata\n");
567
        goto error;
568
    }
569
570
    sprintf(comment, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d),", GD_JPEG_VERSION,
571
            JPEG_LIB_VERSION);
572
573
    if (quality >= 0) {
574
        sprintf(comment + strlen(comment), " quality = %d\n", quality);
575
    } else {
576
        strcat(comment + strlen(comment), " default quality\n");
577
    }
578
579
    jpeg_write_marker(&cinfo, JPEG_COM, (unsigned char *)comment, (unsigned int)strlen(comment));
580
581
    if (im->trueColor) {
582
#if BITS_IN_JSAMPLE == 12
583
        gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit\n"
584
                 "precision. This is mostly useless, because JPEGs on the web are\n"
585
                 "8-bit and such versions of the jpeg library won't read or write\n"
586
                 "them. GD doesn't support these unusual images. Edit your\n"
587
                 "jmorecfg.h file to specify the correct precision and completely\n"
588
                 "'make clean' and 'make install' libjpeg again. Sorry.\n");
589
        goto error;
590
#endif /* BITS_IN_JSAMPLE == 12 */
591
        for (i = 0; i < im->sy; i++) {
592
            for (jidx = 0, j = 0; j < im->sx; j++) {
593
                int val = im->tpixels[i][j];
594
                row[jidx++] = gdTrueColorGetRed(val);
595
                row[jidx++] = gdTrueColorGetGreen(val);
596
                row[jidx++] = gdTrueColorGetBlue(val);
597
            }
598
599
            nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
600
601
            if (nlines != 1) {
602
                gd_error("gd_jpeg: warning: jpeg_write_scanlines returns %u -- "
603
                         "expected 1\n",
604
                         nlines);
605
            }
606
        }
607
    } else {
608
        for (i = 0; i < im->sy; i++) {
609
            for (jidx = 0, j = 0; j < im->sx; j++) {
610
                int idx = im->pixels[i][j];
611
612
                /*
613
                 * NB: Although gd RGB values are ints, their max value is
614
                 * 255 (see the documentation for gdImageColorAllocate())
615
                 * -- perfect for 8-bit JPEG encoding (which is the norm)
616
                 */
617
#if BITS_IN_JSAMPLE == 8
618
                row[jidx++] = im->red[idx];
619
                row[jidx++] = im->green[idx];
620
                row[jidx++] = im->blue[idx];
621
#elif BITS_IN_JSAMPLE == 12
622
                row[jidx++] = im->red[idx] << 4;
623
                row[jidx++] = im->green[idx] << 4;
624
                row[jidx++] = im->blue[idx] << 4;
625
#else
626
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
627
#endif
628
            }
629
630
            nlines = jpeg_write_scanlines(&cinfo, rowptr, 1);
631
            if (nlines != 1) {
632
                gd_error("gd_jpeg: warning: jpeg_write_scanlines"
633
                         " returns %u -- expected 1\n",
634
                         nlines);
635
            }
636
        }
637
    }
638
639
    jpeg_finish_compress(&cinfo);
640
    jpeg_destroy_compress(&cinfo);
641
    gdFree(row);
642
    return 0;
643
644
error:
645
    jpeg_destroy_compress(&cinfo);
646
    if (row) {
647
        gdFree(row);
648
    }
649
    return 1;
650
}
651
652
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg(FILE *inFile)
653
{
654
    return gdImageCreateFromJpegEx(inFile, 1);
655
}
656
657
BGD_DECLARE(gdImagePtr)
658
gdImageCreateFromJpegEx(FILE *inFile, int ignore_warning)
659
{
660
    gdImagePtr im;
661
    gdJpegReadOptions options;
662
    gdIOCtx *in = gdNewFileCtx(inFile);
663
    if (in == NULL)
664
        return NULL;
665
    gdJpegReadOptionsInit(&options);
666
    options.ignore_warning = ignore_warning;
667
    im = gdImageCreateFromJpegCtxWithOptions(in, &options);
668
    in->gd_free(in);
669
    return im;
670
}
671
672
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr(int size, void *data)
673
{
674
    return gdImageCreateFromJpegPtrEx(size, data, 1);
675
}
676
677
BGD_DECLARE(gdImagePtr)
678
gdImageCreateFromJpegPtrEx(int size, void *data, int ignore_warning)
679
{
680
    gdImagePtr im;
681
    gdJpegReadOptions options;
682
    gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
683
    if (!in) {
684
        return 0;
685
    }
686
    gdJpegReadOptionsInit(&options);
687
    options.ignore_warning = ignore_warning;
688
    im = gdImageCreateFromJpegCtxWithOptions(in, &options);
689
    in->gd_free(in);
690
    return im;
691
}
692
693
BGD_DECLARE(gdImagePtr)
694
gdImageCreateFromJpegPtrWithOptions(int size, void *data, const gdJpegReadOptions *options)
695
{
696
    gdImagePtr im;
697
    gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
698
    if (!in) {
699
        return 0;
700
    }
701
    im = gdImageCreateFromJpegCtxWithOptions(in, options);
702
    in->gd_free(in);
703
    return im;
704
}
705
706
static void jpeg_gdIOCtx_src(j_decompress_ptr cinfo, gdIOCtx *infile);
707
708
static int CMYKToRGB(int c, int m, int y, int k, int inverted);
709
static gdImagePtr gdImageCreateFromJpegCtxWithOptionsInternal(
710
    gdIOCtx *infile, const gdJpegReadOptions *options);
711
712
static unsigned int gdJpegGcd(unsigned int a, unsigned int b)
713
{
714
    while (b != 0) {
715
        unsigned int t = b;
716
        b = a % b;
717
        a = t;
718
    }
719
    return a == 0 ? 1 : a;
720
}
721
722
static int gdJpegNormalizeReadOptions(const gdJpegReadOptions *options,
723
                                      gdJpegReadOptions *normalized)
724
{
725
    unsigned int divisor;
726
727
    gdJpegReadOptionsInit(normalized);
728
    if (options != NULL) {
729
        normalized->ignore_warning = options->ignore_warning;
730
        normalized->scale_num = options->scale_num;
731
        normalized->scale_denom = options->scale_denom;
732
        normalized->dct_method = options->dct_method;
733
    }
734
735
    if (normalized->scale_num == 0 || normalized->scale_denom == 0) {
736
        return 0;
737
    }
738
739
    divisor = gdJpegGcd(normalized->scale_num, normalized->scale_denom);
740
    normalized->scale_num /= divisor;
741
    normalized->scale_denom /= divisor;
742
743
    switch (normalized->dct_method) {
744
    case GD_JPEG_DCT_DEFAULT:
745
    case GD_JPEG_DCT_SLOW:
746
    case GD_JPEG_DCT_FAST:
747
    case GD_JPEG_DCT_FLOAT:
748
        break;
749
    default:
750
        return 0;
751
    }
752
753
    return 1;
754
}
755
756
static J_DCT_METHOD gdJpegMapDctMethod(int dct_method)
757
{
758
    switch (dct_method) {
759
    case GD_JPEG_DCT_SLOW:
760
        return JDCT_ISLOW;
761
    case GD_JPEG_DCT_FAST:
762
        return JDCT_IFAST;
763
    case GD_JPEG_DCT_FLOAT:
764
        return JDCT_FLOAT;
765
    case GD_JPEG_DCT_DEFAULT:
766
    default:
767
        return JDCT_DEFAULT;
768
    }
769
}
770
771
static int gdJpegScaledDimension(JDIMENSION source, unsigned int numerator,
772
                                 unsigned int denominator, int *target)
773
{
774
    unsigned long long scaled;
775
776
    scaled = ((unsigned long long)source * (unsigned long long)numerator) /
777
             (unsigned long long)denominator;
778
    if (scaled == 0 || scaled > INT_MAX) {
779
        return 0;
780
    }
781
782
    *target = (int)scaled;
783
    return 1;
784
}
785
786
static int gdJpegMarkerStartsWith(jpeg_saved_marker_ptr marker, const unsigned char *prefix,
787
                                  size_t prefix_size)
788
{
789
    return marker->data_length >= prefix_size && memcmp(marker->data, prefix, prefix_size) == 0;
790
}
791
792
static int gdJpegCollectIptc(const unsigned char *data, size_t size,
793
                             const unsigned char **iptc, size_t *iptc_size)
794
{
795
    size_t offset = sizeof("Photoshop 3.0");
796
797
    if (size < offset || memcmp(data, "Photoshop 3.0\0", offset) != 0) {
798
        return GD_META_ERR_PARSE;
799
        }
800
    while (offset < size) {
801
        unsigned int resource_size;
802
        unsigned int resource_id;
803
        size_t name_size, padded_name_size;
804
        if (size - offset < 9 || memcmp(data + offset, "8BIM", 4) != 0) {
805
            return GD_META_ERR_PARSE;
806
        }
807
        offset += 4;
808
        resource_id = ((unsigned int)data[offset] << 8) | data[offset + 1];
809
        offset += 2;
810
        name_size = data[offset++];
811
        padded_name_size = ((name_size + 2) & ~1U) - 1;
812
        if (size - offset < padded_name_size + 4) {
813
            return GD_META_ERR_PARSE;
814
        }
815
        offset += padded_name_size;
816
        resource_size = ((unsigned int)data[offset] << 24) |
817
                        ((unsigned int)data[offset + 1] << 16) |
818
                        ((unsigned int)data[offset + 2] << 8) |
819
                        data[offset + 3];
820
        offset += 4;
821
        if (resource_size > size - offset) {
822
            return GD_META_ERR_PARSE;
823
        }
824
        if (resource_id == 0x0404) {
825
            *iptc = data + offset;
826
            *iptc_size = resource_size;
827
            return GD_META_OK;
828
        }
829
        offset += resource_size + (resource_size & 1);
830
    }
831
    return GD_META_ERR_PARSE;
832
}
833
834
static int gdJpegCollectMetadata(j_decompress_ptr cinfo, gdImageMetadata *metadata)
835
{
836
    static const unsigned char exif_signature[] = {'E', 'x', 'i', 'f', '\0', '\0'};
837
    static const unsigned char xmp_signature[] = "http://ns.adobe.com/xap/1.0/";
838
    static const unsigned char iptc_signature[] = "Photoshop 3.0";
839
    jpeg_saved_marker_ptr marker;
840
    int status;
841
842
    if (metadata == NULL) {
843
        return GD_META_OK;
844
    }
845
846
    for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
847
        if (marker->marker == JPEG_APP0 + 1 &&
848
            gdJpegMarkerStartsWith(marker, exif_signature, sizeof(exif_signature))) {
849
            const unsigned char *tiff;
850
            size_t tiff_size;
851
            status = gdMetadataGetExifTiff(marker->data, marker->data_length, &tiff, &tiff_size);
852
            if (status == GD_META_OK) {
853
                status = gdImageMetadataSetProfile(metadata, "exif", tiff, tiff_size);
854
            }
855
            if (status != GD_META_OK) {
856
                return status;
857
            }
858
        } else if (marker->marker == JPEG_APP0 + 1 &&
859
                   gdJpegMarkerStartsWith(marker, xmp_signature, sizeof(xmp_signature))) {
860
            size_t prefix_size = sizeof(xmp_signature);
861
            if (marker->data_length > prefix_size && marker->data[prefix_size] == '\0') {
862
                prefix_size++;
863
            }
864
            status = gdImageMetadataSetProfile(metadata, "xmp", marker->data + prefix_size,
865
                                               marker->data_length - prefix_size);
866
            if (status != GD_META_OK) {
867
                return status;
868
            }
869
        } else if (marker->marker == JPEG_APP0 + 13 &&
870
                   gdJpegMarkerStartsWith(marker, iptc_signature, sizeof(iptc_signature))) {
871
            const unsigned char *iptc;
872
            size_t iptc_size;
873
            status = gdJpegCollectIptc(marker->data, marker->data_length, &iptc, &iptc_size);
874
            if (status == GD_META_OK) {
875
                status = gdImageMetadataSetProfile(metadata, "iptc", iptc, iptc_size);
876
            }
877
            if (status != GD_META_OK) {
878
                return status;
879
            }
880
        }
881
    }
882
883
    return GD_META_OK;
884
}
885
886
static int gdJpegReadMetadataCtx(gdIOCtxPtr infile, gdImageMetadata *metadata)
887
{
888
    struct jpeg_decompress_struct cinfo;
889
    struct jpeg_error_mgr jerr;
890
    jmpbuf_wrapper jmpbufw;
891
    int retval;
892
893
    if (infile == NULL || metadata == NULL) {
894
        return GD_META_ERR_INVALID;
895
    }
896
    memset(&cinfo, 0, sizeof(cinfo));
897
    memset(&jerr, 0, sizeof(jerr));
898
    memset(&jmpbufw, 0, sizeof(jmpbufw));
899
    jmpbufw.ignore_warning = 1;
900
    cinfo.err = jpeg_std_error(&jerr);
901
    cinfo.client_data = &jmpbufw;
902
    cinfo.err->emit_message = jpeg_emit_message;
903
    if (setjmp(jmpbufw.jmpbuf) != 0) {
904
        jpeg_destroy_decompress(&cinfo);
905
        return GD_META_ERR_PARSE;
906
    }
907
    cinfo.err->error_exit = fatal_jpeg_error;
908
    jpeg_create_decompress(&cinfo);
909
    jpeg_gdIOCtx_src(&cinfo, infile);
910
    jpeg_save_markers(&cinfo, JPEG_APP0 + 1, 0xFFFF);
911
    jpeg_save_markers(&cinfo, JPEG_APP0 + 13, 0xFFFF);
912
    retval = jpeg_read_header(&cinfo, TRUE);
913
    if (retval != JPEG_HEADER_OK) {
914
        jpeg_destroy_decompress(&cinfo);
915
        return GD_META_ERR_PARSE;
916
    }
917
    retval = gdJpegCollectMetadata(&cinfo, metadata);
918
    jpeg_destroy_decompress(&cinfo);
919
    return retval;
920
}
921
922
BGD_DECLARE(int) gdJpegGetMetadataCtx(gdIOCtxPtr infile, gdImageMetadata *metadata)
923
{
924
    return gdJpegReadMetadataCtx(infile, metadata) == GD_META_OK ? 0 : 1;
925
}
926
927
BGD_DECLARE(int) gdJpegGetMetadata(FILE *infile, gdImageMetadata *metadata)
928
{
929
    gdIOCtx *in;
930
    int result;
931
    in = gdNewFileCtx(infile);
932
    if (in == NULL) {
933
        return 1;
934
    }
935
    result = gdJpegGetMetadataCtx(in, metadata);
936
    in->gd_free(in);
937
    return result;
938
}
939
940
BGD_DECLARE(int) gdJpegGetMetadataPtr(int size, const void *data, gdImageMetadata *metadata)
941
{
942
    gdIOCtx *in;
943
    int result;
944
    if (size <= 0 || data == NULL) {
945
        return 1;
946
    }
947
    in = gdNewDynamicCtxEx(size, (void *)data, 0);
948
    if (in == NULL) {
949
        return 1;
950
    }
951
    result = gdJpegGetMetadataCtx(in, metadata);
952
    in->gd_free(in);
953
    return result;
954
}
955
956
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx(gdIOCtx *infile)
957
{
958
    return gdImageCreateFromJpegCtxEx(infile, 1);
959
}
960
961
BGD_DECLARE(gdImagePtr)
962
gdImageCreateFromJpegCtxEx(gdIOCtx *infile, int ignore_warning)
963
{
964
    gdJpegReadOptions options;
965
966
    gdJpegReadOptionsInit(&options);
967
    options.ignore_warning = ignore_warning;
968
    return gdImageCreateFromJpegCtxWithOptions(infile, &options);
969
}
970
971
BGD_DECLARE(gdImagePtr)
972
gdImageCreateFromJpegCtxWithOptions(gdIOCtx *infile, const gdJpegReadOptions *options)
973
{
974
    return gdImageCreateFromJpegCtxWithOptionsInternal(infile, options);
975
}
976
977
static gdImagePtr gdImageCreateFromJpegCtxWithOptionsInternal(
978
    gdIOCtx *infile, const gdJpegReadOptions *options)
979
{
980
    struct jpeg_decompress_struct cinfo;
981
    struct jpeg_error_mgr jerr;
982
    jmpbuf_wrapper jmpbufw;
983
    gdJpegReadOptions read_options;
984
    /* volatile so we can gdFree them after longjmp */
985
    volatile JSAMPROW row = 0;
986
    volatile gdImagePtr im = 0;
987
    JSAMPROW rowptr[1];
988
    JDIMENSION i, j;
989
    int retval;
990
    JDIMENSION nrows;
991
    int channels = 3;
992
    int inverted = 0;
993
    int target_width = 0;
994
    int target_height = 0;
995
996
#ifdef JPEG_DEBUG
997
    gd_error_ex(GD_DEBUG, "gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
998
    gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG library version %d, %d-bit sample values\n",
999
                JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
1000
    gd_error_ex(GD_DEBUG, "sizeof: %d\n", sizeof(struct jpeg_decompress_struct));
1001
#endif
1002
1003
    memset(&cinfo, 0, sizeof(cinfo));
1004
    memset(&jerr, 0, sizeof(jerr));
1005
1006
    if (!gdJpegNormalizeReadOptions(options, &read_options)) {
1007
        gd_error("gd-jpeg: error: invalid JPEG read options\n");
1008
        return 0;
1009
    }
1010
1011
    jmpbufw.ignore_warning = read_options.ignore_warning;
1012
1013
    cinfo.err = jpeg_std_error(&jerr);
1014
    cinfo.client_data = &jmpbufw;
1015
1016
    cinfo.err->emit_message = jpeg_emit_message;
1017
1018
    if (setjmp(jmpbufw.jmpbuf) != 0) {
1019
        /* we're here courtesy of longjmp */
1020
        if (row) {
1021
            gdFree(row);
1022
        }
1023
        if (im) {
1024
            gdImageDestroy(im);
1025
        }
1026
        return 0;
1027
    }
1028
1029
    cinfo.err->error_exit = fatal_jpeg_error;
1030
1031
    jpeg_create_decompress(&cinfo);
1032
1033
    jpeg_gdIOCtx_src(&cinfo, infile);
1034
1035
    /* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK
1036
     * files with inverted components.
1037
     */
1038
    jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);
1039
1040
    retval = jpeg_read_header(&cinfo, TRUE);
1041
    if (retval != JPEG_HEADER_OK) {
1042
        gd_error("gd-jpeg: warning: jpeg_read_header returns"
1043
                 " %d, expected %d\n",
1044
                 retval, JPEG_HEADER_OK);
1045
    }
1046
1047
    if (cinfo.image_height > INT_MAX) {
1048
        gd_error("gd-jpeg: warning: JPEG image height (%u) is"
1049
                 " greater than INT_MAX (%d) (and thus greater than"
1050
                 " gd can handle)",
1051
                 cinfo.image_height, INT_MAX);
1052
    }
1053
1054
    if (cinfo.image_width > INT_MAX) {
1055
        gd_error("gd-jpeg: warning: JPEG image width (%u) is"
1056
                 " greater than INT_MAX (%d) (and thus greater than"
1057
                 " gd can handle)\n",
1058
                 cinfo.image_width, INT_MAX);
1059
    }
1060
1061
    if (!gdJpegScaledDimension(cinfo.image_width, read_options.scale_num,
1062
                               read_options.scale_denom, &target_width) ||
1063
        !gdJpegScaledDimension(cinfo.image_height, read_options.scale_num,
1064
                               read_options.scale_denom, &target_height)) {
1065
        gd_error("gd-jpeg: error: requested JPEG scale produces invalid dimensions\n");
1066
        goto error;
1067
    }
1068
1069
    /* 2.0.22: very basic support for reading CMYK colorspace files. Nice for
1070
     * thumbnails but there's no support for fussy adjustment of the
1071
     * assumed properties of inks and paper.
1072
     */
1073
    if ((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
1074
        cinfo.out_color_space = JCS_CMYK;
1075
    } else {
1076
        cinfo.out_color_space = JCS_RGB;
1077
    }
1078
1079
    cinfo.scale_num = read_options.scale_num;
1080
    cinfo.scale_denom = read_options.scale_denom;
1081
    cinfo.dct_method = gdJpegMapDctMethod(read_options.dct_method);
1082
1083
    if (jpeg_start_decompress(&cinfo) != TRUE) {
1084
        gd_error("gd-jpeg: warning: jpeg_start_decompress"
1085
                 " reports suspended data source\n");
1086
    }
1087
1088
    if (cinfo.output_width > INT_MAX || cinfo.output_height > INT_MAX) {
1089
        gd_error("gd-jpeg: error: JPEG output dimensions are greater than INT_MAX\n");
1090
        goto error;
1091
    }
1092
1093
    im = gdImageCreateTrueColor((int)cinfo.output_width, (int)cinfo.output_height);
1094
    if (im == 0) {
1095
        gd_error("gd-jpeg error: cannot allocate gdImage struct\n");
1096
        goto error;
1097
    }
1098
1099
    /* check if the resolution is specified */
1100
    switch (cinfo.density_unit) {
1101
    case 1:
1102
        im->res_x = cinfo.X_density;
1103
        im->res_y = cinfo.Y_density;
1104
        break;
1105
    case 2:
1106
        im->res_x = DPCM2DPI(cinfo.X_density);
1107
        im->res_y = DPCM2DPI(cinfo.Y_density);
1108
        break;
1109
    }
1110
1111
#ifdef JPEG_DEBUG
1112
    gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG image information:");
1113
    if (cinfo.saw_JFIF_marker) {
1114
        gd_error_ex(GD_DEBUG, " JFIF version %d.%.2d", (int)cinfo.JFIF_major_version,
1115
                    (int)cinfo.JFIF_minor_version);
1116
    } else if (cinfo.saw_Adobe_marker) {
1117
        gd_error_ex(GD_DEBUG, " Adobe format");
1118
    } else {
1119
        gd_error_ex(GD_DEBUG, " UNKNOWN format");
1120
    }
1121
1122
    gd_error_ex(GD_DEBUG, " %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width,
1123
                cinfo.image_height, cinfo.output_width, cinfo.output_height, cinfo.data_precision);
1124
    gd_error_ex(GD_DEBUG, " %s", (cinfo.progressive_mode ? "progressive" : "baseline"));
1125
    gd_error_ex(GD_DEBUG, " image, %d quantized colors, ", cinfo.actual_number_of_colors);
1126
1127
    switch (cinfo.jpeg_color_space) {
1128
    case JCS_GRAYSCALE:
1129
        gd_error_ex(GD_DEBUG, "grayscale");
1130
        break;
1131
1132
    case JCS_RGB:
1133
        gd_error_ex(GD_DEBUG, "RGB");
1134
        break;
1135
1136
    case JCS_YCbCr:
1137
        gd_error_ex(GD_DEBUG, "YCbCr (a.k.a. YUV)");
1138
        break;
1139
1140
    case JCS_CMYK:
1141
        gd_error_ex(GD_DEBUG, "CMYK");
1142
        break;
1143
1144
    case JCS_YCCK:
1145
        gd_error_ex(GD_DEBUG, "YCbCrK");
1146
        break;
1147
1148
    default:
1149
        gd_error_ex(GD_DEBUG, "UNKNOWN (value: %d)", (int)cinfo.jpeg_color_space);
1150
        break;
1151
    }
1152
1153
    gd_error_ex(GD_DEBUG, " colorspace\n");
1154
    fflush(stdout);
1155
#endif /* JPEG_DEBUG */
1156
1157
    /* REMOVED by TBB 2/12/01. This field of the structure is
1158
     * documented as private, and sure enough it's gone in the
1159
     * latest libjpeg, replaced by something else. Unfortunately
1160
     * there is still no right way to find out if the file was
1161
     * progressive or not; just declare your intent before you
1162
     * write one by calling gdImageInterlace(im, 1) yourself.
1163
     * After all, we're not really supposed to rework JPEGs and
1164
     * write them out again anyway. Lossy compression, remember? */
1165
#if 0
1166
  gdImageInterlace (im, cinfo.progressive_mode != 0);
1167
#endif
1168
    if (cinfo.out_color_space == JCS_RGB) {
1169
        if (cinfo.output_components != 3) {
1170
            gd_error("gd-jpeg: error: JPEG color quantization"
1171
                     " request resulted in output_components == %d"
1172
                     " (expected 3 for RGB)\n",
1173
                     cinfo.output_components);
1174
            goto error;
1175
        }
1176
        channels = 3;
1177
    } else if (cinfo.out_color_space == JCS_CMYK) {
1178
        jpeg_saved_marker_ptr marker;
1179
        if (cinfo.output_components != 4) {
1180
            gd_error("gd-jpeg: error: JPEG color quantization"
1181
                     " request resulted in output_components == %d"
1182
                     " (expected 4 for CMYK)\n",
1183
                     cinfo.output_components);
1184
            goto error;
1185
        }
1186
        channels = 4;
1187
1188
        marker = cinfo.marker_list;
1189
        while (marker) {
1190
            if ((marker->marker == (JPEG_APP0 + 14)) && (marker->data_length >= 12) &&
1191
                (!strncmp((const char *)marker->data, "Adobe", 5))) {
1192
                inverted = 1;
1193
                break;
1194
            }
1195
            marker = marker->next;
1196
        }
1197
    } else {
1198
        gd_error("gd-jpeg: error: unexpected colorspace\n");
1199
        goto error;
1200
    }
1201
#if BITS_IN_JSAMPLE == 12
1202
    gd_error_ex(GD_ERROR, "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
1203
                          "precision. This is mostly useless, because JPEGs on the web are\n"
1204
                          "8-bit and such versions of the jpeg library won't read or write\n"
1205
                          "them. GD doesn't support these unusual images. Edit your\n"
1206
                          "jmorecfg.h file to specify the correct precision and completely\n"
1207
                          "'make clean' and 'make install' libjpeg again. Sorry.\n");
1208
    goto error;
1209
#endif /* BITS_IN_JSAMPLE == 12 */
1210
1211
    row = gdCalloc(cinfo.output_width * channels, sizeof(JSAMPLE));
1212
    if (row == 0) {
1213
        gd_error("gd-jpeg: error: unable to allocate row for"
1214
                 " JPEG scanline: gdCalloc returns NULL\n");
1215
        goto error;
1216
    }
1217
    rowptr[0] = row;
1218
    if (cinfo.out_color_space == JCS_CMYK) {
1219
        for (i = 0; i < cinfo.output_height; i++) {
1220
            register JSAMPROW currow = row;
1221
            register int *tpix = im->tpixels[i];
1222
            nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
1223
            if (nrows != 1) {
1224
                gd_error("gd-jpeg: error: jpeg_read_scanlines"
1225
                         " returns %u, expected 1\n",
1226
                         nrows);
1227
                goto error;
1228
            }
1229
            for (j = 0; j < cinfo.output_width; j++, currow += 4, tpix++) {
1230
                *tpix = CMYKToRGB(currow[0], currow[1], currow[2], currow[3], inverted);
1231
            }
1232
        }
1233
    } else {
1234
        for (i = 0; i < cinfo.output_height; i++) {
1235
            register JSAMPROW currow = row;
1236
            register int *tpix = im->tpixels[i];
1237
            nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
1238
            if (nrows != 1) {
1239
                gd_error("gd-jpeg: error: jpeg_read_scanlines"
1240
                         " returns %u, expected 1\n",
1241
                         nrows);
1242
                goto error;
1243
            }
1244
            for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) {
1245
                *tpix = gdTrueColor(currow[0], currow[1], currow[2]);
1246
            }
1247
        }
1248
    }
1249
1250
    if (jpeg_finish_decompress(&cinfo) != TRUE) {
1251
        gd_error("gd-jpeg: warning: jpeg_finish_decompress"
1252
                 " reports suspended data source\n");
1253
    }
1254
    /* TBB 2.0.29: we should do our best to read whatever we can read, and a
1255
     * warning is a warning. A fatal error on warnings doesn't make sense. */
1256
#if 0
1257
  /* This was originally added by Truxton Fulton */
1258
  if (cinfo.err->num_warnings > 0)
1259
    goto error;
1260
#endif
1261
1262
    jpeg_destroy_decompress(&cinfo);
1263
    gdFree(row);
1264
1265
    if (im->sx != target_width || im->sy != target_height) {
1266
        gdImagePtr scaled = gdImageScale(im, target_width, target_height);
1267
        gdImageDestroy(im);
1268
        im = scaled;
1269
        if (im == NULL) {
1270
            gd_error("gd-jpeg: error: unable to resize decoded JPEG image\n");
1271
            return 0;
1272
        }
1273
    }
1274
1275
    return im;
1276
1277
error:
1278
    jpeg_destroy_decompress(&cinfo);
1279
1280
    if (row) {
1281
        gdFree(row);
1282
    }
1283
    if (im) {
1284
        gdImageDestroy(im);
1285
    }
1286
1287
    return 0;
1288
}
1289
1290
/* A very basic conversion approach, TBB */
1291
1292
static int CMYKToRGB(int c, int m, int y, int k, int inverted)
1293
{
1294
    if (inverted) {
1295
        c = 255 - c;
1296
        m = 255 - m;
1297
        y = 255 - y;
1298
        k = 255 - k;
1299
    }
1300
1301
    return gdTrueColor((255 - c) * (255 - k) / 255, (255 - m) * (255 - k) / 255,
1302
                       (255 - y) * (255 - k) / 255);
1303
#if 0
1304
  if (inverted) {
1305
    c = 255 - c;
1306
    m = 255 - m;
1307
    y = 255 - y;
1308
    k = 255 - k;
1309
  }
1310
  c = c * (255 - k) / 255 + k;
1311
  if (c > 255) {
1312
    c = 255;
1313
  }
1314
  if (c < 0) {
1315
    c = 0;
1316
  }
1317
  m = m * (255 - k) / 255 + k;
1318
  if (m > 255) {
1319
    m = 255;
1320
  }
1321
  if (m < 0) {
1322
    m = 0;
1323
  }
1324
  y = y * (255 - k) / 255 + k;
1325
  if (y > 255) {
1326
    y = 255;
1327
  }
1328
  if (y < 0) {
1329
    y = 0;
1330
  }
1331
  c = 255 - c;
1332
  m = 255 - m;
1333
  y = 255 - y;
1334
  return gdTrueColor (c, m, y);
1335
#endif
1336
}
1337
1338
/*
1339
 * gdIOCtx JPEG data sources and sinks, T. Boutell
1340
 * almost a simple global replace from T. Lane's stdio versions.
1341
 */
1342
1343
/* Expanded data source object for gdIOCtx input */
1344
typedef struct {
1345
    struct jpeg_source_mgr pub; /* public fields */
1346
    gdIOCtx *infile;            /* source stream */
1347
    unsigned char *buffer;      /* start of buffer */
1348
    boolean start_of_file;      /* have we gotten any data yet? */
1349
} my_source_mgr;
1350
1351
typedef my_source_mgr *my_src_ptr;
1352
1353
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
1354
1355
/*
1356
 * Initialize source --- called by jpeg_read_header
1357
 * before any data is actually read.
1358
 */
1359
1360
static void init_source(j_decompress_ptr cinfo)
1361
{
1362
    my_src_ptr src = (my_src_ptr)cinfo->src;
1363
1364
    /* We reset the empty-input-file flag for each image,
1365
     * but we don't clear the input buffer.
1366
     * This is correct behavior for reading a series of images from one source.
1367
     */
1368
    src->start_of_file = TRUE;
1369
}
1370
1371
/*
1372
 * Fill the input buffer --- called whenever buffer is emptied.
1373
 *
1374
 * In typical applications, this should read fresh data into the buffer
1375
 * (ignoring the current state of next_input_byte & bytes_in_buffer),
1376
 * reset the pointer & count to the start of the buffer, and return TRUE
1377
 * indicating that the buffer has been reloaded.  It is not necessary to
1378
 * fill the buffer entirely, only to obtain at least one more byte.
1379
 *
1380
 * There is no such thing as an EOF return.  If the end of the file has been
1381
 * reached, the routine has a choice of ERREXIT() or inserting fake data into
1382
 * the buffer.  In most cases, generating a warning message and inserting a
1383
 * fake EOI marker is the best course of action --- this will allow the
1384
 * decompressor to output however much of the image is there.  However,
1385
 * the resulting error message is misleading if the real problem is an empty
1386
 * input file, so we handle that case specially.
1387
 *
1388
 * In applications that need to be able to suspend compression due to input
1389
 * not being available yet, a FALSE return indicates that no more data can be
1390
 * obtained right now, but more may be forthcoming later.  In this situation,
1391
 * the decompressor will return to its caller (with an indication of the
1392
 * number of scanlines it has read, if any).  The application should resume
1393
 * decompression after it has loaded more data into the input buffer.  Note
1394
 * that there are substantial restrictions on the use of suspension --- see
1395
 * the documentation.
1396
 *
1397
 * When suspending, the decompressor will back up to a convenient restart point
1398
 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
1399
 * indicate where the restart point will be if the current call returns FALSE.
1400
 * Data beyond this point must be rescanned after resumption, so move it to
1401
 * the front of the buffer rather than discarding it.
1402
 */
1403
1404
#define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
1405
1406
static boolean fill_input_buffer(j_decompress_ptr cinfo)
1407
{
1408
    my_src_ptr src = (my_src_ptr)cinfo->src;
1409
    /* 2.0.12: signed size. Thanks to Geert Jansen */
1410
    ssize_t nbytes = 0;
1411
    memset(src->buffer, 0, INPUT_BUF_SIZE);
1412
1413
    while (nbytes < INPUT_BUF_SIZE) {
1414
        int got = gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
1415
1416
        if ((got == EOF) || (got == 0)) {
1417
            /* EOF or error. If we got any data, don't worry about it.
1418
             * If we didn't, then this is unexpected. */
1419
            if (!nbytes) {
1420
                nbytes = -1;
1421
            }
1422
            break;
1423
        }
1424
        nbytes += got;
1425
    }
1426
1427
    if (nbytes <= 0) {
1428
        if (src->start_of_file) {
1429
            /* Treat empty input file as fatal error */
1430
            ERREXIT(cinfo, JERR_INPUT_EMPTY);
1431
        }
1432
        WARNMS(cinfo, JWRN_JPEG_EOF);
1433
        /* Insert a fake EOI marker */
1434
        src->buffer[0] = (unsigned char)0xFF;
1435
        src->buffer[1] = (unsigned char)JPEG_EOI;
1436
        nbytes = 2;
1437
    }
1438
1439
    src->pub.next_input_byte = src->buffer;
1440
    src->pub.bytes_in_buffer = nbytes;
1441
    src->start_of_file = FALSE;
1442
1443
    return TRUE;
1444
}
1445
1446
/*
1447
 * Skip data --- used to skip over a potentially large amount of
1448
 * uninteresting data (such as an APPn marker).
1449
 *
1450
 * Writers of suspendable-input applications must note that skip_input_data
1451
 * is not granted the right to give a suspension return.  If the skip extends
1452
 * beyond the data currently in the buffer, the buffer can be marked empty so
1453
 * that the next read will cause a fill_input_buffer call that can suspend.
1454
 * Arranging for additional bytes to be discarded before reloading the input
1455
 * buffer is the application writer's problem.
1456
 */
1457
1458
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
1459
{
1460
    my_src_ptr src = (my_src_ptr)cinfo->src;
1461
1462
    /* Just a dumb implementation for now. Not clear that being smart is worth
1463
     * any trouble anyway --- large skips are infrequent.
1464
     */
1465
    if (num_bytes > 0) {
1466
        while (num_bytes > (long)src->pub.bytes_in_buffer) {
1467
            num_bytes -= (long)src->pub.bytes_in_buffer;
1468
            (void)fill_input_buffer(cinfo);
1469
            /* note we assume that fill_input_buffer will never return FALSE,
1470
             * so suspension need not be handled.
1471
             */
1472
        }
1473
        src->pub.next_input_byte += (size_t)num_bytes;
1474
        src->pub.bytes_in_buffer -= (size_t)num_bytes;
1475
    }
1476
}
1477
1478
/*
1479
 * An additional method that can be provided by data source modules is the
1480
 * resync_to_restart method for error recovery in the presence of RST markers.
1481
 * For the moment, this source module just uses the default resync method
1482
 * provided by the JPEG library.  That method assumes that no backtracking
1483
 * is possible.
1484
 */
1485
1486
/*
1487
 * Terminate source --- called by jpeg_finish_decompress
1488
 * after all data has been read.  Often a no-op.
1489
 *
1490
 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
1491
 * application must deal with any cleanup that should happen even
1492
 * for error exit.
1493
 */
1494
static void term_source(j_decompress_ptr cinfo) { (void)cinfo; }
1495
1496
/*
1497
 * Prepare for input from a gdIOCtx stream.
1498
 * The caller must have already opened the stream, and is responsible
1499
 * for closing it after finishing decompression.
1500
 */
1501
1502
static void jpeg_gdIOCtx_src(j_decompress_ptr cinfo, gdIOCtx *infile)
1503
{
1504
    my_src_ptr src;
1505
1506
    /* The source object and input buffer are made permanent so that a series
1507
     * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src
1508
     * only before the first one.  (If we discarded the buffer at the end of
1509
     * one image, we'd likely lose the start of the next one.)
1510
     * This makes it unsafe to use this manager and a different source
1511
     * manager serially with the same JPEG object.  Caveat programmer.
1512
     */
1513
    if (cinfo->src == NULL) {
1514
        /* first time for this JPEG object? */
1515
        cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)(
1516
            (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
1517
        src = (my_src_ptr)cinfo->src;
1518
        src->buffer = (unsigned char *)(*cinfo->mem->alloc_small)(
1519
            (j_common_ptr)cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof(unsigned char));
1520
    }
1521
1522
    src = (my_src_ptr)cinfo->src;
1523
    src->pub.init_source = init_source;
1524
    src->pub.fill_input_buffer = fill_input_buffer;
1525
    src->pub.skip_input_data = skip_input_data;
1526
    src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
1527
    src->pub.term_source = term_source;
1528
    src->infile = infile;
1529
    src->pub.bytes_in_buffer = 0;    /* forces fill_input_buffer on first read */
1530
    src->pub.next_input_byte = NULL; /* until buffer loaded */
1531
}
1532
1533
/* Expanded data destination object for stdio output */
1534
typedef struct {
1535
    struct jpeg_destination_mgr pub; /* public fields */
1536
    gdIOCtx *outfile;                /* target stream */
1537
    unsigned char *buffer;           /* start of buffer */
1538
} my_destination_mgr;
1539
1540
typedef my_destination_mgr *my_dest_ptr;
1541
1542
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
1543
1544
/*
1545
 * Initialize destination --- called by jpeg_start_compress
1546
 * before any data is actually written.
1547
 */
1548
1549
static void init_destination(j_compress_ptr cinfo)
1550
{
1551
    my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
1552
1553
    /* Allocate the output buffer --- it will be released when done with image
1554
     */
1555
    dest->buffer = (unsigned char *)(*cinfo->mem->alloc_small)(
1556
        (j_common_ptr)cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(unsigned char));
1557
1558
    dest->pub.next_output_byte = dest->buffer;
1559
    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
1560
}
1561
1562
/*
1563
 * Empty the output buffer --- called whenever buffer fills up.
1564
 *
1565
 * In typical applications, this should write the entire output buffer
1566
 * (ignoring the current state of next_output_byte & free_in_buffer),
1567
 * reset the pointer & count to the start of the buffer, and return TRUE
1568
 * indicating that the buffer has been dumped.
1569
 *
1570
 * In applications that need to be able to suspend compression due to output
1571
 * overrun, a FALSE return indicates that the buffer cannot be emptied now.
1572
 * In this situation, the compressor will return to its caller (possibly with
1573
 * an indication that it has not accepted all the supplied scanlines).  The
1574
 * application should resume compression after it has made more room in the
1575
 * output buffer.  Note that there are substantial restrictions on the use of
1576
 * suspension --- see the documentation.
1577
 *
1578
 * When suspending, the compressor will back up to a convenient restart point
1579
 * (typically the start of the current MCU). next_output_byte & free_in_buffer
1580
 * indicate where the restart point will be if the current call returns FALSE.
1581
 * Data beyond this point will be regenerated after resumption, so do not
1582
 * write it out when emptying the buffer externally.
1583
 */
1584
1585
static boolean empty_output_buffer(j_compress_ptr cinfo)
1586
{
1587
    my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
1588
1589
    if (gdPutBuf(dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t)OUTPUT_BUF_SIZE) {
1590
        ERREXIT(cinfo, JERR_FILE_WRITE);
1591
    }
1592
1593
    dest->pub.next_output_byte = dest->buffer;
1594
    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
1595
1596
    return TRUE;
1597
}
1598
1599
/*
1600
 * Terminate destination --- called by jpeg_finish_compress
1601
 * after all data has been written.  Usually needs to flush buffer.
1602
 *
1603
 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
1604
 * application must deal with any cleanup that should happen even
1605
 * for error exit.
1606
 */
1607
1608
static void term_destination(j_compress_ptr cinfo)
1609
{
1610
    my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
1611
    size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
1612
1613
    /* Write any data remaining in the buffer */
1614
    if (datacount > 0) {
1615
        if ((size_t)gdPutBuf(dest->buffer, datacount, dest->outfile) != datacount) {
1616
            ERREXIT(cinfo, JERR_FILE_WRITE);
1617
        }
1618
    }
1619
}
1620
1621
/*
1622
 * Prepare for output to a stdio stream.
1623
 * The caller must have already opened the stream, and is responsible
1624
 * for closing it after finishing compression.
1625
 */
1626
1627
static void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile)
1628
{
1629
    my_dest_ptr dest;
1630
1631
    /* The destination object is made permanent so that multiple JPEG images
1632
     * can be written to the same file without re-executing jpeg_stdio_dest.
1633
     * This makes it dangerous to use this manager and a different destination
1634
     * manager serially with the same JPEG object, because their private object
1635
     * sizes may be different.  Caveat programmer.
1636
     */
1637
    if (cinfo->dest == NULL) {
1638
        /* first time for this JPEG object? */
1639
        cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small)(
1640
            (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(my_destination_mgr));
1641
    }
1642
1643
    dest = (my_dest_ptr)cinfo->dest;
1644
    dest->pub.init_destination = init_destination;
1645
    dest->pub.empty_output_buffer = empty_output_buffer;
1646
    dest->pub.term_destination = term_destination;
1647
    dest->outfile = outfile;
1648
}
1649
1650
#else /* !HAVE_LIBJPEG */
1651
1652
1
static void _noJpegError(void) { gd_error("JPEG image support has been disabled\n"); }
1653
1654
BGD_DECLARE(void) gdJpegInfoInit(gdJpegInfo *info)
1655
0
{
1656
0
    if (info != NULL) {
1657
0
        memset(info, 0, sizeof(*info));
1658
0
    }
1659
0
}
1660
1661
BGD_DECLARE(void) gdJpegReadOptionsInit(gdJpegReadOptions *options)
1662
0
{
1663
0
    if (options != NULL) {
1664
0
        memset(options, 0, sizeof(*options));
1665
0
        options->ignore_warning = 1;
1666
0
        options->scale_num = 1;
1667
0
        options->scale_denom = 1;
1668
0
        options->dct_method = GD_JPEG_DCT_DEFAULT;
1669
0
    }
1670
0
}
1671
1672
BGD_DECLARE(void) gdJpegWriteOptionsInit(gdJpegWriteOptions *options)
1673
0
{
1674
0
    if (options != NULL) {
1675
0
        memset(options, 0, sizeof(*options));
1676
0
        options->quality = -1;
1677
0
    }
1678
0
}
1679
1680
BGD_DECLARE(int) gdJpegGetInfo(FILE *infile, gdJpegInfo *info)
1681
0
{
1682
0
    ARG_NOT_USED(infile);
1683
0
    ARG_NOT_USED(info);
1684
0
    _noJpegError();
1685
0
    return 1;
1686
0
}
1687
1688
BGD_DECLARE(int) gdJpegGetInfoCtx(gdIOCtxPtr infile, gdJpegInfo *info)
1689
0
{
1690
0
    ARG_NOT_USED(infile);
1691
0
    ARG_NOT_USED(info);
1692
0
    _noJpegError();
1693
0
    return 1;
1694
0
}
1695
1696
BGD_DECLARE(int) gdJpegGetInfoPtr(int size, const void *data, gdJpegInfo *info)
1697
0
{
1698
0
    ARG_NOT_USED(size);
1699
0
    ARG_NOT_USED(data);
1700
0
    ARG_NOT_USED(info);
1701
0
    _noJpegError();
1702
0
    return 1;
1703
0
}
1704
1705
BGD_DECLARE(int) gdJpegGetMetadata(FILE *infile, gdImageMetadata *metadata)
1706
0
{
1707
0
    ARG_NOT_USED(infile);
1708
0
    ARG_NOT_USED(metadata);
1709
0
    _noJpegError();
1710
0
    return 1;
1711
0
}
1712
1713
BGD_DECLARE(int) gdJpegGetMetadataCtx(gdIOCtxPtr infile, gdImageMetadata *metadata)
1714
0
{
1715
0
    ARG_NOT_USED(infile);
1716
0
    ARG_NOT_USED(metadata);
1717
0
    _noJpegError();
1718
0
    return 1;
1719
0
}
1720
1721
BGD_DECLARE(int) gdJpegGetMetadataPtr(int size, const void *data, gdImageMetadata *metadata)
1722
0
{
1723
0
    ARG_NOT_USED(size);
1724
0
    ARG_NOT_USED(data);
1725
0
    ARG_NOT_USED(metadata);
1726
0
    _noJpegError();
1727
0
    return 1;
1728
0
}
1729
1730
BGD_DECLARE(void) gdImageJpeg(gdImagePtr im, FILE *outFile, int quality)
1731
0
{
1732
0
    ARG_NOT_USED(im);
1733
0
    ARG_NOT_USED(outFile);
1734
0
    ARG_NOT_USED(quality);
1735
0
    _noJpegError();
1736
0
}
1737
1738
BGD_DECLARE(void *) gdImageJpegPtr(gdImagePtr im, int *size, int quality)
1739
0
{
1740
0
    ARG_NOT_USED(im);
1741
0
    ARG_NOT_USED(size);
1742
0
    ARG_NOT_USED(quality);
1743
0
    _noJpegError();
1744
0
    return NULL;
1745
0
}
1746
1747
BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
1748
0
{
1749
0
    ARG_NOT_USED(im);
1750
0
    ARG_NOT_USED(outfile);
1751
0
    ARG_NOT_USED(quality);
1752
0
    _noJpegError();
1753
0
}
1754
1755
BGD_DECLARE(int)
1756
gdImageJpegWithOptions(gdImagePtr im, FILE *outFile, const gdJpegWriteOptions *options)
1757
0
{
1758
0
    ARG_NOT_USED(im);
1759
0
    ARG_NOT_USED(outFile);
1760
0
    ARG_NOT_USED(options);
1761
0
    _noJpegError();
1762
0
    return 1;
1763
0
}
1764
1765
BGD_DECLARE(int)
1766
gdImageJpegCtxWithOptions(gdImagePtr im, gdIOCtx *outfile, const gdJpegWriteOptions *options)
1767
0
{
1768
0
    ARG_NOT_USED(im);
1769
0
    ARG_NOT_USED(outfile);
1770
0
    ARG_NOT_USED(options);
1771
0
    _noJpegError();
1772
0
    return 1;
1773
0
}
1774
1775
BGD_DECLARE(void *)
1776
gdImageJpegPtrWithOptions(gdImagePtr im, int *size, const gdJpegWriteOptions *options)
1777
0
{
1778
0
    ARG_NOT_USED(im);
1779
0
    ARG_NOT_USED(size);
1780
0
    ARG_NOT_USED(options);
1781
0
    _noJpegError();
1782
0
    return NULL;
1783
0
}
1784
1785
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg(FILE *inFile)
1786
0
{
1787
0
    ARG_NOT_USED(inFile);
1788
0
    _noJpegError();
1789
0
    return NULL;
1790
0
}
1791
1792
BGD_DECLARE(gdImagePtr)
1793
gdImageCreateFromJpegEx(FILE *inFile, int ignore_warning)
1794
0
{
1795
0
    ARG_NOT_USED(inFile);
1796
0
    ARG_NOT_USED(ignore_warning);
1797
0
    _noJpegError();
1798
0
    return NULL;
1799
0
}
1800
1801
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr(int size, void *data)
1802
1
{
1803
1
    ARG_NOT_USED(size);
1804
1
    ARG_NOT_USED(data);
1805
1
    _noJpegError();
1806
1
    return NULL;
1807
1
}
1808
1809
BGD_DECLARE(gdImagePtr)
1810
gdImageCreateFromJpegPtrEx(int size, void *data, int ignore_warning)
1811
0
{
1812
0
    ARG_NOT_USED(size);
1813
0
    ARG_NOT_USED(data);
1814
0
    ARG_NOT_USED(ignore_warning);
1815
0
    _noJpegError();
1816
0
    return NULL;
1817
0
}
1818
1819
BGD_DECLARE(gdImagePtr)
1820
gdImageCreateFromJpegPtrWithOptions(int size, void *data, const gdJpegReadOptions *options)
1821
0
{
1822
0
    ARG_NOT_USED(size);
1823
0
    ARG_NOT_USED(data);
1824
0
    ARG_NOT_USED(options);
1825
0
    _noJpegError();
1826
0
    return NULL;
1827
0
}
1828
1829
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx(gdIOCtx *infile)
1830
0
{
1831
0
    ARG_NOT_USED(infile);
1832
0
    _noJpegError();
1833
0
    return NULL;
1834
0
}
1835
1836
BGD_DECLARE(gdImagePtr)
1837
gdImageCreateFromJpegCtxEx(gdIOCtx *infile, int ignore_warning)
1838
0
{
1839
0
    ARG_NOT_USED(infile);
1840
0
    ARG_NOT_USED(ignore_warning);
1841
0
    _noJpegError();
1842
0
    return NULL;
1843
0
}
1844
1845
BGD_DECLARE(gdImagePtr)
1846
gdImageCreateFromJpegCtxWithOptions(gdIOCtx *infile, const gdJpegReadOptions *options)
1847
0
{
1848
0
    ARG_NOT_USED(infile);
1849
0
    ARG_NOT_USED(options);
1850
0
    _noJpegError();
1851
    return NULL;
1852
0
}
1853
1854
#endif /* HAVE_LIBJPEG */