The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

445 lines
14KB

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