/indra/llimage/llimagedimensionsinfo.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 222 lines · 142 code · 37 blank · 43 comment · 21 complexity · 119f87edfde8f0cd862bd2c7cff05b39 MD5 · raw file

  1. /**
  2. * @file llimagedimensionsinfo.cpp
  3. *
  4. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "linden_common.h"
  26. #include "stdtypes.h"
  27. #include "llimagejpeg.h"
  28. #include "llimagedimensionsinfo.h"
  29. // Value is true if one of Libjpeg's functions has encountered an error while working.
  30. static bool sJpegErrorEncountered = false;
  31. bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
  32. {
  33. clean();
  34. mSrcFilename = src_filename;
  35. S32 file_size = 0;
  36. apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
  37. if (s != APR_SUCCESS)
  38. {
  39. setLastError("Unable to open file for reading", src_filename);
  40. return false;
  41. }
  42. if (file_size == 0)
  43. {
  44. setLastError("File is empty",src_filename);
  45. return false;
  46. }
  47. switch (codec)
  48. {
  49. case IMG_CODEC_BMP:
  50. return getImageDimensionsBmp();
  51. case IMG_CODEC_TGA:
  52. return getImageDimensionsTga();
  53. case IMG_CODEC_JPEG:
  54. return getImageDimensionsJpeg();
  55. case IMG_CODEC_PNG:
  56. return getImageDimensionsPng();
  57. default:
  58. return false;
  59. }
  60. }
  61. bool LLImageDimensionsInfo::getImageDimensionsBmp()
  62. {
  63. // Make sure the file is long enough.
  64. const S32 DATA_LEN = 26; // BMP header (14) + DIB header size (4) + width (4) + height (4)
  65. if (!checkFileLength(DATA_LEN))
  66. {
  67. llwarns << "Premature end of file" << llendl;
  68. return false;
  69. }
  70. // Read BMP signature.
  71. U8 signature[2];
  72. mInfile.read((void*)signature, sizeof(signature)/sizeof(signature[0]));
  73. // Make sure this is actually a BMP file.
  74. // We only support Windows bitmaps (BM), according to LLImageBMP::updateData().
  75. if (signature[0] != 'B' || signature[1] != 'M')
  76. {
  77. llwarns << "Not a BMP" << llendl;
  78. return false;
  79. }
  80. // Read image dimensions.
  81. mInfile.seek(APR_CUR, 16);
  82. mWidth = read_reverse_s32();
  83. mHeight = read_reverse_s32();
  84. return true;
  85. }
  86. bool LLImageDimensionsInfo::getImageDimensionsTga()
  87. {
  88. const S32 TGA_FILE_HEADER_SIZE = 12;
  89. // Make sure the file is long enough.
  90. if (!checkFileLength(TGA_FILE_HEADER_SIZE + 1 /* width */ + 1 /* height */))
  91. {
  92. llwarns << "Premature end of file" << llendl;
  93. return false;
  94. }
  95. // *TODO: Detect non-TGA files somehow.
  96. mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
  97. mWidth = read_byte() | read_byte() << 8;
  98. mHeight = read_byte() | read_byte() << 8;
  99. return true;
  100. }
  101. bool LLImageDimensionsInfo::getImageDimensionsPng()
  102. {
  103. const S32 PNG_MAGIC_SIZE = 8;
  104. // Make sure the file is long enough.
  105. if (!checkFileLength(PNG_MAGIC_SIZE + 8 + sizeof(S32) * 2 /* width, height */))
  106. {
  107. llwarns << "Premature end of file" << llendl;
  108. return false;
  109. }
  110. // Read PNG signature.
  111. const U8 png_magic[PNG_MAGIC_SIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
  112. U8 signature[PNG_MAGIC_SIZE];
  113. mInfile.read((void*)signature, PNG_MAGIC_SIZE);
  114. // Make sure it's a PNG file.
  115. if (memcmp(signature, png_magic, PNG_MAGIC_SIZE) != 0)
  116. {
  117. llwarns << "Not a PNG" << llendl;
  118. return false;
  119. }
  120. // Read image dimensions.
  121. mInfile.seek(APR_CUR, 8 /* chunk length + chunk type */);
  122. mWidth = read_s32();
  123. mHeight = read_s32();
  124. return true;
  125. }
  126. // Called instead of exit() if Libjpeg encounters an error.
  127. void on_jpeg_error(j_common_ptr cinfo)
  128. {
  129. (void) cinfo;
  130. sJpegErrorEncountered = true;
  131. llwarns << "Libjpeg has encountered an error!" << llendl;
  132. }
  133. bool LLImageDimensionsInfo::getImageDimensionsJpeg()
  134. {
  135. sJpegErrorEncountered = false;
  136. clean();
  137. FILE *fp = fopen (mSrcFilename.c_str(), "rb");
  138. if (fp == NULL)
  139. {
  140. setLastError("Unable to open file for reading", mSrcFilename);
  141. return false;
  142. }
  143. /* Make sure this is a JPEG file. */
  144. const size_t JPEG_MAGIC_SIZE = 2;
  145. const uint8_t jpeg_magic[JPEG_MAGIC_SIZE] = {0xFF, 0xD8};
  146. uint8_t signature[JPEG_MAGIC_SIZE];
  147. if (fread(signature, sizeof(signature), 1, fp) != 1)
  148. {
  149. llwarns << "Premature end of file" << llendl;
  150. return false;
  151. }
  152. if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0)
  153. {
  154. llwarns << "Not a JPEG" << llendl;
  155. return false;
  156. }
  157. fseek(fp, 0, SEEK_SET); // go back to start of the file
  158. /* Init jpeg */
  159. jpeg_error_mgr jerr;
  160. jpeg_decompress_struct cinfo;
  161. cinfo.err = jpeg_std_error(&jerr);
  162. // Call our function instead of exit() if Libjpeg encounters an error.
  163. // This is done to avoid crash in this case (STORM-472).
  164. cinfo.err->error_exit = on_jpeg_error;
  165. jpeg_create_decompress (&cinfo);
  166. jpeg_stdio_src (&cinfo, fp);
  167. jpeg_read_header (&cinfo, TRUE);
  168. cinfo.out_color_space = JCS_RGB;
  169. jpeg_start_decompress (&cinfo);
  170. mHeight = cinfo.output_width;
  171. mHeight = cinfo.output_height;
  172. jpeg_destroy_decompress(&cinfo);
  173. fclose(fp);
  174. return !sJpegErrorEncountered;
  175. }
  176. bool LLImageDimensionsInfo::checkFileLength(S32 min_len)
  177. {
  178. // Make sure the file is not shorter than min_len bytes.
  179. // so that we don't have to check value returned by each read() or seek().
  180. char* buf = new char[min_len];
  181. int nread = mInfile.read(buf, min_len);
  182. delete[] buf;
  183. mInfile.seek(APR_SET, 0);
  184. return nread == min_len;
  185. }