Blender V4.3
jpeg.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* This little block needed for linking to Blender... */
10#include <algorithm>
11#include <csetjmp>
12#include <cstdio>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_fileops.h"
17#include "BLI_listbase.h"
18#include "BLI_string.h"
19#include "BLI_utildefines.h"
20
21#include "BKE_idprop.hh"
22
23#include "DNA_ID.h" /* ID property definitions. */
24
26#include "IMB_filetype.hh"
27#include "IMB_imbuf.hh"
28#include "IMB_imbuf_types.hh"
29#include "IMB_metadata.hh"
30
31#include <cstring>
32#include <jerror.h>
33#include <jpeglib.h>
34
35/* the types are from the jpeg lib */
36static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN;
37static void init_source(j_decompress_ptr cinfo);
38static boolean fill_input_buffer(j_decompress_ptr cinfo);
39static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
40static void term_source(j_decompress_ptr cinfo);
41static void memory_source(j_decompress_ptr cinfo, const uchar *buffer, size_t size);
42static boolean handle_app1(j_decompress_ptr cinfo);
44 jpeg_decompress_struct *cinfo, int flags, int max_size, size_t *r_width, size_t *r_height);
45
46static const uchar jpeg_default_quality = 75;
48
49bool imb_is_a_jpeg(const uchar *mem, const size_t size)
50{
51 const char magic[2] = {0xFF, 0xD8};
52 if (size < sizeof(magic)) {
53 return false;
54 }
55 return memcmp(mem, magic, sizeof(magic)) == 0;
56}
57
58/*----------------------------------------------------------
59 * JPG ERROR HANDLING
60 *---------------------------------------------------------- */
61
63 jpeg_error_mgr pub; /* "public" fields */
64
65 jmp_buf setjmp_buffer; /* for return to caller */
66};
67
69
70static void jpeg_error(j_common_ptr cinfo)
71{
72 my_error_ptr err = (my_error_ptr)cinfo->err;
73
74 /* Always display the message */
75 (*cinfo->err->output_message)(cinfo);
76
77 /* Let the memory manager delete any temp files before we die */
78 jpeg_destroy(cinfo);
79
80 /* return control to the setjmp point */
81 longjmp(err->setjmp_buffer, 1);
82}
83
84/*----------------------------------------------------------
85 * INPUT HANDLER FROM MEMORY
86 *---------------------------------------------------------- */
87
89 jpeg_source_mgr pub; /* public fields */
90
91 const uchar *buffer;
92 int size;
93 JOCTET terminal[2];
94};
95
97
98static void init_source(j_decompress_ptr cinfo)
99{
100 (void)cinfo; /* unused */
101}
102
103static boolean fill_input_buffer(j_decompress_ptr cinfo)
104{
105 my_src_ptr src = (my_src_ptr)cinfo->src;
106
107 /* Since we have given all we have got already
108 * we simply fake an end of file
109 */
110
111 src->pub.next_input_byte = src->terminal;
112 src->pub.bytes_in_buffer = 2;
113 src->terminal[0] = (JOCTET)0xFF;
114 src->terminal[1] = (JOCTET)JPEG_EOI;
115
116 return true;
117}
118
119static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
120{
121 my_src_ptr src = (my_src_ptr)cinfo->src;
122
123 if (num_bytes > 0) {
124 /* prevent skipping over file end */
125 size_t skip_size = size_t(num_bytes) <= src->pub.bytes_in_buffer ? num_bytes :
126 src->pub.bytes_in_buffer;
127
128 src->pub.next_input_byte = src->pub.next_input_byte + skip_size;
129 src->pub.bytes_in_buffer = src->pub.bytes_in_buffer - skip_size;
130 }
131}
132
133static void term_source(j_decompress_ptr cinfo)
134{
135 (void)cinfo; /* unused */
136}
137
138static void memory_source(j_decompress_ptr cinfo, const uchar *buffer, size_t size)
139{
140 my_src_ptr src;
141
142 if (cinfo->src == nullptr) { /* first time for this JPEG object? */
143 cinfo->src = (jpeg_source_mgr *)(*cinfo->mem->alloc_small)(
144 (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
145 }
146
147 src = (my_src_ptr)cinfo->src;
148 src->pub.init_source = init_source;
149 src->pub.fill_input_buffer = fill_input_buffer;
150 src->pub.skip_input_data = skip_input_data;
151 src->pub.resync_to_restart = jpeg_resync_to_restart;
152 src->pub.term_source = term_source;
153
154 src->pub.bytes_in_buffer = size;
155 src->pub.next_input_byte = buffer;
156
157 src->buffer = buffer;
158 src->size = size;
159}
160
161#define MAKESTMT(stuff) \
162 do { \
163 stuff \
164 } while (0)
165
166#define INPUT_VARS(cinfo) \
167 jpeg_source_mgr *datasrc = (cinfo)->src; \
168 const JOCTET *next_input_byte = datasrc->next_input_byte; \
169 size_t bytes_in_buffer = datasrc->bytes_in_buffer
170
171/* Unload the local copies --- do this only at a restart boundary */
172#define INPUT_SYNC(cinfo) \
173 (datasrc->next_input_byte = next_input_byte, datasrc->bytes_in_buffer = bytes_in_buffer)
174
175/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */
176#define INPUT_RELOAD(cinfo) \
177 (next_input_byte = datasrc->next_input_byte, bytes_in_buffer = datasrc->bytes_in_buffer)
178
179/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
180 * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
181 * but we must reload the local copies after a successful fill.
182 */
183#define MAKE_BYTE_AVAIL(cinfo, action) \
184 if (bytes_in_buffer == 0) { \
185 if (!(*datasrc->fill_input_buffer)(cinfo)) { \
186 action; \
187 } \
188 INPUT_RELOAD(cinfo); \
189 } \
190 (void)0
191
192/* Read a byte into variable V.
193 * If must suspend, take the specified action (typically "return false").
194 */
195#define INPUT_BYTE(cinfo, V, action) \
196 MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); bytes_in_buffer--; V = GETJOCTET(*next_input_byte++);)
197
198/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
199 * V should be declared `uint` or perhaps INT32.
200 */
201#define INPUT_2BYTES(cinfo, V, action) \
202 MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); bytes_in_buffer--; \
203 V = uint(GETJOCTET(*next_input_byte++)) << 8; \
204 MAKE_BYTE_AVAIL(cinfo, action); \
205 bytes_in_buffer--; \
206 V += GETJOCTET(*next_input_byte++);)
207
214BLI_STATIC_ASSERT(sizeof(NeoGeo_Word) == 4, "Must be 4 bytes");
215
216static boolean handle_app1(j_decompress_ptr cinfo)
217{
218 INT32 length; /* initialized by the macro */
219 INT32 i;
220 char neogeo[128];
221
222 INPUT_VARS(cinfo);
223
224 INPUT_2BYTES(cinfo, length, return false);
225 length -= 2;
226
227 if (length < 16) {
228 for (i = 0; i < length; i++) {
229 INPUT_BYTE(cinfo, neogeo[i], return false);
230 }
231 length = 0;
232 if (STRPREFIX(neogeo, "NeoGeo")) {
233 NeoGeo_Word *neogeo_word = (NeoGeo_Word *)(neogeo + 6);
234 ibuf_quality = neogeo_word->quality;
235 }
236 }
237 INPUT_SYNC(cinfo); /* do before skip_input_data */
238 if (length > 0) {
239 (*cinfo->src->skip_input_data)(cinfo, length);
240 }
241 return true;
242}
243
245 jpeg_decompress_struct *cinfo, int flags, int max_size, size_t *r_width, size_t *r_height)
246{
247 JSAMPARRAY row_pointer;
248 JSAMPLE *buffer = nullptr;
249 int row_stride;
250 int x, y, depth, r, g, b, k;
251 ImBuf *ibuf = nullptr;
252 uchar *rect;
253 jpeg_saved_marker_ptr marker;
254 char *str, *key, *value;
255
256 /* install own app1 handler */
258 jpeg_set_marker_processor(cinfo, 0xe1, handle_app1);
259 cinfo->dct_method = JDCT_FLOAT;
260 jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
261
262 if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) {
263 depth = cinfo->num_components;
264
265 if (cinfo->jpeg_color_space == JCS_YCCK) {
266 cinfo->out_color_space = JCS_CMYK;
267 }
268
269 if (r_width) {
270 *r_width = cinfo->image_width;
271 }
272 if (r_height) {
273 *r_height = cinfo->image_height;
274 }
275
276 if (max_size > 0) {
277 /* `libjpeg` can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
278 * while `libjpeg-turbo` can also do 3/8, 5/8, etc. But max is 1/8. */
279 float scale = float(max_size) / std::max(cinfo->image_width, cinfo->image_height);
280 cinfo->scale_denom = 8;
281 cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * float(cinfo->scale_denom))));
282 cinfo->dct_method = JDCT_FASTEST;
283 cinfo->dither_mode = JDITHER_ORDERED;
284 }
285
286 jpeg_start_decompress(cinfo);
287
288 x = cinfo->output_width;
289 y = cinfo->output_height;
290
291 if (flags & IB_test) {
292 jpeg_abort_decompress(cinfo);
293 ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
294 }
295 else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect | IB_uninitialized_pixels)) ==
296 nullptr)
297 {
298 jpeg_abort_decompress(cinfo);
299 }
300 else {
301 row_stride = cinfo->output_width * depth;
302
303 row_pointer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
304
305 for (y = ibuf->y - 1; y >= 0; y--) {
306 jpeg_read_scanlines(cinfo, row_pointer, 1);
307 rect = ibuf->byte_buffer.data + 4 * y * size_t(ibuf->x);
308 buffer = row_pointer[0];
309
310 switch (depth) {
311 case 1:
312 for (x = ibuf->x; x > 0; x--) {
313 rect[3] = 255;
314 rect[0] = rect[1] = rect[2] = *buffer++;
315 rect += 4;
316 }
317 break;
318 case 3:
319 for (x = ibuf->x; x > 0; x--) {
320 rect[3] = 255;
321 rect[0] = *buffer++;
322 rect[1] = *buffer++;
323 rect[2] = *buffer++;
324 rect += 4;
325 }
326 break;
327 case 4:
328 for (x = ibuf->x; x > 0; x--) {
329 r = *buffer++;
330 g = *buffer++;
331 b = *buffer++;
332 k = *buffer++;
333
334 r = (r * k) / 255;
335 g = (g * k) / 255;
336 b = (b * k) / 255;
337
338 rect[3] = 255;
339 rect[2] = b;
340 rect[1] = g;
341 rect[0] = r;
342 rect += 4;
343 }
344 break;
345 }
346 }
347
348 marker = cinfo->marker_list;
349 while (marker) {
350 if (marker->marker != JPEG_COM) {
351 goto next_stamp_marker;
352 }
353
354 /*
355 * JPEG marker strings are not meant to be null-terminated,
356 * create a null-terminated copy before going further.
357 *
358 * Files saved from Blender pre v4.0 were null terminated,
359 * use `BLI_strnlen` to prevent assertion on passing in too short a string. */
360 str = BLI_strdupn((const char *)marker->data,
361 BLI_strnlen((const char *)marker->data, marker->data_length));
362
363 /*
364 * Because JPEG format don't support the
365 * pair "key/value" like PNG, we store the
366 * stamp-info in a single "encode" string:
367 * "Blender:key:value"
368 *
369 * That is why we need split it to the
370 * common key/value here.
371 */
372 if (!STRPREFIX(str, "Blender")) {
373 /*
374 * Maybe the file have text that
375 * we don't know "what it's", in that
376 * case we keep the text (with a
377 * key "None").
378 * This is only for don't "lose"
379 * the information when we write
380 * it back to disk.
381 */
383 IMB_metadata_set_field(ibuf->metadata, "None", str);
384 ibuf->flags |= IB_metadata;
385 MEM_freeN(str);
386 goto next_stamp_marker;
387 }
388
389 key = strchr(str, ':');
390 /*
391 * A little paranoid, but the file maybe
392 * is broken... and a "extra" check is better
393 * then segfault ;)
394 */
395 if (!key) {
396 MEM_freeN(str);
397 goto next_stamp_marker;
398 }
399
400 key++;
401 value = strchr(key, ':');
402 if (!value) {
403 MEM_freeN(str);
404 goto next_stamp_marker;
405 }
406
407 *value = '\0'; /* need finish the key string */
408 value++;
410 IMB_metadata_set_field(ibuf->metadata, key, value);
411 ibuf->flags |= IB_metadata;
412 MEM_freeN(str);
413 next_stamp_marker:
414 marker = marker->next;
415 }
416
417 jpeg_finish_decompress(cinfo);
418 }
419
420 if (ibuf) {
421 /* Density_unit may be 0 for unknown, 1 for dots/inch, or 2 for dots/cm. */
422 if (cinfo->density_unit == 1) {
423 /* Convert inches to meters. */
424 ibuf->ppm[0] = double(cinfo->X_density) / 0.0254;
425 ibuf->ppm[1] = double(cinfo->Y_density) / 0.0254;
426 }
427 else if (cinfo->density_unit == 2) {
428 ibuf->ppm[0] = double(cinfo->X_density) * 100.0;
429 ibuf->ppm[1] = double(cinfo->Y_density) * 100.0;
430 }
431
432 ibuf->ftype = IMB_FTYPE_JPG;
433 ibuf->foptions.quality = std::min<char>(ibuf_quality, 100);
434 }
435 jpeg_destroy((j_common_ptr)cinfo);
436 }
437
438 return ibuf;
439}
440
441ImBuf *imb_load_jpeg(const uchar *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE])
442{
443 jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
444 my_error_mgr jerr;
445 ImBuf *ibuf;
446
447 if (!imb_is_a_jpeg(buffer, size)) {
448 return nullptr;
449 }
450
452
453 cinfo->err = jpeg_std_error(&jerr.pub);
454 jerr.pub.error_exit = jpeg_error;
455
456 /* Establish the setjmp return context for my_error_exit to use. */
457 if (setjmp(jerr.setjmp_buffer)) {
458 /* If we get here, the JPEG code has signaled an error.
459 * We need to clean up the JPEG object, close the input file, and return.
460 */
461 jpeg_destroy_decompress(cinfo);
462 return nullptr;
463 }
464
465 jpeg_create_decompress(cinfo);
466 memory_source(cinfo, buffer, size);
467
468 ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, nullptr, nullptr);
469
470 return ibuf;
471}
472
473/* Defines for JPEG Header markers and segment size. */
474#define JPEG_MARKER_MSB (0xFF)
475#define JPEG_MARKER_SOI (0xD8)
476#define JPEG_MARKER_APP1 (0xE1)
477#define JPEG_APP1_MAX (1 << 16)
478
479ImBuf *imb_thumbnail_jpeg(const char *filepath,
480 const int flags,
481 const size_t max_thumb_size,
482 char colorspace[IM_MAX_SPACE],
483 size_t *r_width,
484 size_t *r_height)
485{
486 jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
487 my_error_mgr jerr;
488 FILE *infile = nullptr;
489
491
492 cinfo->err = jpeg_std_error(&jerr.pub);
493 jerr.pub.error_exit = jpeg_error;
494
495 /* Establish the setjmp return context for my_error_exit to use. */
496 if (setjmp(jerr.setjmp_buffer)) {
497 /* If we get here, the JPEG code has signaled an error.
498 * We need to clean up the JPEG object, close the input file, and return.
499 */
500 jpeg_destroy_decompress(cinfo);
501 return nullptr;
502 }
503
504 if ((infile = BLI_fopen(filepath, "rb")) == nullptr) {
505 fprintf(stderr, "can't open %s\n", filepath);
506 return nullptr;
507 }
508
509 /* If file contains an embedded thumbnail, let's return that instead. */
510
511 if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) &&
512 (fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1))
513 {
514 /* This is a JPEG in EXIF format (SOI + APP1), not JFIF (SOI + APP0). */
516 /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
517 while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
518 !feof(infile) && i--)
519 {
520 }
521 if (i > 0 && !feof(infile)) {
522 /* We found a JPEG thumbnail inside this image. */
523 ImBuf *ibuf = nullptr;
524 uchar *buffer = static_cast<uchar *>(MEM_callocN(JPEG_APP1_MAX, "thumbbuffer"));
525 /* Just put SOI directly in buffer rather than seeking back 2 bytes. */
526 buffer[0] = JPEG_MARKER_MSB;
527 buffer[1] = JPEG_MARKER_SOI;
528 if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) {
529 ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace);
530 }
531 MEM_SAFE_FREE(buffer);
532 if (ibuf) {
533 fclose(infile);
534 return ibuf;
535 }
536 }
537 }
538
539 /* No embedded thumbnail found, so let's create a new one. */
540
541 fseek(infile, 0, SEEK_SET);
542 jpeg_create_decompress(cinfo);
543
544 jpeg_stdio_src(cinfo, infile);
545 ImBuf *ibuf = ibJpegImageFromCinfo(cinfo, flags, max_thumb_size, r_width, r_height);
546 fclose(infile);
547
548 return ibuf;
549}
550
551#undef JPEG_MARKER_MSB
552#undef JPEG_MARKER_SOI
553#undef JPEG_MARKER_APP1
554#undef JPEG_APP1_MAX
555
556static void write_jpeg(jpeg_compress_struct *cinfo, ImBuf *ibuf)
557{
558 JSAMPLE *buffer = nullptr;
559 JSAMPROW row_pointer[1];
560 uchar *rect;
561 int x, y;
562 char neogeo[128];
563 NeoGeo_Word *neogeo_word;
564
565 jpeg_start_compress(cinfo, true);
566
567 STRNCPY(neogeo, "NeoGeo");
568 neogeo_word = (NeoGeo_Word *)(neogeo + 6);
569 memset(neogeo_word, 0, sizeof(*neogeo_word));
570 neogeo_word->quality = ibuf->foptions.quality;
571 jpeg_write_marker(cinfo, 0xe1, (JOCTET *)neogeo, 10);
572 if (ibuf->metadata) {
573
574 /* Static storage array for the short metadata. */
575 char static_text[1024];
576 const int static_text_size = ARRAY_SIZE(static_text);
577 LISTBASE_FOREACH (IDProperty *, prop, &ibuf->metadata->data.group) {
578 if (prop->type == IDP_STRING) {
579 int text_len;
580 if (STREQ(prop->name, "None")) {
581 jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *)IDP_String(prop), prop->len);
582 }
583
584 char *text = static_text;
585 int text_size = static_text_size;
586 /* 7 is for Blender, 2 colon separators, length of property
587 * name and property value, followed by the nullptr-terminator
588 * which isn't needed by JPEG but #BLI_snprintf_rlen requires it. */
589 const int text_length_required = 7 + 2 + strlen(prop->name) + strlen(IDP_String(prop)) + 1;
590 if (text_length_required <= static_text_size) {
591 text = static_cast<char *>(MEM_mallocN(text_length_required, "jpeg metadata field"));
592 text_size = text_length_required;
593 }
594
595 /*
596 * The JPEG format don't support a pair "key/value"
597 * like PNG, so we "encode" the stamp in a
598 * single string:
599 * "Blender:key:value"
600 *
601 * The first "Blender" is a simple identify to help
602 * in the read process.
603 */
604 text_len = BLI_snprintf_rlen(
605 text, text_size, "Blender:%s:%s", prop->name, IDP_String(prop));
606 /* Don't write the null byte (not expected by the JPEG format). */
607 jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *)text, text_len);
608
609 /* TODO(sergey): Ideally we will try to re-use allocation as
610 * much as possible. In practice, such long fields don't happen
611 * often. */
612 if (text != static_text) {
613 MEM_freeN(text);
614 }
615 }
616 }
617 }
618
619 row_pointer[0] = static_cast<JSAMPROW>(MEM_mallocN(
620 sizeof(JSAMPLE) * cinfo->input_components * cinfo->image_width, "jpeg row_pointer"));
621
622 for (y = ibuf->y - 1; y >= 0; y--) {
623 rect = ibuf->byte_buffer.data + 4 * y * size_t(ibuf->x);
624 buffer = row_pointer[0];
625
626 switch (cinfo->in_color_space) {
627 case JCS_RGB:
628 for (x = 0; x < ibuf->x; x++) {
629 *buffer++ = rect[0];
630 *buffer++ = rect[1];
631 *buffer++ = rect[2];
632 rect += 4;
633 }
634 break;
635 case JCS_GRAYSCALE:
636 for (x = 0; x < ibuf->x; x++) {
637 *buffer++ = rect[0];
638 rect += 4;
639 }
640 break;
641 case JCS_UNKNOWN:
642 memcpy(buffer, rect, 4 * ibuf->x);
643 break;
644 /* default was missing... intentional ? */
645 default:
646 /* do nothing */
647 break;
648 }
649
650 jpeg_write_scanlines(cinfo, row_pointer, 1);
651 }
652
653 jpeg_finish_compress(cinfo);
654 MEM_freeN(row_pointer[0]);
655}
656
657static int init_jpeg(FILE *outfile, jpeg_compress_struct *cinfo, ImBuf *ibuf)
658{
659 int quality;
660
661 quality = ibuf->foptions.quality;
662 if (quality <= 0) {
663 quality = jpeg_default_quality;
664 }
665 if (quality > 100) {
666 quality = 100;
667 }
668
669 jpeg_create_compress(cinfo);
670 jpeg_stdio_dest(cinfo, outfile);
671
672 cinfo->image_width = ibuf->x;
673 cinfo->image_height = ibuf->y;
674
675 cinfo->in_color_space = JCS_RGB;
676 if (ibuf->planes == 8) {
677 cinfo->in_color_space = JCS_GRAYSCALE;
678 }
679#if 0
680 /* just write RGBA as RGB,
681 * unsupported feature only confuses other s/w */
682
683 if (ibuf->planes == 32) {
684 cinfo->in_color_space = JCS_UNKNOWN;
685 }
686#endif
687 switch (cinfo->in_color_space) {
688 case JCS_RGB:
689 cinfo->input_components = 3;
690 break;
691 case JCS_GRAYSCALE:
692 cinfo->input_components = 1;
693 break;
694 case JCS_UNKNOWN:
695 cinfo->input_components = 4;
696 break;
697 /* default was missing... intentional ? */
698 default:
699 /* do nothing */
700 break;
701 }
702 jpeg_set_defaults(cinfo);
703
704 /* own settings */
705
706 cinfo->dct_method = JDCT_FLOAT;
707 jpeg_set_quality(cinfo, quality, true);
708
709 return 0;
710}
711
712static bool save_stdjpeg(const char *filepath, ImBuf *ibuf)
713{
714 FILE *outfile;
715 jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
716 my_error_mgr jerr;
717
718 if ((outfile = BLI_fopen(filepath, "wb")) == nullptr) {
719 return false;
720 }
721
722 cinfo->err = jpeg_std_error(&jerr.pub);
723 jerr.pub.error_exit = jpeg_error;
724
725 /* Establish the setjmp return context for jpeg_error to use. */
726 if (setjmp(jerr.setjmp_buffer)) {
727 /* If we get here, the JPEG code has signaled an error.
728 * We need to clean up the JPEG object, close the input file, and return.
729 */
730 jpeg_destroy_compress(cinfo);
731 fclose(outfile);
732 remove(filepath);
733 return false;
734 }
735
736 init_jpeg(outfile, cinfo, ibuf);
737
738 write_jpeg(cinfo, ibuf);
739
740 fclose(outfile);
741 jpeg_destroy_compress(cinfo);
742
743 return true;
744}
745
746bool imb_savejpeg(ImBuf *ibuf, const char *filepath, int flags)
747{
748
749 ibuf->flags = flags;
750 return save_stdjpeg(filepath, ibuf);
751}
#define IDP_String(prop)
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define ATTR_NORETURN
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LISTBASE_FOREACH(type, var, list)
MINLINE uint min_uu(uint a, uint b)
MINLINE uint max_uu(uint a, uint b)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
int char char int int int int size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:909
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define STRPREFIX(a, b)
#define ARRAY_SIZE(arr)
#define STREQ(a, b)
typedef double(DMatrix)[4][4]
ID and Library types, which are fundamental for SDNA.
@ IDP_STRING
@ COLOR_ROLE_DEFAULT_BYTE
#define IM_MAX_SPACE
Definition IMB_imbuf.hh:49
@ IMB_FTYPE_JPG
Contains defines and structs used throughout the imbuf module.
@ IB_uninitialized_pixels
@ IB_metadata
@ IB_test
@ IB_rect
void IMB_metadata_set_field(IDProperty *metadata, const char *key, const char *value)
Definition metadata.cc:69
void IMB_metadata_ensure(IDProperty **metadata)
Definition metadata.cc:24
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
void colorspace_set_default_role(char *colorspace, int size, int role)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
#define str(s)
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
#define JPEG_MARKER_APP1
Definition jpeg.cc:476
#define INPUT_BYTE(cinfo, V, action)
Definition jpeg.cc:195
static const uchar jpeg_default_quality
Definition jpeg.cc:46
bool imb_is_a_jpeg(const uchar *mem, const size_t size)
Definition jpeg.cc:49
static void memory_source(j_decompress_ptr cinfo, const uchar *buffer, size_t size)
Definition jpeg.cc:138
#define JPEG_MARKER_MSB
Definition jpeg.cc:474
my_source_mgr * my_src_ptr
Definition jpeg.cc:96
bool imb_savejpeg(ImBuf *ibuf, const char *filepath, int flags)
Definition jpeg.cc:746
#define JPEG_MARKER_SOI
Definition jpeg.cc:475
#define INPUT_2BYTES(cinfo, V, action)
Definition jpeg.cc:201
#define INPUT_VARS(cinfo)
Definition jpeg.cc:166
static int init_jpeg(FILE *outfile, jpeg_compress_struct *cinfo, ImBuf *ibuf)
Definition jpeg.cc:657
static ImBuf * ibJpegImageFromCinfo(jpeg_decompress_struct *cinfo, int flags, int max_size, size_t *r_width, size_t *r_height)
Definition jpeg.cc:244
static void term_source(j_decompress_ptr cinfo)
Definition jpeg.cc:133
ImBuf * imb_thumbnail_jpeg(const char *filepath, const int flags, const size_t max_thumb_size, char colorspace[IM_MAX_SPACE], size_t *r_width, size_t *r_height)
Definition jpeg.cc:479
static uchar ibuf_quality
Definition jpeg.cc:47
static boolean handle_app1(j_decompress_ptr cinfo)
Definition jpeg.cc:216
#define INPUT_SYNC(cinfo)
Definition jpeg.cc:172
my_error_mgr * my_error_ptr
Definition jpeg.cc:68
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
Definition jpeg.cc:119
ImBuf * imb_load_jpeg(const uchar *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE])
Definition jpeg.cc:441
static void init_source(j_decompress_ptr cinfo)
Definition jpeg.cc:98
static void write_jpeg(jpeg_compress_struct *cinfo, ImBuf *ibuf)
Definition jpeg.cc:556
static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN
Definition jpeg.cc:70
static boolean fill_input_buffer(j_decompress_ptr cinfo)
Definition jpeg.cc:103
#define JPEG_APP1_MAX
Definition jpeg.cc:477
static bool save_stdjpeg(const char *filepath, ImBuf *ibuf)
Definition jpeg.cc:712
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ListBase group
Definition DNA_ID.h:146
IDPropertyData data
Definition DNA_ID.h:168
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
IDProperty * metadata
double ppm[2]
uchar pad2
Definition jpeg.cc:210
uchar pad1
Definition jpeg.cc:209
uchar pad3
Definition jpeg.cc:211
uchar quality
Definition jpeg.cc:212
jmp_buf setjmp_buffer
Definition jpeg.cc:65
jpeg_error_mgr pub
Definition jpeg.cc:63
const uchar * buffer
Definition jpeg.cc:91
jpeg_source_mgr pub
Definition jpeg.cc:89
JOCTET terminal[2]
Definition jpeg.cc:93
static int magic(const Tex *tex, const float texvec[3], TexResult *texres)