2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
29 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4365 6240 6326 6386 6385 28182 28183 6387 6011 6001)
31 namespace jpeglibNamespace
33 #if JUCE_INCLUDE_JPEGLIB_CODE || ! defined (JUCE_INCLUDE_JPEGLIB_CODE)
35 typedef unsigned char boolean
;
38 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion",
39 "-Wdeprecated-register",
40 "-Wdeprecated-declarations",
45 "-Wimplicit-fallthrough",
46 "-Wzero-as-null-pointer-constant",
47 "-Wshift-negative-value",
50 #define JPEG_INTERNALS
52 #include "jpglib/jpeglib.h"
54 #include "jpglib/jcapimin.c"
55 #include "jpglib/jcapistd.c"
56 #include "jpglib/jccoefct.c"
57 #include "jpglib/jccolor.c"
59 #include "jpglib/jcdctmgr.c"
61 #include "jpglib/jchuff.c"
63 #include "jpglib/jcinit.c"
64 #include "jpglib/jcmainct.c"
65 #include "jpglib/jcmarker.c"
66 #include "jpglib/jcmaster.c"
67 #include "jpglib/jcomapi.c"
68 #include "jpglib/jcparam.c"
69 #include "jpglib/jcphuff.c"
70 #include "jpglib/jcprepct.c"
71 #include "jpglib/jcsample.c"
72 #include "jpglib/jctrans.c"
73 #include "jpglib/jdapistd.c"
74 #include "jpglib/jdapimin.c"
75 #include "jpglib/jdatasrc.c"
76 #include "jpglib/jdcoefct.c"
78 #include "jpglib/jdcolor.c"
80 #include "jpglib/jddctmgr.c"
83 #include "jpglib/jdhuff.c"
84 #include "jpglib/jdinput.c"
85 #include "jpglib/jdmainct.c"
86 #include "jpglib/jdmarker.c"
87 #include "jpglib/jdmaster.c"
89 #include "jpglib/jdmerge.c"
91 #include "jpglib/jdphuff.c"
92 #include "jpglib/jdpostct.c"
94 #include "jpglib/jdsample.c"
95 #include "jpglib/jdtrans.c"
96 #include "jpglib/jfdctflt.c"
97 #include "jpglib/jfdctint.c"
100 #undef FIX_0_541196100
101 #include "jpglib/jfdctfst.c"
102 #undef FIX_0_541196100
103 #include "jpglib/jidctflt.c"
105 #undef FIX_1_847759065
109 #include "jpglib/jidctfst.c"
111 #undef FIX_1_847759065
114 #include "jpglib/jidctint.c"
115 #include "jpglib/jidctred.c"
116 #include "jpglib/jmemmgr.c"
117 #include "jpglib/jmemnobs.c"
118 #include "jpglib/jquant1.c"
119 #include "jpglib/jquant2.c"
120 #include "jpglib/jutils.c"
121 #include "jpglib/transupp.c"
123 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
125 #define JPEG_INTERNALS
134 JUCE_END_IGNORE_WARNINGS_MSVC
136 //==============================================================================
137 namespace JPEGHelpers
139 using namespace jpeglibNamespace
;
141 #if ! (JUCE_WINDOWS && (JUCE_MSVC || JUCE_CLANG))
142 using jpeglibNamespace::boolean
;
145 static void fatalErrorHandler (j_common_ptr p
) { *((bool*) (p
->client_data
)) = true; }
146 static void silentErrorCallback1 (j_common_ptr
) {}
147 static void silentErrorCallback2 (j_common_ptr
, int) {}
148 static void silentErrorCallback3 (j_common_ptr
, char*) {}
150 static void setupSilentErrorHandler (struct jpeg_error_mgr
& err
)
154 err
.error_exit
= fatalErrorHandler
;
155 err
.emit_message
= silentErrorCallback2
;
156 err
.output_message
= silentErrorCallback1
;
157 err
.format_message
= silentErrorCallback3
;
158 err
.reset_error_mgr
= silentErrorCallback1
;
161 //==============================================================================
162 #if ! JUCE_USING_COREIMAGE_LOADER
163 static void dummyCallback1 (j_decompress_ptr
) {}
165 static void jpegSkip (j_decompress_ptr decompStruct
, long num
)
167 decompStruct
->src
->next_input_byte
+= num
;
169 num
= jmin (num
, (long) decompStruct
->src
->bytes_in_buffer
);
170 decompStruct
->src
->bytes_in_buffer
-= (size_t) num
;
173 static boolean
jpegFill (j_decompress_ptr
)
179 //==============================================================================
180 const int jpegBufferSize
= 512;
182 struct JuceJpegDest
: public jpeg_destination_mgr
184 OutputStream
* output
;
188 static void jpegWriteInit (j_compress_ptr
) {}
190 static void jpegWriteTerminate (j_compress_ptr cinfo
)
192 JuceJpegDest
* const dest
= static_cast<JuceJpegDest
*> (cinfo
->dest
);
194 const size_t numToWrite
= jpegBufferSize
- dest
->free_in_buffer
;
195 dest
->output
->write (dest
->buffer
, numToWrite
);
198 static boolean
jpegWriteFlush (j_compress_ptr cinfo
)
200 JuceJpegDest
* const dest
= static_cast<JuceJpegDest
*> (cinfo
->dest
);
202 const int numToWrite
= jpegBufferSize
;
204 dest
->next_output_byte
= reinterpret_cast<JOCTET
*> (dest
->buffer
);
205 dest
->free_in_buffer
= jpegBufferSize
;
207 return (boolean
) dest
->output
->write (dest
->buffer
, (size_t) numToWrite
);
211 //==============================================================================
212 JPEGImageFormat::JPEGImageFormat()
217 JPEGImageFormat::~JPEGImageFormat() {}
219 void JPEGImageFormat::setQuality (const float newQuality
)
221 quality
= newQuality
;
224 String
JPEGImageFormat::getFormatName() { return "JPEG"; }
225 bool JPEGImageFormat::usesFileExtension (const File
& f
) { return f
.hasFileExtension ("jpeg;jpg"); }
227 bool JPEGImageFormat::canUnderstand (InputStream
& in
)
229 const int bytesNeeded
= 24;
230 uint8 header
[bytesNeeded
];
232 if (in
.read (header
, bytesNeeded
) == bytesNeeded
235 && header
[2] == 0xff)
238 #if JUCE_USING_COREIMAGE_LOADER
239 return header
[20] == 'j'
242 && header
[23] == ' ';
248 #if JUCE_USING_COREIMAGE_LOADER
249 Image
juce_loadWithCoreImage (InputStream
& input
);
252 Image
JPEGImageFormat::decodeImage (InputStream
& in
)
254 #if JUCE_USING_COREIMAGE_LOADER
255 return juce_loadWithCoreImage (in
);
257 using namespace jpeglibNamespace
;
258 using namespace JPEGHelpers
;
260 MemoryOutputStream mb
;
265 if (mb
.getDataSize() > 16)
267 struct jpeg_decompress_struct jpegDecompStruct
;
269 struct jpeg_error_mgr jerr
;
270 setupSilentErrorHandler (jerr
);
271 jpegDecompStruct
.err
= &jerr
;
273 jpeg_create_decompress (&jpegDecompStruct
);
275 jpegDecompStruct
.src
= (jpeg_source_mgr
*)(jpegDecompStruct
.mem
->alloc_small
)
276 ((j_common_ptr
)(&jpegDecompStruct
), JPOOL_PERMANENT
, sizeof (jpeg_source_mgr
));
278 bool hasFailed
= false;
279 jpegDecompStruct
.client_data
= &hasFailed
;
281 jpegDecompStruct
.src
->init_source
= dummyCallback1
;
282 jpegDecompStruct
.src
->fill_input_buffer
= jpegFill
;
283 jpegDecompStruct
.src
->skip_input_data
= jpegSkip
;
284 jpegDecompStruct
.src
->resync_to_restart
= jpeg_resync_to_restart
;
285 jpegDecompStruct
.src
->term_source
= dummyCallback1
;
287 jpegDecompStruct
.src
->next_input_byte
= static_cast<const unsigned char*> (mb
.getData());
288 jpegDecompStruct
.src
->bytes_in_buffer
= mb
.getDataSize();
290 jpeg_read_header (&jpegDecompStruct
, TRUE
);
294 jpeg_calc_output_dimensions (&jpegDecompStruct
);
298 const int width
= (int) jpegDecompStruct
.output_width
;
299 const int height
= (int) jpegDecompStruct
.output_height
;
301 jpegDecompStruct
.out_color_space
= JCS_RGB
;
304 = (*jpegDecompStruct
.mem
->alloc_sarray
) ((j_common_ptr
) &jpegDecompStruct
,
306 (JDIMENSION
) width
* 3, 1);
308 if (jpeg_start_decompress (&jpegDecompStruct
) && ! hasFailed
)
310 image
= Image (Image::RGB
, width
, height
, false);
311 image
.getProperties()->set ("originalImageHadAlpha", false);
312 const bool hasAlphaChan
= image
.hasAlphaChannel(); // (the native image creator may not give back what we expect)
314 const Image::BitmapData
destData (image
, Image::BitmapData::writeOnly
);
316 for (int y
= 0; y
< height
; ++y
)
318 jpeg_read_scanlines (&jpegDecompStruct
, buffer
, 1);
323 const uint8
* src
= *buffer
;
324 uint8
* dest
= destData
.getLinePointer (y
);
328 for (int i
= width
; --i
>= 0;)
330 ((PixelARGB
*) dest
)->setARGB (0xff, src
[0], src
[1], src
[2]);
331 ((PixelARGB
*) dest
)->premultiply();
332 dest
+= destData
.pixelStride
;
338 for (int i
= width
; --i
>= 0;)
340 ((PixelRGB
*) dest
)->setARGB (0xff, src
[0], src
[1], src
[2]);
341 dest
+= destData
.pixelStride
;
348 jpeg_finish_decompress (&jpegDecompStruct
);
350 in
.setPosition (((char*) jpegDecompStruct
.src
->next_input_byte
) - (char*) mb
.getData());
355 jpeg_destroy_decompress (&jpegDecompStruct
);
362 bool JPEGImageFormat::writeImageToStream (const Image
& image
, OutputStream
& out
)
364 using namespace jpeglibNamespace
;
365 using namespace JPEGHelpers
;
367 jpeg_compress_struct jpegCompStruct
;
368 zerostruct (jpegCompStruct
);
369 jpeg_create_compress (&jpegCompStruct
);
371 struct jpeg_error_mgr jerr
;
372 setupSilentErrorHandler (jerr
);
373 jpegCompStruct
.err
= &jerr
;
376 jpegCompStruct
.dest
= &dest
;
379 HeapBlock
<char> tempBuffer (jpegBufferSize
);
380 dest
.buffer
= tempBuffer
;
381 dest
.next_output_byte
= (JOCTET
*) dest
.buffer
;
382 dest
.free_in_buffer
= jpegBufferSize
;
383 dest
.init_destination
= jpegWriteInit
;
384 dest
.empty_output_buffer
= jpegWriteFlush
;
385 dest
.term_destination
= jpegWriteTerminate
;
387 jpegCompStruct
.image_width
= (JDIMENSION
) image
.getWidth();
388 jpegCompStruct
.image_height
= (JDIMENSION
) image
.getHeight();
389 jpegCompStruct
.input_components
= 3;
390 jpegCompStruct
.in_color_space
= JCS_RGB
;
391 jpegCompStruct
.write_JFIF_header
= 1;
393 jpegCompStruct
.X_density
= 72;
394 jpegCompStruct
.Y_density
= 72;
396 jpeg_set_defaults (&jpegCompStruct
);
398 jpegCompStruct
.dct_method
= JDCT_FLOAT
;
399 jpegCompStruct
.optimize_coding
= 1;
404 jpeg_set_quality (&jpegCompStruct
, jlimit (0, 100, roundToInt (quality
* 100.0f
)), TRUE
);
406 jpeg_start_compress (&jpegCompStruct
, TRUE
);
408 const int strideBytes
= (int) (jpegCompStruct
.image_width
* (unsigned int) jpegCompStruct
.input_components
);
410 JSAMPARRAY buffer
= (*jpegCompStruct
.mem
->alloc_sarray
) ((j_common_ptr
) &jpegCompStruct
,
411 JPOOL_IMAGE
, (JDIMENSION
) strideBytes
, 1);
413 const Image::BitmapData
srcData (image
, Image::BitmapData::readOnly
);
415 while (jpegCompStruct
.next_scanline
< jpegCompStruct
.image_height
)
417 uint8
* dst
= *buffer
;
419 if (srcData
.pixelFormat
== Image::RGB
)
421 const uint8
* src
= srcData
.getLinePointer ((int) jpegCompStruct
.next_scanline
);
423 for (int i
= srcData
.width
; --i
>= 0;)
425 *dst
++ = ((const PixelRGB
*) src
)->getRed();
426 *dst
++ = ((const PixelRGB
*) src
)->getGreen();
427 *dst
++ = ((const PixelRGB
*) src
)->getBlue();
428 src
+= srcData
.pixelStride
;
433 for (int x
= 0; x
< srcData
.width
; ++x
)
435 const Colour
pixel (srcData
.getPixelColour (x
, (int) jpegCompStruct
.next_scanline
));
436 *dst
++ = pixel
.getRed();
437 *dst
++ = pixel
.getGreen();
438 *dst
++ = pixel
.getBlue();
442 jpeg_write_scanlines (&jpegCompStruct
, buffer
, 1);
445 jpeg_finish_compress (&jpegCompStruct
);
446 jpeg_destroy_compress (&jpegCompStruct
);