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.

363 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #if JUCE_MSVC
  19. #pragma warning (push)
  20. #pragma warning (disable: 4390 4611 4365 4267)
  21. #ifdef __INTEL_COMPILER
  22. #pragma warning (disable: 2544 2545)
  23. #endif
  24. #endif
  25. namespace zlibNamespace
  26. {
  27. #if JUCE_INCLUDE_ZLIB_CODE
  28. #undef OS_CODE
  29. #undef fdopen
  30. #include "../../juce_core/zip/zlib/zlib.h"
  31. #undef OS_CODE
  32. #else
  33. #include JUCE_ZLIB_INCLUDE_PATH
  34. #endif
  35. }
  36. namespace pnglibNamespace
  37. {
  38. using namespace zlibNamespace;
  39. #if JUCE_INCLUDE_PNGLIB_CODE || ! defined (JUCE_INCLUDE_PNGLIB_CODE)
  40. #if _MSC_VER != 1310
  41. using std::calloc; // (causes conflict in VS.NET 2003)
  42. using std::malloc;
  43. using std::free;
  44. #endif
  45. #if JUCE_CLANG
  46. #pragma clang diagnostic push
  47. #pragma clang diagnostic ignored "-Wsign-conversion"
  48. #endif
  49. using std::abs;
  50. #define PNG_INTERNAL
  51. #define NO_DUMMY_DECL
  52. #define PNG_SETJMP_NOT_SUPPORTED
  53. #include "pnglib/png.h"
  54. #include "pnglib/pngconf.h"
  55. #define PNG_NO_EXTERN
  56. #include "pnglib/png.c"
  57. #include "pnglib/pngerror.c"
  58. #include "pnglib/pngget.c"
  59. #include "pnglib/pngmem.c"
  60. #include "pnglib/pngread.c"
  61. #include "pnglib/pngpread.c"
  62. #include "pnglib/pngrio.c"
  63. #include "pnglib/pngrtran.c"
  64. #include "pnglib/pngrutil.c"
  65. #include "pnglib/pngset.c"
  66. #include "pnglib/pngtrans.c"
  67. #include "pnglib/pngwio.c"
  68. #include "pnglib/pngwrite.c"
  69. #include "pnglib/pngwtran.c"
  70. #include "pnglib/pngwutil.c"
  71. #if JUCE_CLANG
  72. #pragma clang diagnostic pop
  73. #endif
  74. #else
  75. extern "C"
  76. {
  77. #include <png.h>
  78. #include <pngconf.h>
  79. }
  80. #endif
  81. }
  82. #undef max
  83. #undef min
  84. #if JUCE_MSVC
  85. #pragma warning (pop)
  86. #endif
  87. //==============================================================================
  88. namespace PNGHelpers
  89. {
  90. using namespace pnglibNamespace;
  91. static void JUCE_CDECL writeDataCallback (png_structp png, png_bytep data, png_size_t length)
  92. {
  93. static_cast<OutputStream*> (png_get_io_ptr (png))->write (data, (int) length);
  94. }
  95. #if ! JUCE_USING_COREIMAGE_LOADER
  96. static void JUCE_CDECL readCallback (png_structp png, png_bytep data, png_size_t length)
  97. {
  98. static_cast<InputStream*> (png_get_io_ptr (png))->read (data, (int) length);
  99. }
  100. struct PNGErrorStruct {};
  101. static void JUCE_CDECL errorCallback (png_structp, png_const_charp)
  102. {
  103. throw PNGErrorStruct();
  104. }
  105. #endif
  106. }
  107. //==============================================================================
  108. PNGImageFormat::PNGImageFormat() {}
  109. PNGImageFormat::~PNGImageFormat() {}
  110. String PNGImageFormat::getFormatName() { return "PNG"; }
  111. bool PNGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("png"); }
  112. bool PNGImageFormat::canUnderstand (InputStream& in)
  113. {
  114. const int bytesNeeded = 4;
  115. char header [bytesNeeded];
  116. return in.read (header, bytesNeeded) == bytesNeeded
  117. && header[1] == 'P'
  118. && header[2] == 'N'
  119. && header[3] == 'G';
  120. }
  121. #if JUCE_USING_COREIMAGE_LOADER
  122. Image juce_loadWithCoreImage (InputStream& input);
  123. #endif
  124. Image PNGImageFormat::decodeImage (InputStream& in)
  125. {
  126. #if JUCE_USING_COREIMAGE_LOADER
  127. return juce_loadWithCoreImage (in);
  128. #else
  129. using namespace pnglibNamespace;
  130. Image image;
  131. png_structp pngReadStruct;
  132. png_infop pngInfoStruct;
  133. pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
  134. if (pngReadStruct != 0)
  135. {
  136. try
  137. {
  138. pngInfoStruct = png_create_info_struct (pngReadStruct);
  139. if (pngInfoStruct == 0)
  140. {
  141. png_destroy_read_struct (&pngReadStruct, 0, 0);
  142. return Image::null;
  143. }
  144. png_set_error_fn (pngReadStruct, 0, PNGHelpers::errorCallback, PNGHelpers::errorCallback );
  145. // read the header..
  146. png_set_read_fn (pngReadStruct, &in, PNGHelpers::readCallback);
  147. png_uint_32 width, height;
  148. int bitDepth, colorType, interlaceType;
  149. png_read_info (pngReadStruct, pngInfoStruct);
  150. png_get_IHDR (pngReadStruct, pngInfoStruct,
  151. &width, &height,
  152. &bitDepth, &colorType,
  153. &interlaceType, 0, 0);
  154. if (bitDepth == 16)
  155. png_set_strip_16 (pngReadStruct);
  156. if (colorType == PNG_COLOR_TYPE_PALETTE)
  157. png_set_expand (pngReadStruct);
  158. if (bitDepth < 8)
  159. png_set_expand (pngReadStruct);
  160. if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS))
  161. png_set_expand (pngReadStruct);
  162. if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
  163. png_set_gray_to_rgb (pngReadStruct);
  164. png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER);
  165. bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0
  166. || pngInfoStruct->num_trans > 0;
  167. // Load the image into a temp buffer in the pnglib format..
  168. HeapBlock <uint8> tempBuffer (height * (width << 2));
  169. {
  170. HeapBlock <png_bytep> rows (height);
  171. for (int y = (int) height; --y >= 0;)
  172. rows[y] = (png_bytep) (tempBuffer + (width << 2) * y);
  173. try
  174. {
  175. png_read_image (pngReadStruct, rows);
  176. png_read_end (pngReadStruct, pngInfoStruct);
  177. }
  178. catch (PNGHelpers::PNGErrorStruct&)
  179. {}
  180. }
  181. png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0);
  182. // now convert the data to a juce image format..
  183. image = Image (hasAlphaChan ? Image::ARGB : Image::RGB,
  184. (int) width, (int) height, hasAlphaChan);
  185. image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel());
  186. hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
  187. const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
  188. uint8* srcRow = tempBuffer;
  189. uint8* destRow = destData.data;
  190. for (int y = 0; y < (int) height; ++y)
  191. {
  192. const uint8* src = srcRow;
  193. srcRow += (width << 2);
  194. uint8* dest = destRow;
  195. destRow += destData.lineStride;
  196. if (hasAlphaChan)
  197. {
  198. for (int i = (int) width; --i >= 0;)
  199. {
  200. ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]);
  201. ((PixelARGB*) dest)->premultiply();
  202. dest += destData.pixelStride;
  203. src += 4;
  204. }
  205. }
  206. else
  207. {
  208. for (int i = (int) width; --i >= 0;)
  209. {
  210. ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
  211. dest += destData.pixelStride;
  212. src += 4;
  213. }
  214. }
  215. }
  216. }
  217. catch (PNGHelpers::PNGErrorStruct&)
  218. {}
  219. }
  220. return image;
  221. #endif
  222. }
  223. bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
  224. {
  225. using namespace pnglibNamespace;
  226. const int width = image.getWidth();
  227. const int height = image.getHeight();
  228. png_structp pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
  229. if (pngWriteStruct == 0)
  230. return false;
  231. png_infop pngInfoStruct = png_create_info_struct (pngWriteStruct);
  232. if (pngInfoStruct == 0)
  233. {
  234. png_destroy_write_struct (&pngWriteStruct, (png_infopp) 0);
  235. return false;
  236. }
  237. png_set_write_fn (pngWriteStruct, &out, PNGHelpers::writeDataCallback, 0);
  238. png_set_IHDR (pngWriteStruct, pngInfoStruct, (png_uint_32) width, (png_uint_32) height, 8,
  239. image.hasAlphaChannel() ? PNG_COLOR_TYPE_RGB_ALPHA
  240. : PNG_COLOR_TYPE_RGB,
  241. PNG_INTERLACE_NONE,
  242. PNG_COMPRESSION_TYPE_BASE,
  243. PNG_FILTER_TYPE_BASE);
  244. HeapBlock <uint8> rowData ((size_t) width * 4);
  245. png_color_8 sig_bit;
  246. sig_bit.red = 8;
  247. sig_bit.green = 8;
  248. sig_bit.blue = 8;
  249. sig_bit.alpha = 8;
  250. png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit);
  251. png_write_info (pngWriteStruct, pngInfoStruct);
  252. png_set_shift (pngWriteStruct, &sig_bit);
  253. png_set_packing (pngWriteStruct);
  254. const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
  255. for (int y = 0; y < height; ++y)
  256. {
  257. uint8* dst = rowData;
  258. const uint8* src = srcData.getLinePointer (y);
  259. if (image.hasAlphaChannel())
  260. {
  261. for (int i = width; --i >= 0;)
  262. {
  263. PixelARGB p (*(const PixelARGB*) src);
  264. p.unpremultiply();
  265. *dst++ = p.getRed();
  266. *dst++ = p.getGreen();
  267. *dst++ = p.getBlue();
  268. *dst++ = p.getAlpha();
  269. src += srcData.pixelStride;
  270. }
  271. }
  272. else
  273. {
  274. for (int i = width; --i >= 0;)
  275. {
  276. *dst++ = ((const PixelRGB*) src)->getRed();
  277. *dst++ = ((const PixelRGB*) src)->getGreen();
  278. *dst++ = ((const PixelRGB*) src)->getBlue();
  279. src += srcData.pixelStride;
  280. }
  281. }
  282. png_bytep rowPtr = rowData;
  283. png_write_rows (pngWriteStruct, &rowPtr, 1);
  284. }
  285. png_write_end (pngWriteStruct, pngInfoStruct);
  286. png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct);
  287. return true;
  288. }