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.

484 lines
15KB

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