Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_JPEGLoader.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4365 6240 6326 6386 6385 28182 28183 6387 6011 6001)
  21. namespace jpeglibNamespace
  22. {
  23. #if JUCE_INCLUDE_JPEGLIB_CODE || ! defined (JUCE_INCLUDE_JPEGLIB_CODE)
  24. #if JUCE_MINGW
  25. typedef unsigned char boolean;
  26. #endif
  27. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion",
  28. "-Wdeprecated-register",
  29. "-Wdeprecated-declarations",
  30. "-Wsign-conversion",
  31. "-Wcast-align",
  32. "-Wswitch-enum",
  33. "-Wswitch-default",
  34. "-Wimplicit-fallthrough",
  35. "-Wzero-as-null-pointer-constant",
  36. "-Wshift-negative-value",
  37. "-Wcomma")
  38. #define JPEG_INTERNALS
  39. #undef FAR
  40. #include "jpglib/jpeglib.h"
  41. #include "jpglib/jcapimin.c"
  42. #include "jpglib/jcapistd.c"
  43. #include "jpglib/jccoefct.c"
  44. #include "jpglib/jccolor.c"
  45. #undef FIX
  46. #include "jpglib/jcdctmgr.c"
  47. #undef CONST_BITS
  48. #include "jpglib/jchuff.c"
  49. #undef emit_byte
  50. #include "jpglib/jcinit.c"
  51. #include "jpglib/jcmainct.c"
  52. #include "jpglib/jcmarker.c"
  53. #include "jpglib/jcmaster.c"
  54. #include "jpglib/jcomapi.c"
  55. #include "jpglib/jcparam.c"
  56. #include "jpglib/jcphuff.c"
  57. #include "jpglib/jcprepct.c"
  58. #include "jpglib/jcsample.c"
  59. #include "jpglib/jctrans.c"
  60. #include "jpglib/jdapistd.c"
  61. #include "jpglib/jdapimin.c"
  62. #include "jpglib/jdatasrc.c"
  63. #include "jpglib/jdcoefct.c"
  64. #undef FIX
  65. #include "jpglib/jdcolor.c"
  66. #undef FIX
  67. #include "jpglib/jddctmgr.c"
  68. #undef CONST_BITS
  69. #undef ASSIGN_STATE
  70. #include "jpglib/jdhuff.c"
  71. #include "jpglib/jdinput.c"
  72. #include "jpglib/jdmainct.c"
  73. #include "jpglib/jdmarker.c"
  74. #include "jpglib/jdmaster.c"
  75. #undef FIX
  76. #include "jpglib/jdmerge.c"
  77. #undef ASSIGN_STATE
  78. #include "jpglib/jdphuff.c"
  79. #include "jpglib/jdpostct.c"
  80. #undef FIX
  81. #include "jpglib/jdsample.c"
  82. #include "jpglib/jdtrans.c"
  83. #include "jpglib/jfdctflt.c"
  84. #include "jpglib/jfdctint.c"
  85. #undef CONST_BITS
  86. #undef MULTIPLY
  87. #undef FIX_0_541196100
  88. #include "jpglib/jfdctfst.c"
  89. #undef FIX_0_541196100
  90. #include "jpglib/jidctflt.c"
  91. #undef CONST_BITS
  92. #undef FIX_1_847759065
  93. #undef MULTIPLY
  94. #undef DEQUANTIZE
  95. #undef DESCALE
  96. #include "jpglib/jidctfst.c"
  97. #undef CONST_BITS
  98. #undef FIX_1_847759065
  99. #undef MULTIPLY
  100. #undef DEQUANTIZE
  101. #include "jpglib/jidctint.c"
  102. #include "jpglib/jidctred.c"
  103. #include "jpglib/jmemmgr.c"
  104. #include "jpglib/jmemnobs.c"
  105. #include "jpglib/jquant1.c"
  106. #include "jpglib/jquant2.c"
  107. #include "jpglib/jutils.c"
  108. #include "jpglib/transupp.c"
  109. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  110. #else
  111. #define JPEG_INTERNALS
  112. #undef FAR
  113. #include <jpeglib.h>
  114. #endif
  115. }
  116. #undef max
  117. #undef min
  118. JUCE_END_IGNORE_WARNINGS_MSVC
  119. //==============================================================================
  120. namespace JPEGHelpers
  121. {
  122. using namespace jpeglibNamespace;
  123. #if ! (JUCE_WINDOWS && (JUCE_MSVC || JUCE_CLANG))
  124. using jpeglibNamespace::boolean;
  125. #endif
  126. static void fatalErrorHandler (j_common_ptr p) { *((bool*) (p->client_data)) = true; }
  127. static void silentErrorCallback1 (j_common_ptr) {}
  128. static void silentErrorCallback2 (j_common_ptr, int) {}
  129. static void silentErrorCallback3 (j_common_ptr, char*) {}
  130. static void setupSilentErrorHandler (struct jpeg_error_mgr& err)
  131. {
  132. zerostruct (err);
  133. err.error_exit = fatalErrorHandler;
  134. err.emit_message = silentErrorCallback2;
  135. err.output_message = silentErrorCallback1;
  136. err.format_message = silentErrorCallback3;
  137. err.reset_error_mgr = silentErrorCallback1;
  138. }
  139. //==============================================================================
  140. #if ! JUCE_USING_COREIMAGE_LOADER
  141. static void dummyCallback1 (j_decompress_ptr) {}
  142. static void jpegSkip (j_decompress_ptr decompStruct, long num)
  143. {
  144. decompStruct->src->next_input_byte += num;
  145. num = jmin (num, (long) decompStruct->src->bytes_in_buffer);
  146. decompStruct->src->bytes_in_buffer -= (size_t) num;
  147. }
  148. static boolean jpegFill (j_decompress_ptr)
  149. {
  150. return 0;
  151. }
  152. #endif
  153. //==============================================================================
  154. const int jpegBufferSize = 512;
  155. struct JuceJpegDest : public jpeg_destination_mgr
  156. {
  157. OutputStream* output;
  158. char* buffer;
  159. };
  160. static void jpegWriteInit (j_compress_ptr) {}
  161. static void jpegWriteTerminate (j_compress_ptr cinfo)
  162. {
  163. JuceJpegDest* const dest = static_cast<JuceJpegDest*> (cinfo->dest);
  164. const size_t numToWrite = jpegBufferSize - dest->free_in_buffer;
  165. dest->output->write (dest->buffer, numToWrite);
  166. }
  167. static boolean jpegWriteFlush (j_compress_ptr cinfo)
  168. {
  169. JuceJpegDest* const dest = static_cast<JuceJpegDest*> (cinfo->dest);
  170. const int numToWrite = jpegBufferSize;
  171. dest->next_output_byte = reinterpret_cast<JOCTET*> (dest->buffer);
  172. dest->free_in_buffer = jpegBufferSize;
  173. return (boolean) dest->output->write (dest->buffer, (size_t) numToWrite);
  174. }
  175. }
  176. //==============================================================================
  177. JPEGImageFormat::JPEGImageFormat()
  178. : quality (-1.0f)
  179. {
  180. }
  181. JPEGImageFormat::~JPEGImageFormat() {}
  182. void JPEGImageFormat::setQuality (const float newQuality)
  183. {
  184. quality = newQuality;
  185. }
  186. String JPEGImageFormat::getFormatName() { return "JPEG"; }
  187. bool JPEGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("jpeg;jpg"); }
  188. bool JPEGImageFormat::canUnderstand (InputStream& in)
  189. {
  190. const int bytesNeeded = 24;
  191. uint8 header [bytesNeeded];
  192. if (in.read (header, bytesNeeded) == bytesNeeded
  193. && header[0] == 0xff
  194. && header[1] == 0xd8
  195. && header[2] == 0xff)
  196. return true;
  197. #if JUCE_USING_COREIMAGE_LOADER
  198. return header[20] == 'j'
  199. && header[21] == 'p'
  200. && header[22] == '2'
  201. && header[23] == ' ';
  202. #endif
  203. return false;
  204. }
  205. #if JUCE_USING_COREIMAGE_LOADER
  206. Image juce_loadWithCoreImage (InputStream& input);
  207. #endif
  208. Image JPEGImageFormat::decodeImage (InputStream& in)
  209. {
  210. #if JUCE_USING_COREIMAGE_LOADER
  211. return juce_loadWithCoreImage (in);
  212. #else
  213. using namespace jpeglibNamespace;
  214. using namespace JPEGHelpers;
  215. MemoryOutputStream mb;
  216. mb << in;
  217. Image image;
  218. if (mb.getDataSize() > 16)
  219. {
  220. struct jpeg_decompress_struct jpegDecompStruct;
  221. struct jpeg_error_mgr jerr;
  222. setupSilentErrorHandler (jerr);
  223. jpegDecompStruct.err = &jerr;
  224. jpeg_create_decompress (&jpegDecompStruct);
  225. jpegDecompStruct.src = (jpeg_source_mgr*)(jpegDecompStruct.mem->alloc_small)
  226. ((j_common_ptr)(&jpegDecompStruct), JPOOL_PERMANENT, sizeof (jpeg_source_mgr));
  227. bool hasFailed = false;
  228. jpegDecompStruct.client_data = &hasFailed;
  229. jpegDecompStruct.src->init_source = dummyCallback1;
  230. jpegDecompStruct.src->fill_input_buffer = jpegFill;
  231. jpegDecompStruct.src->skip_input_data = jpegSkip;
  232. jpegDecompStruct.src->resync_to_restart = jpeg_resync_to_restart;
  233. jpegDecompStruct.src->term_source = dummyCallback1;
  234. jpegDecompStruct.src->next_input_byte = static_cast<const unsigned char*> (mb.getData());
  235. jpegDecompStruct.src->bytes_in_buffer = mb.getDataSize();
  236. jpeg_read_header (&jpegDecompStruct, TRUE);
  237. if (! hasFailed)
  238. {
  239. jpeg_calc_output_dimensions (&jpegDecompStruct);
  240. if (! hasFailed)
  241. {
  242. const int width = (int) jpegDecompStruct.output_width;
  243. const int height = (int) jpegDecompStruct.output_height;
  244. jpegDecompStruct.out_color_space = JCS_RGB;
  245. JSAMPARRAY buffer
  246. = (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct,
  247. JPOOL_IMAGE,
  248. (JDIMENSION) width * 3, 1);
  249. if (jpeg_start_decompress (&jpegDecompStruct) && ! hasFailed)
  250. {
  251. image = Image (Image::RGB, width, height, false);
  252. image.getProperties()->set ("originalImageHadAlpha", false);
  253. const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
  254. const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
  255. for (int y = 0; y < height; ++y)
  256. {
  257. jpeg_read_scanlines (&jpegDecompStruct, buffer, 1);
  258. if (hasFailed)
  259. break;
  260. const uint8* src = *buffer;
  261. uint8* dest = destData.getLinePointer (y);
  262. if (hasAlphaChan)
  263. {
  264. for (int i = width; --i >= 0;)
  265. {
  266. ((PixelARGB*) dest)->setARGB (0xff, src[0], src[1], src[2]);
  267. ((PixelARGB*) dest)->premultiply();
  268. dest += destData.pixelStride;
  269. src += 3;
  270. }
  271. }
  272. else
  273. {
  274. for (int i = width; --i >= 0;)
  275. {
  276. ((PixelRGB*) dest)->setARGB (0xff, src[0], src[1], src[2]);
  277. dest += destData.pixelStride;
  278. src += 3;
  279. }
  280. }
  281. }
  282. if (! hasFailed)
  283. jpeg_finish_decompress (&jpegDecompStruct);
  284. in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData());
  285. }
  286. }
  287. }
  288. jpeg_destroy_decompress (&jpegDecompStruct);
  289. }
  290. return image;
  291. #endif
  292. }
  293. bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
  294. {
  295. using namespace jpeglibNamespace;
  296. using namespace JPEGHelpers;
  297. jpeg_compress_struct jpegCompStruct;
  298. zerostruct (jpegCompStruct);
  299. jpeg_create_compress (&jpegCompStruct);
  300. struct jpeg_error_mgr jerr;
  301. setupSilentErrorHandler (jerr);
  302. jpegCompStruct.err = &jerr;
  303. JuceJpegDest dest;
  304. jpegCompStruct.dest = &dest;
  305. dest.output = &out;
  306. HeapBlock<char> tempBuffer (jpegBufferSize);
  307. dest.buffer = tempBuffer;
  308. dest.next_output_byte = (JOCTET*) dest.buffer;
  309. dest.free_in_buffer = jpegBufferSize;
  310. dest.init_destination = jpegWriteInit;
  311. dest.empty_output_buffer = jpegWriteFlush;
  312. dest.term_destination = jpegWriteTerminate;
  313. jpegCompStruct.image_width = (JDIMENSION) image.getWidth();
  314. jpegCompStruct.image_height = (JDIMENSION) image.getHeight();
  315. jpegCompStruct.input_components = 3;
  316. jpegCompStruct.in_color_space = JCS_RGB;
  317. jpegCompStruct.write_JFIF_header = 1;
  318. jpegCompStruct.X_density = 72;
  319. jpegCompStruct.Y_density = 72;
  320. jpeg_set_defaults (&jpegCompStruct);
  321. jpegCompStruct.dct_method = JDCT_FLOAT;
  322. jpegCompStruct.optimize_coding = 1;
  323. if (quality < 0.0f)
  324. quality = 0.85f;
  325. jpeg_set_quality (&jpegCompStruct, jlimit (0, 100, roundToInt (quality * 100.0f)), TRUE);
  326. jpeg_start_compress (&jpegCompStruct, TRUE);
  327. const int strideBytes = (int) (jpegCompStruct.image_width * (unsigned int) jpegCompStruct.input_components);
  328. JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct,
  329. JPOOL_IMAGE, (JDIMENSION) strideBytes, 1);
  330. const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
  331. while (jpegCompStruct.next_scanline < jpegCompStruct.image_height)
  332. {
  333. uint8* dst = *buffer;
  334. if (srcData.pixelFormat == Image::RGB)
  335. {
  336. const uint8* src = srcData.getLinePointer ((int) jpegCompStruct.next_scanline);
  337. for (int i = srcData.width; --i >= 0;)
  338. {
  339. *dst++ = ((const PixelRGB*) src)->getRed();
  340. *dst++ = ((const PixelRGB*) src)->getGreen();
  341. *dst++ = ((const PixelRGB*) src)->getBlue();
  342. src += srcData.pixelStride;
  343. }
  344. }
  345. else
  346. {
  347. for (int x = 0; x < srcData.width; ++x)
  348. {
  349. const Colour pixel (srcData.getPixelColour (x, (int) jpegCompStruct.next_scanline));
  350. *dst++ = pixel.getRed();
  351. *dst++ = pixel.getGreen();
  352. *dst++ = pixel.getBlue();
  353. }
  354. }
  355. jpeg_write_scanlines (&jpegCompStruct, buffer, 1);
  356. }
  357. jpeg_finish_compress (&jpegCompStruct);
  358. jpeg_destroy_compress (&jpegCompStruct);
  359. return true;
  360. }
  361. } // namespace juce