00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "linden_common.h"
00033 #include "stdtypes.h"
00034 #include "llerror.h"
00035
00036 #include "llimage.h"
00037 #include "llpngwrapper.h"
00038
00039
00040
00041
00042
00043 LLPngWrapper::LLPngWrapper()
00044 : mReadPngPtr( NULL ),
00045 mReadInfoPtr( NULL ),
00046 mWritePngPtr( NULL ),
00047 mWriteInfoPtr( NULL ),
00048 mRowPointers( NULL ),
00049 mBitDepth( 0 ),
00050 mColorType( 0 ),
00051 mChannels( 0 ),
00052 mInterlaceType( 0 ),
00053 mCompressionType( 0 ),
00054 mFilterMethod( 0 ),
00055 mFinalSize( 0 )
00056 {
00057 }
00058
00059 LLPngWrapper::~LLPngWrapper()
00060 {
00061 releaseResources();
00062 }
00063
00064
00065 BOOL LLPngWrapper::isValidPng(U8* src)
00066 {
00067 const int PNG_BYTES_TO_CHECK = 8;
00068
00069 int sig = png_sig_cmp((png_bytep)src, (png_size_t)0, PNG_BYTES_TO_CHECK);
00070 if (sig != 0)
00071 {
00072 mErrorMessage = "Invalid or corrupt PNG file";
00073 return FALSE;
00074 }
00075
00076 return TRUE;
00077 }
00078
00079
00080
00081
00082 void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg)
00083 {
00084 throw msg;
00085 }
00086
00087
00088
00089 void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length)
00090 {
00091 PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr);
00092 U8 *src = &dataInfo->mData[dataInfo->mOffset];
00093 memcpy(dest, src, length);
00094 dataInfo->mOffset += static_cast<U32>(length);
00095 }
00096
00097
00098
00099 void LLPngWrapper::writeDataCallback(png_structp png_ptr, png_bytep src, png_size_t length)
00100 {
00101 PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr);
00102 U8 *dest = &dataInfo->mData[dataInfo->mOffset];
00103 memcpy(dest, src, length);
00104 dataInfo->mOffset += static_cast<U32>(length);
00105 }
00106
00107
00108 void LLPngWrapper::writeFlush(png_structp png_ptr)
00109 {
00110
00111 }
00112
00113
00114
00115
00116
00117
00118
00119 BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop)
00120 {
00121 try
00122 {
00123
00124 mReadPngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00125 this, &errorHandler, NULL);
00126 if (mReadPngPtr == NULL)
00127 {
00128 throw "Problem creating png read structure";
00129 }
00130
00131
00132 mReadInfoPtr = png_create_info_struct(mReadPngPtr);
00133
00134
00135 PngDataInfo dataPtr;
00136 dataPtr.mData = src;
00137 dataPtr.mOffset = 0;
00138
00139 png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback);
00140 png_set_sig_bytes(mReadPngPtr, 0);
00141
00142
00143 png_read_info(mReadPngPtr, mReadInfoPtr);
00144 png_get_IHDR(mReadPngPtr, mReadInfoPtr, &mWidth, &mHeight,
00145 &mBitDepth, &mColorType, &mInterlaceType,
00146 &mCompressionType, &mFilterMethod);
00147
00148
00149
00150 normalizeImage();
00151 updateMetaData();
00152
00153
00154
00155 if (rawImage != NULL)
00156 {
00157 rawImage->resize(static_cast<U16>(mWidth),
00158 static_cast<U16>(mHeight), mChannels);
00159 U8 *dest = rawImage->getData();
00160 int offset = mWidth * mChannels;
00161
00162
00163 mRowPointers = new U8* [mHeight];
00164 for (U32 i=0; i < mHeight; i++)
00165 {
00166 mRowPointers[i] = &dest[(mHeight-i-1)*offset];
00167 }
00168
00169 png_read_image(mReadPngPtr, mRowPointers);
00170
00171
00172 png_read_end(mReadPngPtr, NULL);
00173 }
00174
00175
00176 if (infop != NULL)
00177 {
00178 infop->mHeight = static_cast<U16>(mHeight);
00179 infop->mWidth = static_cast<U16>(mWidth);
00180 infop->mComponents = mChannels;
00181 }
00182
00183 mFinalSize = dataPtr.mOffset;
00184 }
00185 catch (png_const_charp msg)
00186 {
00187 mErrorMessage = msg;
00188 releaseResources();
00189 return (FALSE);
00190 }
00191
00192
00193 releaseResources();
00194 return (TRUE);
00195 }
00196
00197
00198 void LLPngWrapper::normalizeImage()
00199 {
00200
00201
00202
00203
00204
00205
00206
00207 if (mColorType == PNG_COLOR_TYPE_PALETTE)
00208 {
00209 png_set_palette_to_rgb(mReadPngPtr);
00210 }
00211 if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8)
00212 {
00213 png_set_gray_1_2_4_to_8(mReadPngPtr);
00214 }
00215 if (mColorType == PNG_COLOR_TYPE_GRAY
00216 || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
00217 {
00218 png_set_gray_to_rgb(mReadPngPtr);
00219 }
00220 if (png_get_valid(mReadPngPtr, mReadInfoPtr, PNG_INFO_tRNS))
00221 {
00222 png_set_tRNS_to_alpha(mReadPngPtr);
00223 }
00224 if (mBitDepth < 8)
00225 {
00226 png_set_packing(mReadPngPtr);
00227 }
00228 else if (mBitDepth == 16)
00229 {
00230 png_set_strip_16(mReadPngPtr);
00231 }
00232 mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
00233 if (mHasBKGD)
00234 {
00235 png_set_background(mReadPngPtr, mBackgroundColor,
00236 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
00237 }
00238
00239 #if LL_DARWIN
00240 const F64 SCREEN_GAMMA = 1.8;
00241 #else
00242 const F64 SCREEN_GAMMA = 2.2;
00243 #endif
00244
00245 if (png_get_gAMA(mReadPngPtr, mReadInfoPtr, &mGamma))
00246 {
00247 png_set_gamma(mReadPngPtr, SCREEN_GAMMA, mGamma);
00248 }
00249 else
00250 {
00251 png_set_gamma(mReadPngPtr, SCREEN_GAMMA, 1/SCREEN_GAMMA);
00252 }
00253 }
00254
00255
00256 void LLPngWrapper::updateMetaData()
00257 {
00258 png_read_update_info(mReadPngPtr, mReadInfoPtr);
00259 mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr);
00260 mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr);
00261 mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr);
00262 mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr);
00263 mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr);
00264 mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
00265 }
00266
00267
00268
00269 BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
00270 {
00271 try
00272 {
00273 S8 numComponents = rawImage->getComponents();
00274 switch (numComponents)
00275 {
00276 case 1:
00277 mColorType = PNG_COLOR_TYPE_GRAY;
00278 break;
00279 case 2:
00280 mColorType = PNG_COLOR_TYPE_GRAY_ALPHA;
00281 break;
00282 case 3:
00283 mColorType = PNG_COLOR_TYPE_RGB;
00284 break;
00285 case 4:
00286 mColorType = PNG_COLOR_TYPE_RGB_ALPHA;
00287 break;
00288 default:
00289 mColorType = -1;
00290 }
00291
00292 if (mColorType == -1)
00293 {
00294 throw "Unsupported image: unexpected number of channels";
00295 }
00296
00297 mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00298 NULL, &errorHandler, NULL);
00299 if (!mWritePngPtr)
00300 {
00301 throw "Problem creating png write structure";
00302 }
00303
00304 mWriteInfoPtr = png_create_info_struct(mWritePngPtr);
00305
00306
00307 PngDataInfo dataPtr;
00308 dataPtr.mData = dest;
00309 dataPtr.mOffset = 0;
00310 png_set_write_fn(mWritePngPtr, &dataPtr, &writeDataCallback, &writeFlush);
00311
00312
00313 mWidth = rawImage->getWidth();
00314 mHeight = rawImage->getHeight();
00315 mBitDepth = 8;
00316 mChannels = numComponents;
00317 mInterlaceType = PNG_INTERLACE_NONE;
00318 mCompressionType = PNG_COMPRESSION_TYPE_DEFAULT;
00319 mFilterMethod = PNG_FILTER_TYPE_DEFAULT;
00320
00321
00322 png_set_IHDR(mWritePngPtr, mWriteInfoPtr, mWidth, mHeight,
00323 mBitDepth, mColorType, mInterlaceType,
00324 mCompressionType, mFilterMethod);
00325
00326
00327 const U8* data = rawImage->getData();
00328 int offset = mWidth * mChannels;
00329
00330
00331 png_write_info(mWritePngPtr, mWriteInfoPtr);
00332
00333
00334 const U8 * rowPointer;
00335 for (U32 i=0; i < mHeight; i++)
00336 {
00337 rowPointer = &data[(mHeight-1-i)*offset];
00338 png_write_row(mWritePngPtr, const_cast<png_bytep>(rowPointer));
00339 }
00340
00341
00342 png_write_end(mWritePngPtr, mWriteInfoPtr);
00343 mFinalSize = dataPtr.mOffset;
00344 }
00345 catch (png_const_charp msg)
00346 {
00347 mErrorMessage = msg;
00348 releaseResources();
00349 return (FALSE);
00350 }
00351
00352 releaseResources();
00353 return TRUE;
00354 }
00355
00356
00357 void LLPngWrapper::releaseResources()
00358 {
00359 if (mReadPngPtr || mReadInfoPtr)
00360 {
00361 png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, png_infopp_NULL);
00362 mReadPngPtr = NULL;
00363 mReadInfoPtr = NULL;
00364 }
00365
00366 if (mWritePngPtr || mWriteInfoPtr)
00367 {
00368 png_destroy_write_struct(&mWritePngPtr, &mWriteInfoPtr);
00369 mWritePngPtr = NULL;
00370 mWriteInfoPtr = NULL;
00371 }
00372
00373 if (mRowPointers)
00374 {
00375 delete[] mRowPointers;
00376 mRowPointers = NULL;
00377 }
00378 }
00379
00380
00381 U32 LLPngWrapper::getFinalSize()
00382 {
00383 return mFinalSize;
00384 }
00385
00386
00387 LLString LLPngWrapper::getErrorMessage()
00388 {
00389 return mErrorMessage;
00390 }