llpngwrapper.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:10k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /*
  2.  * @file llpngwrapper.cpp
  3.  * @brief Encapsulates libpng read/write functionality.
  4.  *
  5.  * $LicenseInfo:firstyear=2007&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2007-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "stdtypes.h"
  34. #include "llerror.h"
  35. #include "llimage.h"
  36. #include "llpngwrapper.h"
  37. // ---------------------------------------------------------------------------
  38. // LLPngWrapper
  39. // ---------------------------------------------------------------------------
  40. LLPngWrapper::LLPngWrapper()
  41. : mReadPngPtr( NULL ),
  42.   mReadInfoPtr( NULL ),
  43.   mWritePngPtr( NULL ),
  44.   mWriteInfoPtr( NULL ),
  45.   mRowPointers( NULL ),
  46.   mWidth( 0 ),
  47.   mHeight( 0 ),
  48.   mBitDepth( 0 ),
  49.   mColorType( 0 ),
  50.   mChannels( 0 ),
  51.   mInterlaceType( 0 ),
  52.   mCompressionType( 0 ),
  53.   mFilterMethod( 0 ),
  54.   mFinalSize( 0 ),
  55.   mHasBKGD(false),
  56.   mBackgroundColor(),
  57.   mGamma(0.f)
  58. {
  59. }
  60. LLPngWrapper::~LLPngWrapper()
  61. {
  62. releaseResources();
  63. }
  64. // Checks the src for a valid PNG header
  65. BOOL LLPngWrapper::isValidPng(U8* src)
  66. {
  67. const int PNG_BYTES_TO_CHECK = 8;
  68. int sig = png_sig_cmp((png_bytep)src, (png_size_t)0, PNG_BYTES_TO_CHECK);
  69. if (sig != 0)
  70. {
  71. mErrorMessage = "Invalid or corrupt PNG file";
  72. return FALSE;
  73. }
  74. return TRUE;
  75. }
  76. // Called by the libpng library when a fatal encoding or decoding error
  77. // occurs.  We simply throw the error message and let our try/catch
  78. // block clean up.
  79. void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg)
  80. {
  81. throw msg;
  82. }
  83. // Called by the libpng library when reading (decoding) the PNG file. We
  84. // copy the PNG data from our internal buffer into the PNG's data buffer.
  85. void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length)
  86. {
  87. PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr);
  88. U8 *src = &dataInfo->mData[dataInfo->mOffset];
  89. memcpy(dest, src, length);
  90. dataInfo->mOffset += static_cast<U32>(length);
  91. }
  92. // Called by the libpng library when writing (encoding) the PNG file. We
  93. // copy the encoded result into our data buffer.
  94. void LLPngWrapper::writeDataCallback(png_structp png_ptr, png_bytep src, png_size_t length)
  95. {
  96. PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr);
  97. U8 *dest = &dataInfo->mData[dataInfo->mOffset];
  98. memcpy(dest, src, length);
  99. dataInfo->mOffset += static_cast<U32>(length);
  100. }
  101. // Flush the write output pointer
  102. void LLPngWrapper::writeFlush(png_structp png_ptr)
  103. {
  104. // no-op since we're just writing to memory
  105. }
  106. // Read the PNG file using the libpng.  The low-level interface is used here
  107. // because we want to do various transformations (including setting the
  108. // matte background if any, and applying gama) which can't be done with
  109. // the high-level interface. The scanline also begins at the bottom of
  110. // the image (per SecondLife conventions) instead of at the top, so we
  111. // must assign row-pointers in "reverse" order.
  112. BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop)
  113. {
  114. try
  115. {
  116. // Create and initialize the png structures
  117. mReadPngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  118. this, &errorHandler, NULL);
  119. if (mReadPngPtr == NULL)
  120. {
  121. throw "Problem creating png read structure";
  122. }
  123. // Allocate/initialize the memory for image information.
  124. mReadInfoPtr = png_create_info_struct(mReadPngPtr);
  125. // Set up the input control
  126. PngDataInfo dataPtr;
  127. dataPtr.mData = src;
  128. dataPtr.mOffset = 0;
  129. png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback);
  130. png_set_sig_bytes(mReadPngPtr, 0);
  131. // setup low-level read and get header information
  132. png_read_info(mReadPngPtr, mReadInfoPtr);
  133. png_get_IHDR(mReadPngPtr, mReadInfoPtr, &mWidth, &mHeight,
  134. &mBitDepth, &mColorType, &mInterlaceType,
  135. &mCompressionType, &mFilterMethod);
  136. // Normalize the image, then get updated image information
  137. // after transformations have been applied
  138. normalizeImage();
  139. updateMetaData();
  140. // If a raw object is supplied, read the PNG image into its
  141. // data space
  142. if (rawImage != NULL)
  143. {
  144. rawImage->resize(static_cast<U16>(mWidth),
  145. static_cast<U16>(mHeight), mChannels);
  146. U8 *dest = rawImage->getData();
  147. int offset = mWidth * mChannels;
  148. // Set up the row pointers and read the image
  149. mRowPointers = new U8* [mHeight];
  150. for (U32 i=0; i < mHeight; i++)
  151. {
  152. mRowPointers[i] = &dest[(mHeight-i-1)*offset];
  153. }
  154. png_read_image(mReadPngPtr, mRowPointers);
  155. // Finish up, ensures all metadata are updated
  156. png_read_end(mReadPngPtr, NULL);
  157. }
  158. // If an info object is supplied, copy the relevant info
  159. if (infop != NULL)
  160. {
  161. infop->mHeight = static_cast<U16>(mHeight);
  162. infop->mWidth = static_cast<U16>(mWidth);
  163. infop->mComponents = mChannels;
  164. }
  165. mFinalSize = dataPtr.mOffset;
  166. }
  167. catch (png_const_charp msg)
  168. {
  169. mErrorMessage = msg;
  170. releaseResources();
  171. return (FALSE);
  172. }
  173. // Clean up and return
  174. releaseResources();
  175. return (TRUE);
  176. }
  177. // Do transformations to normalize the input to 8-bpp RGBA
  178. void LLPngWrapper::normalizeImage()
  179. {
  180. // 1. Expand any palettes
  181. // 2. Convert grayscales to RGB
  182. // 3. Create alpha layer from transparency
  183. // 4. Ensure 8-bpp for all images
  184. // 5. Apply background matte if any
  185. // 6. Set (or guess) gamma
  186. if (mColorType == PNG_COLOR_TYPE_PALETTE)
  187. {
  188. png_set_palette_to_rgb(mReadPngPtr);
  189. }
  190.     if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8)
  191. {
  192. png_set_gray_1_2_4_to_8(mReadPngPtr);
  193. }
  194. if (mColorType == PNG_COLOR_TYPE_GRAY
  195. || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
  196. {
  197. png_set_gray_to_rgb(mReadPngPtr);
  198. }
  199. if (png_get_valid(mReadPngPtr, mReadInfoPtr, PNG_INFO_tRNS))
  200. {
  201. png_set_tRNS_to_alpha(mReadPngPtr);
  202. }
  203. if (mBitDepth < 8)
  204. {
  205. png_set_packing(mReadPngPtr);
  206. }
  207. else if (mBitDepth == 16)
  208. {
  209. png_set_strip_16(mReadPngPtr);
  210. }
  211. mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
  212. if (mHasBKGD)
  213. {
  214. png_set_background(mReadPngPtr, mBackgroundColor,
  215. PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
  216. }
  217. #if LL_DARWIN
  218. const F64 SCREEN_GAMMA = 1.8;
  219. #else
  220. const F64 SCREEN_GAMMA = 2.2;
  221. #endif
  222. if (png_get_gAMA(mReadPngPtr, mReadInfoPtr, &mGamma))
  223. {
  224. png_set_gamma(mReadPngPtr, SCREEN_GAMMA, mGamma);
  225. }
  226. else
  227. {
  228. png_set_gamma(mReadPngPtr, SCREEN_GAMMA, 1/SCREEN_GAMMA);
  229. }
  230. }
  231. // Read out the image meta-data
  232. void LLPngWrapper::updateMetaData()
  233. {
  234. png_read_update_info(mReadPngPtr, mReadInfoPtr);
  235.     mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr);
  236.     mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr);
  237.     mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr);
  238.     mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr);
  239. mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr);
  240. mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
  241. }
  242. // Method to write raw image into PNG at dest. The raw scanline begins
  243. // at the bottom of the image per SecondLife conventions.
  244. BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
  245. {
  246. try
  247. {
  248. S8 numComponents = rawImage->getComponents();
  249. switch (numComponents)
  250. {
  251. case 1:
  252. mColorType = PNG_COLOR_TYPE_GRAY;
  253. break;
  254. case 2:
  255. mColorType = PNG_COLOR_TYPE_GRAY_ALPHA;
  256. break;
  257. case 3:
  258. mColorType = PNG_COLOR_TYPE_RGB;
  259. break;
  260. case 4:
  261. mColorType = PNG_COLOR_TYPE_RGB_ALPHA;
  262. break;
  263. default:
  264. mColorType = -1;
  265. }
  266. if (mColorType == -1)
  267. {
  268. throw "Unsupported image: unexpected number of channels";
  269. }
  270. mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  271. NULL, &errorHandler, NULL);
  272. if (!mWritePngPtr)
  273. {
  274. throw "Problem creating png write structure";
  275. }
  276. mWriteInfoPtr = png_create_info_struct(mWritePngPtr);
  277. // Setup write function
  278. PngDataInfo dataPtr;
  279. dataPtr.mData = dest;
  280. dataPtr.mOffset = 0;
  281. png_set_write_fn(mWritePngPtr, &dataPtr, &writeDataCallback, &writeFlush);
  282. // Setup image params
  283. mWidth = rawImage->getWidth();
  284. mHeight = rawImage->getHeight();
  285. mBitDepth = 8; // Fixed to 8-bpp in SL
  286. mChannels = numComponents;
  287. mInterlaceType = PNG_INTERLACE_NONE;
  288. mCompressionType = PNG_COMPRESSION_TYPE_DEFAULT;
  289. mFilterMethod = PNG_FILTER_TYPE_DEFAULT;
  290. // Write header
  291. png_set_IHDR(mWritePngPtr, mWriteInfoPtr, mWidth, mHeight,
  292. mBitDepth, mColorType, mInterlaceType,
  293. mCompressionType, mFilterMethod);
  294. // Get data and compute row size
  295. const U8* data = rawImage->getData();
  296. int offset = mWidth * mChannels;
  297. // Ready to write, start with the header
  298. png_write_info(mWritePngPtr, mWriteInfoPtr);
  299. // Write image (sorry, must const-cast for libpng)
  300. const U8 * rowPointer;
  301. for (U32 i=0; i < mHeight; i++)
  302. {
  303. rowPointer = &data[(mHeight-1-i)*offset];
  304. png_write_row(mWritePngPtr, const_cast<png_bytep>(rowPointer));
  305. }
  306. // Finish up
  307. png_write_end(mWritePngPtr, mWriteInfoPtr);
  308. mFinalSize = dataPtr.mOffset;
  309. }
  310. catch (png_const_charp msg)
  311. {
  312. mErrorMessage = msg;
  313. releaseResources();
  314. return (FALSE);
  315. }
  316. releaseResources();
  317. return TRUE;
  318. }
  319. // Cleanup various internal structures
  320. void LLPngWrapper::releaseResources()
  321. {
  322. if (mReadPngPtr || mReadInfoPtr)
  323. {
  324. png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, png_infopp_NULL);
  325. mReadPngPtr = NULL;
  326. mReadInfoPtr = NULL;
  327. }
  328. if (mWritePngPtr || mWriteInfoPtr)
  329. {
  330. png_destroy_write_struct(&mWritePngPtr, &mWriteInfoPtr);
  331. mWritePngPtr = NULL;
  332. mWriteInfoPtr = NULL;
  333. }
  334. if (mRowPointers)
  335. {
  336. delete[] mRowPointers;
  337. mRowPointers = NULL;
  338. }
  339. }
  340. // Get final image size after compression
  341. U32 LLPngWrapper::getFinalSize()
  342. {
  343. return mFinalSize;
  344. }
  345. // Get last error message, if any
  346. const std::string& LLPngWrapper::getErrorMessage()
  347. {
  348. return mErrorMessage;
  349. }