/xbmc/screensavers/rsxs-0.9/src/pngimage.cc

http://github.com/xbmc/xbmc · C++ · 206 lines · 162 code · 22 blank · 22 comment · 27 complexity · 0ffa13c8acccd80ff9d80b6dfd4e5a0f MD5 · raw file

  1. /*
  2. * Really Slick XScreenSavers
  3. * Copyright (C) 2002-2006 Michael Chapman
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *****************************************************************************
  19. *
  20. * This is a Linux port of the Really Slick Screensavers,
  21. * Copyright (C) 2002 Terence M. Welsh, available from www.reallyslick.com
  22. */
  23. #include <common.hh>
  24. #if HAVE_PNG_H
  25. #include <png.h>
  26. #endif
  27. #if HAVE_SETJMP_H
  28. #include <setjmp.h>
  29. #endif
  30. #include <cerrno>
  31. #include <color.hh>
  32. #include <pngimage.hh>
  33. #include <cstring>
  34. void PNG::load(FILE* in, bool fullColor) {
  35. png_byte sig[8];
  36. int sigBytes = fread(sig, 1, 8, in);
  37. if (png_sig_cmp(sig, 0, sigBytes))
  38. throw Exception("Not a PNG file");
  39. png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  40. NULL, NULL, NULL);
  41. if (!png)
  42. throw Exception("Could not create PNG read structure");
  43. png_infop pngInfo = png_create_info_struct(png);
  44. if (!pngInfo)
  45. throw Exception("Could not create PNG info structure");
  46. try {
  47. if (setjmp(png_jmpbuf(png)))
  48. throw Exception("PNG could not be decoded");
  49. png_init_io(png, in);
  50. png_set_sig_bytes(png, sigBytes);
  51. png_read_info(png, pngInfo);
  52. if (png_get_color_type(png, pngInfo) == PNG_COLOR_TYPE_PALETTE)
  53. png_set_palette_to_rgb(png);
  54. if (
  55. (png_get_color_type(png, pngInfo) == PNG_COLOR_TYPE_GRAY) &&
  56. png_get_bit_depth(png, pngInfo) < 8
  57. )
  58. png_set_expand_gray_1_2_4_to_8(png);
  59. if (png_get_valid(png, pngInfo, PNG_INFO_tRNS))
  60. png_set_tRNS_to_alpha(png);
  61. if (fullColor)
  62. png_set_gray_to_rgb(png);
  63. if (png_get_bit_depth(png, pngInfo) < 8)
  64. png_set_packing(png);
  65. png_read_update_info(png, pngInfo);
  66. _width = png_get_image_width(png, pngInfo);
  67. _height = png_get_image_height(png, pngInfo);
  68. switch (png_get_color_type(png, pngInfo)) {
  69. case PNG_COLOR_TYPE_GRAY:
  70. _format = GL_LUMINANCE;
  71. _bytesPerPixel = 1;
  72. _hasAlphaChannel = false;
  73. break;
  74. case PNG_COLOR_TYPE_RGB:
  75. _format = GL_RGB;
  76. _bytesPerPixel = 3;
  77. _hasAlphaChannel = false;
  78. break;
  79. case PNG_COLOR_TYPE_RGBA:
  80. _format = GL_RGBA;
  81. _bytesPerPixel = 4;
  82. _hasAlphaChannel = true;
  83. break;
  84. case PNG_COLOR_TYPE_GA:
  85. _format = GL_LUMINANCE_ALPHA;
  86. _bytesPerPixel = 2;
  87. _hasAlphaChannel = true;
  88. break;
  89. default:
  90. throw Exception("Unhandled image type");
  91. }
  92. switch (png_get_bit_depth(png, pngInfo)) {
  93. case 8:
  94. _type = GL_UNSIGNED_BYTE;
  95. break;
  96. case 16:
  97. _type = GL_UNSIGNED_SHORT;
  98. _bytesPerPixel *= 2;
  99. break;
  100. default:
  101. throw Exception("Unhandled image depth");
  102. }
  103. _numComponents = png_get_channels(png, pngInfo);
  104. GLint alignment;
  105. glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
  106. _rowLength =
  107. ((_width * _bytesPerPixel + alignment - 1) / alignment) * alignment;
  108. _data = new uint8_t[_height * _rowLength];
  109. png_bytep* rows = new png_bytep[_height];
  110. for (GLsizei i = 0; i < _height; ++i)
  111. rows[i] = _data + _rowLength * i;
  112. png_read_image(png, rows);
  113. delete[] rows;
  114. png_read_end(png, NULL);
  115. png_destroy_read_struct(&png, &pngInfo, NULL);
  116. } catch (...) {
  117. png_destroy_read_struct(&png, &pngInfo, NULL);
  118. throw;
  119. }
  120. }
  121. PNG::PNG(const std::string& filename, bool fullColor) {
  122. if (filename.empty())
  123. throw Exception("Empty filename");
  124. FILE* in = NULL;
  125. if (filename[0] != '/')
  126. in = std::fopen((Common::resourceDir + '/' + filename).c_str(), "rb");
  127. if (!in)
  128. in = std::fopen(filename.c_str(), "rb");
  129. if (!in)
  130. throw Exception(stdx::oss() << filename << ": " << std::strerror(errno));
  131. try {
  132. load(in, fullColor);
  133. } catch (Exception e) {
  134. throw Exception(stdx::oss() << filename << ": " << e);
  135. }
  136. std::fclose(in);
  137. }
  138. PNG::~PNG() {
  139. if (_data) delete[] _data;
  140. }
  141. const RGBColor PNG::operator()(GLsizei x, GLsizei y) const {
  142. if (x >= _width || y >= _height)
  143. return RGBColor();
  144. uint8_t* pos = _data + _rowLength * y + _bytesPerPixel * x;
  145. if (_type == GL_UNSIGNED_BYTE) {
  146. switch (_format) {
  147. case GL_LUMINANCE:
  148. case GL_LUMINANCE_ALPHA:
  149. {
  150. float l = float(*pos) / 255.0f;
  151. return RGBColor(l, l, l);
  152. }
  153. case GL_RGB:
  154. case GL_RGBA:
  155. {
  156. float r = float(pos[0]) / 255.0f;
  157. float g = float(pos[1]) / 255.0f;
  158. float b = float(pos[2]) / 255.0f;
  159. return RGBColor(r, g, b);
  160. }
  161. default:
  162. return RGBColor();
  163. }
  164. } else {
  165. switch (_format) {
  166. case GL_LUMINANCE:
  167. case GL_LUMINANCE_ALPHA:
  168. {
  169. float l = float((unsigned int)(pos[0]) * 255 + pos[1]) / 65535.0f;
  170. return RGBColor(l, l, l);
  171. }
  172. case GL_RGB:
  173. case GL_RGBA:
  174. {
  175. float r = float((unsigned int)(pos[0]) * 255 + pos[1]) / 65535.0f;
  176. float g = float((unsigned int)(pos[2]) * 255 + pos[3]) / 65535.0f;
  177. float b = float((unsigned int)(pos[4]) * 255 + pos[5]) / 65535.0f;
  178. return RGBColor(r, g, b);
  179. }
  180. default:
  181. return RGBColor();
  182. }
  183. }
  184. }