Coverage Report

Created: 2026-08-11 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvips/libvips/foreign/jpegload.c
Line
Count
Source
1
/* load jpeg from a file
2
 *
3
 * 24/11/11
4
 *  - wrap a class around the jpeg writer
5
 * 29/11/11
6
 *  - split to make load, load from buffer and load from file
7
 * 24/7/21
8
 *  - add fail_on support
9
 */
10
11
/*
12
13
  This file is part of VIPS.
14
15
  VIPS is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU Lesser General Public License as published by
17
  the Free Software Foundation; either version 2 of the License, or
18
  (at your option) any later version.
19
20
  This program is distributed in the hope that it will be useful,
21
  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
  GNU Lesser General Public License for more details.
24
25
  You should have received a copy of the GNU Lesser General Public License
26
  along with this program; if not, write to the Free Software
27
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28
  02110-1301  USA
29
30
 */
31
32
/*
33
34
  These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
35
36
 */
37
38
#ifdef HAVE_CONFIG_H
39
#include <config.h>
40
#endif /*HAVE_CONFIG_H*/
41
#include <glib/gi18n-lib.h>
42
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <setjmp.h>
47
48
#include <vips/vips.h>
49
#include <vips/buf.h>
50
#include <vips/internal.h>
51
52
#include "pforeign.h"
53
54
#ifdef HAVE_JPEG
55
56
#ifdef HAVE_EXIF
57
#ifdef UNTAGGED_EXIF
58
#include <exif-data.h>
59
#include <exif-loader.h>
60
#include <exif-ifd.h>
61
#include <exif-utils.h>
62
#else /*!UNTAGGED_EXIF*/
63
#include <libexif/exif-data.h>
64
#include <libexif/exif-loader.h>
65
#include <libexif/exif-ifd.h>
66
#include <libexif/exif-utils.h>
67
#endif /*UNTAGGED_EXIF*/
68
#endif /*HAVE_EXIF*/
69
70
typedef struct _VipsForeignLoadJpeg {
71
  VipsForeignLoad parent_object;
72
73
  /* Set by subclasses.
74
   */
75
  VipsSource *source;
76
77
  /* Remove DoS limits.
78
   */
79
  gboolean unlimited;
80
81
  /* Shrink by this much during load.
82
   */
83
  int shrink;
84
85
  /* Autorotate using exif orientation tag.
86
   */
87
  gboolean autorotate;
88
89
} VipsForeignLoadJpeg;
90
91
typedef VipsForeignLoadClass VipsForeignLoadJpegClass;
92
93
117
G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadJpeg, vips_foreign_load_jpeg,
94
117
  VIPS_TYPE_FOREIGN_LOAD);
95
117
96
117
static void
97
117
vips_foreign_load_jpeg_dispose(GObject *gobject)
98
75.3k
{
99
75.3k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) gobject;
100
101
75.3k
  VIPS_UNREF(jpeg->source);
102
103
75.3k
  G_OBJECT_CLASS(vips_foreign_load_jpeg_parent_class)->dispose(gobject);
104
75.3k
}
105
106
static int
107
vips_foreign_load_jpeg_build(VipsObject *object)
108
75.3k
{
109
75.3k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object;
110
111
75.3k
  if (jpeg->shrink != 1 &&
112
769
    jpeg->shrink != 2 &&
113
292
    jpeg->shrink != 4 &&
114
259
    jpeg->shrink != 8) {
115
1
    vips_error("VipsFormatLoadJpeg",
116
1
      _("bad shrink factor %d"), jpeg->shrink);
117
1
    return -1;
118
1
  }
119
120
75.3k
  return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_parent_class)
121
75.3k
    ->build(object);
122
75.3k
}
123
124
static VipsForeignFlags
125
vips_foreign_load_jpeg_get_flags(VipsForeignLoad *load)
126
75.3k
{
127
75.3k
  return VIPS_FOREIGN_SEQUENTIAL;
128
75.3k
}
129
130
static VipsForeignFlags
131
vips_foreign_load_jpeg_get_flags_filename(const char *filename)
132
0
{
133
0
  return VIPS_FOREIGN_SEQUENTIAL;
134
0
}
135
136
static int
137
vips_foreign_load_jpeg_header(VipsForeignLoad *load)
138
75.3k
{
139
75.3k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
140
141
75.3k
  if (vips__jpeg_read_source(jpeg->source,
142
75.3k
      load->out, TRUE, jpeg->shrink, load->fail_on,
143
75.3k
      jpeg->autorotate, jpeg->unlimited))
144
8.43k
    return -1;
145
146
66.8k
  return 0;
147
75.3k
}
148
149
static int
150
vips_foreign_load_jpeg_load(VipsForeignLoad *load)
151
56.0k
{
152
56.0k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
153
154
56.0k
  if (vips__jpeg_read_source(jpeg->source,
155
56.0k
      load->real, FALSE, jpeg->shrink, load->fail_on,
156
56.0k
      jpeg->autorotate, jpeg->unlimited))
157
35.8k
    return -1;
158
159
20.1k
  return 0;
160
56.0k
}
161
162
static void
163
vips_foreign_load_jpeg_class_init(VipsForeignLoadJpegClass *class)
164
19
{
165
19
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
166
19
  VipsObjectClass *object_class = (VipsObjectClass *) class;
167
19
  VipsForeignClass *foreign_class = (VipsForeignClass *) class;
168
19
  VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
169
170
19
  gobject_class->dispose = vips_foreign_load_jpeg_dispose;
171
19
  gobject_class->set_property = vips_object_set_property;
172
19
  gobject_class->get_property = vips_object_get_property;
173
174
19
  object_class->nickname = "jpegload_base";
175
19
  object_class->description = _("load jpeg");
176
19
  object_class->build = vips_foreign_load_jpeg_build;
177
178
  /* We are fast at is_a(), so high priority.
179
   */
180
19
  foreign_class->priority = 150;
181
182
19
  load_class->get_flags_filename = vips_foreign_load_jpeg_get_flags_filename;
183
19
  load_class->get_flags = vips_foreign_load_jpeg_get_flags;
184
19
  load_class->header = vips_foreign_load_jpeg_header;
185
19
  load_class->load = vips_foreign_load_jpeg_load;
186
187
19
  VIPS_ARG_INT(class, "shrink", 20,
188
19
    _("Shrink"),
189
19
    _("Shrink factor on load"),
190
19
    VIPS_ARGUMENT_OPTIONAL_INPUT,
191
19
    G_STRUCT_OFFSET(VipsForeignLoadJpeg, shrink),
192
19
    1, 8, 1);
193
194
19
  VIPS_ARG_BOOL(class, "autorotate", 21,
195
19
    _("Autorotate"),
196
19
    _("Rotate image using exif orientation"),
197
19
    VIPS_ARGUMENT_OPTIONAL_INPUT,
198
19
    G_STRUCT_OFFSET(VipsForeignLoadJpeg, autorotate),
199
19
    FALSE);
200
201
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
202
  VIPS_ARG_BOOL(class, "unlimited", 22,
203
    _("Unlimited"),
204
    _("Remove all denial of service limits"),
205
    VIPS_ARGUMENT_OPTIONAL_INPUT,
206
    G_STRUCT_OFFSET(VipsForeignLoadJpeg, unlimited),
207
    FALSE);
208
#endif
209
19
}
210
211
static void
212
vips_foreign_load_jpeg_init(VipsForeignLoadJpeg *jpeg)
213
75.4k
{
214
75.4k
  jpeg->shrink = 1;
215
75.4k
  jpeg->unlimited = vips_unlimited_get();
216
75.4k
}
217
218
typedef struct _VipsForeignLoadJpegSource {
219
  VipsForeignLoadJpeg parent_object;
220
221
  VipsSource *source;
222
223
} VipsForeignLoadJpegSource;
224
225
typedef VipsForeignLoadJpegClass VipsForeignLoadJpegSourceClass;
226
227
39
G_DEFINE_TYPE(VipsForeignLoadJpegSource, vips_foreign_load_jpeg_source,
228
39
  vips_foreign_load_jpeg_get_type());
229
39
230
39
static int
231
39
vips_foreign_load_jpeg_source_build(VipsObject *object)
232
805
{
233
805
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object;
234
805
  VipsForeignLoadJpegSource *source = (VipsForeignLoadJpegSource *) object;
235
236
805
  if (source->source) {
237
805
    jpeg->source = source->source;
238
805
    g_object_ref(jpeg->source);
239
805
  }
240
241
805
  return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_source_parent_class)
242
805
    ->build(object);
243
805
}
244
245
static gboolean
246
vips_foreign_load_jpeg_source_is_a_source(VipsSource *source)
247
475k
{
248
475k
  return vips__isjpeg_source(source);
249
475k
}
250
251
static void
252
vips_foreign_load_jpeg_source_class_init(
253
  VipsForeignLoadJpegSourceClass *class)
254
19
{
255
19
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
256
19
  VipsObjectClass *object_class = (VipsObjectClass *) class;
257
19
  VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class);
258
19
  VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
259
260
19
  gobject_class->set_property = vips_object_set_property;
261
19
  gobject_class->get_property = vips_object_get_property;
262
263
19
  object_class->nickname = "jpegload_source";
264
19
  object_class->description = _("load image from jpeg source");
265
19
  object_class->build = vips_foreign_load_jpeg_source_build;
266
267
19
  operation_class->flags |= VIPS_OPERATION_NOCACHE;
268
269
19
  load_class->is_a_source = vips_foreign_load_jpeg_source_is_a_source;
270
271
19
  VIPS_ARG_OBJECT(class, "source", 1,
272
19
    _("Source"),
273
19
    _("Source to load from"),
274
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
275
19
    G_STRUCT_OFFSET(VipsForeignLoadJpegSource, source),
276
19
    VIPS_TYPE_SOURCE);
277
19
}
278
279
static void
280
vips_foreign_load_jpeg_source_init(VipsForeignLoadJpegSource *source)
281
873
{
282
873
}
283
284
typedef struct _VipsForeignLoadJpegFile {
285
  VipsForeignLoadJpeg parent_object;
286
287
  char *filename;
288
289
} VipsForeignLoadJpegFile;
290
291
typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass;
292
293
39
G_DEFINE_TYPE(VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file,
294
39
  vips_foreign_load_jpeg_get_type());
295
39
296
39
static int
297
39
vips_foreign_load_jpeg_file_build(VipsObject *object)
298
5.55k
{
299
5.55k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object;
300
5.55k
  VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) object;
301
302
5.55k
  if (file->filename &&
303
5.55k
    !(jpeg->source = vips_source_new_from_file(file->filename)))
304
0
    return -1;
305
306
5.55k
  return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_file_parent_class)
307
5.55k
    ->build(object);
308
5.55k
}
309
310
static gboolean
311
vips_foreign_load_jpeg_file_is_a(const char *filename)
312
38.4k
{
313
38.4k
  VipsSource *source;
314
315
38.4k
  if (!(source = vips_source_new_from_file(filename)))
316
0
    return FALSE;
317
38.4k
  gboolean is_a = vips_foreign_load_jpeg_source_is_a_source(source);
318
38.4k
  VIPS_UNREF(source);
319
320
38.4k
  return is_a;
321
38.4k
}
322
323
static void
324
vips_foreign_load_jpeg_file_class_init(VipsForeignLoadJpegFileClass *class)
325
19
{
326
19
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
327
19
  VipsObjectClass *object_class = (VipsObjectClass *) class;
328
19
  VipsForeignClass *foreign_class = (VipsForeignClass *) class;
329
19
  VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
330
331
19
  gobject_class->set_property = vips_object_set_property;
332
19
  gobject_class->get_property = vips_object_get_property;
333
334
19
  object_class->nickname = "jpegload";
335
19
  object_class->description = _("load jpeg from file");
336
19
  object_class->build = vips_foreign_load_jpeg_file_build;
337
338
19
  foreign_class->suffs = vips__jpeg_suffs;
339
340
19
  load_class->is_a = vips_foreign_load_jpeg_file_is_a;
341
342
19
  VIPS_ARG_STRING(class, "filename", 1,
343
19
    _("Filename"),
344
19
    _("Filename to load from"),
345
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
346
19
    G_STRUCT_OFFSET(VipsForeignLoadJpegFile, filename),
347
19
    NULL);
348
19
}
349
350
static void
351
vips_foreign_load_jpeg_file_init(VipsForeignLoadJpegFile *file)
352
5.55k
{
353
5.55k
}
354
355
typedef struct _VipsForeignLoadJpegBuffer {
356
  VipsForeignLoadJpeg parent_object;
357
358
  VipsBlob *blob;
359
360
} VipsForeignLoadJpegBuffer;
361
362
typedef VipsForeignLoadJpegClass VipsForeignLoadJpegBufferClass;
363
364
39
G_DEFINE_TYPE(VipsForeignLoadJpegBuffer, vips_foreign_load_jpeg_buffer,
365
39
  vips_foreign_load_jpeg_get_type());
366
39
367
39
static int
368
39
vips_foreign_load_jpeg_buffer_build(VipsObject *object)
369
68.9k
{
370
68.9k
  VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object;
371
68.9k
  VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) object;
372
373
68.9k
  if (buffer->blob &&
374
68.9k
    !(jpeg->source = vips_source_new_from_memory(
375
68.9k
        VIPS_AREA(buffer->blob)->data,
376
68.9k
        VIPS_AREA(buffer->blob)->length)))
377
0
    return -1;
378
379
68.9k
  return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_buffer_parent_class)
380
68.9k
    ->build(object);
381
68.9k
}
382
383
static gboolean
384
vips_foreign_load_jpeg_buffer_is_a_buffer(const void *buf, size_t len)
385
424k
{
386
424k
  VipsSource *source;
387
424k
  gboolean result;
388
389
424k
  if (!(source = vips_source_new_from_memory(buf, len)))
390
0
    return FALSE;
391
424k
  result = vips_foreign_load_jpeg_source_is_a_source(source);
392
424k
  VIPS_UNREF(source);
393
394
424k
  return result;
395
424k
}
396
397
static void
398
vips_foreign_load_jpeg_buffer_class_init(
399
  VipsForeignLoadJpegBufferClass *class)
400
19
{
401
19
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
402
19
  VipsObjectClass *object_class = (VipsObjectClass *) class;
403
19
  VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
404
405
19
  gobject_class->set_property = vips_object_set_property;
406
19
  gobject_class->get_property = vips_object_get_property;
407
408
19
  object_class->nickname = "jpegload_buffer";
409
19
  object_class->description = _("load jpeg from buffer");
410
19
  object_class->build = vips_foreign_load_jpeg_buffer_build;
411
412
19
  load_class->is_a_buffer = vips_foreign_load_jpeg_buffer_is_a_buffer;
413
414
19
  VIPS_ARG_BOXED(class, "buffer", 1,
415
19
    _("Buffer"),
416
19
    _("Buffer to load from"),
417
19
    VIPS_ARGUMENT_REQUIRED_INPUT,
418
19
    G_STRUCT_OFFSET(VipsForeignLoadJpegBuffer, blob),
419
19
    VIPS_TYPE_BLOB);
420
19
}
421
422
static void
423
vips_foreign_load_jpeg_buffer_init(VipsForeignLoadJpegBuffer *buffer)
424
69.0k
{
425
69.0k
}
426
427
#endif /*HAVE_JPEG*/
428
429
/**
430
 * vips_jpegload:
431
 * @filename: file to load
432
 * @out: (out): decompressed image
433
 * @...: `NULL`-terminated list of optional named arguments
434
 *
435
 * Read a JPEG file into a VIPS image. It can read most 8-bit JPEG images,
436
 * including CMYK and YCbCr.
437
 *
438
 * @shrink means shrink by this integer factor during load.  Possible values
439
 * are 1, 2, 4 and 8. Shrinking during read is very much faster than
440
 * decompressing the whole image and then shrinking later.
441
 *
442
 * Use @fail_on to set the type of error that will cause load to fail. By
443
 * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE].
444
 *
445
 * Setting @autorotate to `TRUE` will make the loader interpret the
446
 * orientation tag and automatically rotate the image appropriately during
447
 * load.
448
 *
449
 * If @autorotate is `FALSE`, the metadata field [const@META_ORIENTATION] is set
450
 * to the value of the orientation tag. Applications may read and interpret
451
 * this field
452
 * as they wish later in processing. See [method@Image.autorot]. Save
453
 * operations will use [const@META_ORIENTATION], if present, to set the
454
 * orientation of output images.
455
 *
456
 * Example:
457
 *
458
 * ```c
459
 * vips_jpegload("fred.jpg", &out,
460
 *     "shrink", 8,
461
 *     "fail_on", VIPS_FAIL_ON_TRUNCATED,
462
 *     NULL);
463
 * ```
464
 *
465
 * Any embedded ICC profiles are ignored: you always just get the RGB from
466
 * the file. Instead, the embedded profile will be attached to the image as
467
 * [const@META_ICC_NAME]. You need to use something like
468
 * [method@Image.icc_import] to get CIE values from the file.
469
 *
470
 * EXIF metadata is attached as [const@META_EXIF_NAME], IPTC as
471
 * [const@META_IPTC_NAME], and XMP as [const@META_XMP_NAME].
472
 *
473
 * The int metadata item "jpeg-multiscan" is set to the result of
474
 * `jpeg_has_multiple_scans()`. Interlaced jpeg images need a large amount of
475
 * memory to load, so this field gives callers a chance to handle these
476
 * images differently.
477
 *
478
 * The string-valued field "jpeg-chroma-subsample" gives the chroma subsample
479
 * in standard notation. 4:4:4 means no subsample, 4:2:0 means YCbCr with
480
 * Cb and Cr subsampled horizontally and vertically, 4:4:4:4 means a CMYK
481
 * image with no subsampling.
482
 *
483
 * The EXIF thumbnail, if present, is attached to the image as
484
 * "jpeg-thumbnail-data". See [method@Image.get_blob].
485
 *
486
 * ::: tip "Optional arguments"
487
 *     * @shrink: `gint`, shrink by this much on load
488
 *     * @fail_on: [enum@FailOn], types of read error to fail on
489
 *     * @autorotate: `gboolean`, use exif Orientation tag to rotate the image
490
 *       during load
491
 *
492
 * ::: seealso
493
 *     [ctor@Image.jpegload_buffer], [method@Image.autorot].
494
 *
495
 * Returns: 0 on success, -1 on error.
496
 */
497
int
498
vips_jpegload(const char *filename, VipsImage **out, ...)
499
0
{
500
0
  va_list ap;
501
0
  int result;
502
503
0
  va_start(ap, out);
504
0
  result = vips_call_split("jpegload", ap, filename, out);
505
0
  va_end(ap);
506
507
0
  return result;
508
0
}
509
510
/**
511
 * vips_jpegload_buffer:
512
 * @buf: (array length=len) (element-type guint8): memory area to load
513
 * @len: (type gsize): size of memory area
514
 * @out: (out): image to write
515
 * @...: `NULL`-terminated list of optional named arguments
516
 *
517
 * Read a JPEG-formatted memory block into a VIPS image. Exactly as
518
 * [ctor@Image.jpegload], but read from a memory buffer.
519
 *
520
 * You must not free the buffer while @out is active. The
521
 * [signal@Object::postclose] signal on @out is a good place to free.
522
 *
523
 * ::: tip "Optional arguments"
524
 *     * @shrink: `gint`, shrink by this much on load
525
 *     * @fail_on: [enum@FailOn], types of read error to fail on
526
 *     * @autorotate: `gboolean`, use exif Orientation tag to rotate the image
527
 *       during load
528
 *
529
 * ::: seealso
530
 *     [ctor@Image.jpegload].
531
 *
532
 * Returns: 0 on success, -1 on error.
533
 */
534
int
535
vips_jpegload_buffer(void *buf, size_t len, VipsImage **out, ...)
536
377
{
537
377
  va_list ap;
538
377
  VipsBlob *blob;
539
377
  int result;
540
541
  /* We don't take a copy of the data or free it.
542
   */
543
377
  blob = vips_blob_new(NULL, buf, len);
544
545
377
  va_start(ap, out);
546
377
  result = vips_call_split("jpegload_buffer", ap, blob, out);
547
377
  va_end(ap);
548
549
377
  vips_area_unref(VIPS_AREA(blob));
550
551
377
  return result;
552
377
}
553
554
/**
555
 * vips_jpegload_source:
556
 * @source: source to load
557
 * @out: (out): image to write
558
 * @...: `NULL`-terminated list of optional named arguments
559
 *
560
 * Read a JPEG-formatted memory block into a VIPS image. Exactly as
561
 * [ctor@Image.jpegload], but read from a source.
562
 *
563
 * ::: tip "Optional arguments"
564
 *     * @shrink: `gint`, shrink by this much on load
565
 *     * @fail_on: [enum@FailOn], types of read error to fail on
566
 *     * @autorotate: `gboolean`, use exif Orientation tag to rotate the image
567
 *       during load
568
 *
569
 * ::: seealso
570
 *     [ctor@Image.jpegload].
571
 *
572
 * Returns: 0 on success, -1 on error.
573
 */
574
int
575
vips_jpegload_source(VipsSource *source, VipsImage **out, ...)
576
0
{
577
0
  va_list ap;
578
0
  int result;
579
580
0
  va_start(ap, out);
581
0
  result = vips_call_split("jpegload_source", ap, source, out);
582
0
  va_end(ap);
583
584
0
  return result;
585
0
}