CImageLoaderPNG.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #include "CImageLoaderPNG.h"
  5. #ifdef _IRR_COMPILE_WITH_PNG_LOADER_
  6. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  7. #ifndef _IRR_USE_NON_SYSTEM_LIB_PNG_
  8. #include <png.h> // use system lib png
  9. #else // _IRR_USE_NON_SYSTEM_LIB_PNG_
  10. #include "libpng/png.h" // use irrlicht included lib png
  11. #endif // _IRR_USE_NON_SYSTEM_LIB_PNG_
  12. #endif // _IRR_COMPILE_WITH_LIBPNG_
  13. #include "CImage.h"
  14. #include "CReadFile.h"
  15. #include "os.h"
  16. namespace irr
  17. {
  18. namespace video
  19. {
  20. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  21. // PNG function for error handling
  22. static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg)
  23. {
  24. printf("PNG fatal error: %s\n", msg);
  25. longjmp(png_jmpbuf(png_ptr), 1);
  26. }
  27. // PNG function for warning handling
  28. static void png_cpexcept_warn(png_structp png_ptr, png_const_charp msg)
  29. {
  30. //os::Printer::log("PNG warning", msg, ELL_WARNING);
  31. }
  32. // PNG function for file reading
  33. void PNGAPI user_read_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length)
  34. {
  35. png_size_t check;
  36. // changed by zola {
  37. io::IReadFile* file=(io::IReadFile*)png_get_io_ptr(png_ptr);
  38. check=(png_size_t) file->read((void*)data,(u32)length);
  39. // }
  40. if (check != length)
  41. png_error(png_ptr, "Read Error");
  42. }
  43. #endif // _IRR_COMPILE_WITH_LIBPNG_
  44. //! returns true if the file maybe is able to be loaded by this class
  45. //! based on the file extension (e.g. ".tga")
  46. bool CImageLoaderPng::isALoadableFileExtension(const io::path& filename) const
  47. {
  48. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  49. return core::hasFileExtension ( filename, "png" );
  50. #else
  51. return false;
  52. #endif // _IRR_COMPILE_WITH_LIBPNG_
  53. }
  54. //! returns true if the file maybe is able to be loaded by this class
  55. bool CImageLoaderPng::isALoadableFileFormat(io::IReadFile* file) const
  56. {
  57. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  58. if (!file)
  59. return false;
  60. png_byte buffer[8];
  61. // Read the first few bytes of the PNG file
  62. if (file->read(buffer, 8) != 8)
  63. return false;
  64. // Check if it really is a PNG file
  65. return !png_sig_cmp(buffer, 0, 8);
  66. #else
  67. return false;
  68. #endif // _IRR_COMPILE_WITH_LIBPNG_
  69. }
  70. // load in the image data
  71. IImage* CImageLoaderPng::loadImage(io::IReadFile* file, bool skip_checking) const
  72. {
  73. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  74. if (!file)
  75. return 0;
  76. video::IImage* image = 0;
  77. //Used to point to image rows
  78. u8** RowPointers = 0;
  79. if (skip_checking)
  80. file->seek(8);
  81. else if (!isALoadableFileFormat(file))
  82. return 0;
  83. // Allocate the png read struct
  84. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  85. NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn);
  86. if (!png_ptr)
  87. {
  88. //os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR);
  89. return 0;
  90. }
  91. // Allocate the png info struct
  92. png_infop info_ptr = png_create_info_struct(png_ptr);
  93. if (!info_ptr)
  94. {
  95. //os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR);
  96. png_destroy_read_struct(&png_ptr, NULL, NULL);
  97. return 0;
  98. }
  99. // for proper error handling
  100. if (setjmp(png_jmpbuf(png_ptr)))
  101. {
  102. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  103. if (RowPointers)
  104. delete [] RowPointers;
  105. return 0;
  106. }
  107. // changed by zola so we don't need to have public FILE pointers
  108. png_set_read_fn(png_ptr, file, user_read_data_fcn);
  109. png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature
  110. png_read_info(png_ptr, info_ptr); // Read the info section of the png file
  111. u32 Width;
  112. u32 Height;
  113. s32 BitDepth;
  114. s32 ColorType;
  115. {
  116. // Use temporary variables to avoid passing casted pointers
  117. png_uint_32 w,h;
  118. // Extract info
  119. png_get_IHDR(png_ptr, info_ptr,
  120. &w, &h,
  121. &BitDepth, &ColorType, NULL, NULL, NULL);
  122. Width=w;
  123. Height=h;
  124. }
  125. // Convert palette color to true color
  126. if (ColorType==PNG_COLOR_TYPE_PALETTE)
  127. png_set_palette_to_rgb(png_ptr);
  128. // Convert low bit colors to 8 bit colors
  129. if (BitDepth < 8)
  130. {
  131. if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
  132. png_set_expand_gray_1_2_4_to_8(png_ptr);
  133. else
  134. png_set_packing(png_ptr);
  135. }
  136. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
  137. png_set_tRNS_to_alpha(png_ptr);
  138. // Convert high bit colors to 8 bit colors
  139. if (BitDepth == 16)
  140. png_set_strip_16(png_ptr);
  141. // Convert gray color to true color
  142. if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
  143. png_set_gray_to_rgb(png_ptr);
  144. // Update the changes in between, as we need to get the new color type
  145. // for proper processing of the RGBA type
  146. png_read_update_info(png_ptr, info_ptr);
  147. {
  148. // Use temporary variables to avoid passing casted pointers
  149. png_uint_32 w,h;
  150. // Extract info
  151. png_get_IHDR(png_ptr, info_ptr,
  152. &w, &h,
  153. &BitDepth, &ColorType, NULL, NULL, NULL);
  154. Width=w;
  155. Height=h;
  156. }
  157. // Convert RGBA to BGRA
  158. if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
  159. {
  160. #ifdef __BIG_ENDIAN__
  161. png_set_swap_alpha(png_ptr);
  162. #else
  163. png_set_bgr(png_ptr);
  164. #endif
  165. }
  166. // Create the image structure to be filled by png data
  167. if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
  168. image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(Width, Height));
  169. else
  170. image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(Width, Height));
  171. if (!image)
  172. {
  173. //os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR);
  174. png_destroy_read_struct(&png_ptr, NULL, NULL);
  175. return 0;
  176. }
  177. // Create array of pointers to rows in image data
  178. RowPointers = new png_bytep[Height];
  179. if (!RowPointers)
  180. {
  181. //os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR);
  182. png_destroy_read_struct(&png_ptr, NULL, NULL);
  183. delete image;
  184. return 0;
  185. }
  186. // Fill array of pointers to rows in image data
  187. unsigned char* data = (unsigned char*)image->lock();
  188. for (u32 i=0; i<Height; ++i)
  189. {
  190. RowPointers[i]=data;
  191. data += image->getPitch();
  192. }
  193. // for proper error handling
  194. if (setjmp(png_jmpbuf(png_ptr)))
  195. {
  196. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  197. delete [] RowPointers;
  198. image->unlock();
  199. delete image;
  200. return 0;
  201. }
  202. // Read data using the library function that handles all transformations including interlacing
  203. png_read_image(png_ptr, RowPointers);
  204. png_read_end(png_ptr, NULL);
  205. delete [] RowPointers;
  206. image->unlock();
  207. png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory
  208. return image;
  209. #else
  210. return 0;
  211. #endif // _IRR_COMPILE_WITH_LIBPNG_
  212. }
  213. core::dimension2du CImageLoaderPng::getImageSize(io::IReadFile* file) const
  214. {
  215. #ifdef _IRR_COMPILE_WITH_LIBPNG_
  216. if (!file || !isALoadableFileFormat(file))
  217. return core::dimension2du(0, 0);
  218. core::dimension2d<u32> dim;
  219. file->seek(16);
  220. file->read(&dim.Width, 4);
  221. file->seek(20);
  222. file->read(&dim.Height, 4);
  223. file->seek(0);
  224. #ifndef __BIG_ENDIAN__
  225. dim.Width = os::Byteswap::byteswap(dim.Width);
  226. dim.Height = os::Byteswap::byteswap(dim.Height);
  227. #endif
  228. return dim;
  229. #else
  230. return core::dimension2du(0, 0);
  231. #endif // _IRR_COMPILE_WITH_LIBPNG_
  232. }
  233. IImageLoader* createImageLoaderPNG()
  234. {
  235. return new CImageLoaderPng();
  236. }
  237. }// end namespace irr
  238. }//end namespace video
  239. #endif