diff options
Diffstat (limited to 'indra/llimage/llimagetga.cpp')
-rw-r--r-- | indra/llimage/llimagetga.cpp | 2172 |
1 files changed, 1086 insertions, 1086 deletions
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 152a7f309c..adc98cd81d 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llimagetga.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,20 +34,20 @@ // For expanding 5-bit pixel values to 8-bit with best rounding // static -const U8 LLImageTGA::s5to8bits[32] = - { - 0, 8, 16, 25, 33, 41, 49, 58, - 66, 74, 82, 90, 99, 107, 115, 123, - 132, 140, 148, 156, 165, 173, 181, 189, - 197, 206, 214, 222, 230, 239, 247, 255 - }; +const U8 LLImageTGA::s5to8bits[32] = + { + 0, 8, 16, 25, 33, 41, 49, 58, + 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, + 197, 206, 214, 222, 230, 239, 247, 255 + }; inline void LLImageTGA::decodeTruecolorPixel15( U8* dst, const U8* src ) { // We expand 5 bit data to 8 bit sample width. // The format of the 16-bit (LSB first) input word is // xRRRRRGGGGGBBBBB - U32 t = U32(src[0]) + (U32(src[1]) << 8); + U32 t = U32(src[0]) + (U32(src[1]) << 8); dst[2] = s5to8bits[t & 0x1F]; // blue t >>= 5; dst[1] = s5to8bits[t & 0x1F]; // green @@ -55,988 +55,988 @@ inline void LLImageTGA::decodeTruecolorPixel15( U8* dst, const U8* src ) dst[0] = s5to8bits[t & 0x1F]; // red } -LLImageTGA::LLImageTGA() - : LLImageFormatted(IMG_CODEC_TGA), - mColorMap( NULL ), - mColorMapStart( 0 ), - mColorMapLength( 0 ), - mColorMapBytesPerEntry( 0 ), - mIs15Bit( false ), - - mAttributeBits(0), - mColorMapDepth(0), - mColorMapIndexHi(0), - mColorMapIndexLo(0), - mColorMapLengthHi(0), - mColorMapLengthLo(0), - mColorMapType(0), - mDataOffset(0), - mHeightHi(0), - mHeightLo(0), - mIDLength(0), - mImageType(0), - mInterleave(0), - mOriginRightBit(0), - mOriginTopBit(0), - mPixelSize(0), - mWidthHi(0), - mWidthLo(0), - mXOffsetHi(0), - mXOffsetLo(0), - mYOffsetHi(0), - mYOffsetLo(0) +LLImageTGA::LLImageTGA() + : LLImageFormatted(IMG_CODEC_TGA), + mColorMap( NULL ), + mColorMapStart( 0 ), + mColorMapLength( 0 ), + mColorMapBytesPerEntry( 0 ), + mIs15Bit( false ), + + mAttributeBits(0), + mColorMapDepth(0), + mColorMapIndexHi(0), + mColorMapIndexLo(0), + mColorMapLengthHi(0), + mColorMapLengthLo(0), + mColorMapType(0), + mDataOffset(0), + mHeightHi(0), + mHeightLo(0), + mIDLength(0), + mImageType(0), + mInterleave(0), + mOriginRightBit(0), + mOriginTopBit(0), + mPixelSize(0), + mWidthHi(0), + mWidthLo(0), + mXOffsetHi(0), + mXOffsetLo(0), + mYOffsetHi(0), + mYOffsetLo(0) { } -LLImageTGA::LLImageTGA(const std::string& file_name) - : LLImageFormatted(IMG_CODEC_TGA), - mColorMap( NULL ), - mColorMapStart( 0 ), - mColorMapLength( 0 ), - mColorMapBytesPerEntry( 0 ), - mIs15Bit( false ) +LLImageTGA::LLImageTGA(const std::string& file_name) + : LLImageFormatted(IMG_CODEC_TGA), + mColorMap( NULL ), + mColorMapStart( 0 ), + mColorMapLength( 0 ), + mColorMapBytesPerEntry( 0 ), + mIs15Bit( false ) { - loadFile(file_name); + loadFile(file_name); } LLImageTGA::~LLImageTGA() { - delete [] mColorMap; + delete [] mColorMap; } bool LLImageTGA::updateData() { - resetLastError(); - - // Check to make sure that this instance has been initialized with data - if (!getData() || (0 == getDataSize())) - { - setLastError("LLImageTGA uninitialized"); - return false; - } - - // Pull image information from the header... - U8 flags; - U8 junk[256]; - - /**************************************************************************** - ** - ** For more information about the original Truevision TGA(tm) file format, - ** or for additional information about the new extensions to the - ** Truevision TGA file, refer to the "Truevision TGA File Format - ** Specification Version 2.0" available from Truevision or your - ** Truevision dealer. - ** - ** FILE STRUCTURE FOR THE ORIGINAL TRUEVISION TGA FILE - ** FIELD 1 : NUMBER OF CHARACTERS IN ID FIELD (1 BYTES) - ** FIELD 2 : COLOR MAP TYPE (1 BYTES) - ** FIELD 3 : IMAGE TYPE CODE (1 BYTES) - ** = 0 NO IMAGE DATA INCLUDED - ** = (0001) 1 UNCOMPRESSED, COLOR-MAPPED IMAGE - ** = (0010) 2 UNCOMPRESSED, TRUE-COLOR IMAGE - ** = (0011) 3 UNCOMPRESSED, BLACK AND WHITE IMAGE - ** = (1001) 9 RUN-LENGTH ENCODED COLOR-MAPPED IMAGE - ** = (1010) 10 RUN-LENGTH ENCODED TRUE-COLOR IMAGE - ** = (1011) 11 RUN-LENGTH ENCODED BLACK AND WHITE IMAGE - ** FIELD 4 : COLOR MAP SPECIFICATION (5 BYTES) - ** 4.1 : COLOR MAP ORIGIN (2 BYTES) - ** 4.2 : COLOR MAP LENGTH (2 BYTES) - ** 4.3 : COLOR MAP ENTRY SIZE (2 BYTES) - ** FIELD 5 : IMAGE SPECIFICATION (10 BYTES) - ** 5.1 : X-ORIGIN OF IMAGE (2 BYTES) - ** 5.2 : Y-ORIGIN OF IMAGE (2 BYTES) - ** 5.3 : WIDTH OF IMAGE (2 BYTES) - ** 5.4 : HEIGHT OF IMAGE (2 BYTES) - ** 5.5 : IMAGE PIXEL SIZE (1 BYTE) - ** 5.6 : IMAGE DESCRIPTOR BYTE (1 BYTE) - ** FIELD 6 : IMAGE ID FIELD (LENGTH SPECIFIED BY FIELD 1) - ** FIELD 7 : COLOR MAP DATA (BIT WIDTH SPECIFIED BY FIELD 4.3 AND - ** NUMBER OF COLOR MAP ENTRIES SPECIFIED IN FIELD 4.2) - ** FIELD 8 : IMAGE DATA FIELD (WIDTH AND HEIGHT SPECIFIED IN - ** FIELD 5.3 AND 5.4) - ****************************************************************************/ - - mDataOffset = 0; - mIDLength = *(getData()+mDataOffset++); - mColorMapType = *(getData()+mDataOffset++); - mImageType = *(getData()+mDataOffset++); - mColorMapIndexLo = *(getData()+mDataOffset++); - mColorMapIndexHi = *(getData()+mDataOffset++); - mColorMapLengthLo = *(getData()+mDataOffset++); - mColorMapLengthHi = *(getData()+mDataOffset++); - mColorMapDepth = *(getData()+mDataOffset++); - mXOffsetLo = *(getData()+mDataOffset++); - mXOffsetHi = *(getData()+mDataOffset++); - mYOffsetLo = *(getData()+mDataOffset++); - mYOffsetHi = *(getData()+mDataOffset++); - mWidthLo = *(getData()+mDataOffset++); - mWidthHi = *(getData()+mDataOffset++); - mHeightLo = *(getData()+mDataOffset++); - mHeightHi = *(getData()+mDataOffset++); - mPixelSize = *(getData()+mDataOffset++); - flags = *(getData()+mDataOffset++); - mAttributeBits = flags & 0xf; - mOriginRightBit = (flags & 0x10) >> 4; - mOriginTopBit = (flags & 0x20) >> 5; - mInterleave = (flags & 0xc0) >> 6; - - switch( mImageType ) - { - case 0: - // No image data included in file - setLastError("Unable to load file. TGA file contains no image data."); - return false; - case 1: - // Colormapped uncompressed - if( 8 != mPixelSize ) - { - setLastError("Unable to load file. Colormapped images must have 8 bits per pixel."); - return false; - } - break; - case 2: - // Truecolor uncompressed - break; - case 3: - // Monochrome uncompressed - if( 8 != mPixelSize ) - { - setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); - return false; - } - break; - case 9: - // Colormapped, RLE - break; - case 10: - // Truecolor, RLE - break; - case 11: - // Monochrome, RLE - if( 8 != mPixelSize ) - { - setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); - return false; - } - break; - default: - setLastError("Unable to load file. Unrecoginzed TGA image type."); - return false; - } - - // discard the ID field, if any - if (mIDLength) - { - memcpy(junk, getData()+mDataOffset, mIDLength); /* Flawfinder: ignore */ - mDataOffset += mIDLength; - } - - // check to see if there's a colormap since even rgb files can have them - S32 color_map_bytes = 0; - if( (1 == mColorMapType) && (mColorMapDepth > 0) ) - { - mColorMapStart = (S32(mColorMapIndexHi) << 8) + mColorMapIndexLo; - mColorMapLength = (S32(mColorMapLengthHi) << 8) + mColorMapLengthLo; - - if( mColorMapDepth > 24 ) - { - mColorMapBytesPerEntry = 4; - } - else - if( mColorMapDepth > 16 ) - { - mColorMapBytesPerEntry = 3; - } - else - if( mColorMapDepth > 8 ) - { - mColorMapBytesPerEntry = 2; - } - else - { - mColorMapBytesPerEntry = 1; - } - color_map_bytes = mColorMapLength * mColorMapBytesPerEntry; - - // Note: although it's legal for TGA files to have color maps and not use them - // (some programs actually do this and use the color map for other ends), we'll - // only allocate memory for one if _we_ intend to use it. - if ( (1 == mImageType) || (9 == mImageType) ) - { - mColorMap = new(std::nothrow) U8[ color_map_bytes ]; - if (!mColorMap) - { + resetLastError(); + + // Check to make sure that this instance has been initialized with data + if (!getData() || (0 == getDataSize())) + { + setLastError("LLImageTGA uninitialized"); + return false; + } + + // Pull image information from the header... + U8 flags; + U8 junk[256]; + + /**************************************************************************** + ** + ** For more information about the original Truevision TGA(tm) file format, + ** or for additional information about the new extensions to the + ** Truevision TGA file, refer to the "Truevision TGA File Format + ** Specification Version 2.0" available from Truevision or your + ** Truevision dealer. + ** + ** FILE STRUCTURE FOR THE ORIGINAL TRUEVISION TGA FILE + ** FIELD 1 : NUMBER OF CHARACTERS IN ID FIELD (1 BYTES) + ** FIELD 2 : COLOR MAP TYPE (1 BYTES) + ** FIELD 3 : IMAGE TYPE CODE (1 BYTES) + ** = 0 NO IMAGE DATA INCLUDED + ** = (0001) 1 UNCOMPRESSED, COLOR-MAPPED IMAGE + ** = (0010) 2 UNCOMPRESSED, TRUE-COLOR IMAGE + ** = (0011) 3 UNCOMPRESSED, BLACK AND WHITE IMAGE + ** = (1001) 9 RUN-LENGTH ENCODED COLOR-MAPPED IMAGE + ** = (1010) 10 RUN-LENGTH ENCODED TRUE-COLOR IMAGE + ** = (1011) 11 RUN-LENGTH ENCODED BLACK AND WHITE IMAGE + ** FIELD 4 : COLOR MAP SPECIFICATION (5 BYTES) + ** 4.1 : COLOR MAP ORIGIN (2 BYTES) + ** 4.2 : COLOR MAP LENGTH (2 BYTES) + ** 4.3 : COLOR MAP ENTRY SIZE (2 BYTES) + ** FIELD 5 : IMAGE SPECIFICATION (10 BYTES) + ** 5.1 : X-ORIGIN OF IMAGE (2 BYTES) + ** 5.2 : Y-ORIGIN OF IMAGE (2 BYTES) + ** 5.3 : WIDTH OF IMAGE (2 BYTES) + ** 5.4 : HEIGHT OF IMAGE (2 BYTES) + ** 5.5 : IMAGE PIXEL SIZE (1 BYTE) + ** 5.6 : IMAGE DESCRIPTOR BYTE (1 BYTE) + ** FIELD 6 : IMAGE ID FIELD (LENGTH SPECIFIED BY FIELD 1) + ** FIELD 7 : COLOR MAP DATA (BIT WIDTH SPECIFIED BY FIELD 4.3 AND + ** NUMBER OF COLOR MAP ENTRIES SPECIFIED IN FIELD 4.2) + ** FIELD 8 : IMAGE DATA FIELD (WIDTH AND HEIGHT SPECIFIED IN + ** FIELD 5.3 AND 5.4) + ****************************************************************************/ + + mDataOffset = 0; + mIDLength = *(getData()+mDataOffset++); + mColorMapType = *(getData()+mDataOffset++); + mImageType = *(getData()+mDataOffset++); + mColorMapIndexLo = *(getData()+mDataOffset++); + mColorMapIndexHi = *(getData()+mDataOffset++); + mColorMapLengthLo = *(getData()+mDataOffset++); + mColorMapLengthHi = *(getData()+mDataOffset++); + mColorMapDepth = *(getData()+mDataOffset++); + mXOffsetLo = *(getData()+mDataOffset++); + mXOffsetHi = *(getData()+mDataOffset++); + mYOffsetLo = *(getData()+mDataOffset++); + mYOffsetHi = *(getData()+mDataOffset++); + mWidthLo = *(getData()+mDataOffset++); + mWidthHi = *(getData()+mDataOffset++); + mHeightLo = *(getData()+mDataOffset++); + mHeightHi = *(getData()+mDataOffset++); + mPixelSize = *(getData()+mDataOffset++); + flags = *(getData()+mDataOffset++); + mAttributeBits = flags & 0xf; + mOriginRightBit = (flags & 0x10) >> 4; + mOriginTopBit = (flags & 0x20) >> 5; + mInterleave = (flags & 0xc0) >> 6; + + switch( mImageType ) + { + case 0: + // No image data included in file + setLastError("Unable to load file. TGA file contains no image data."); + return false; + case 1: + // Colormapped uncompressed + if( 8 != mPixelSize ) + { + setLastError("Unable to load file. Colormapped images must have 8 bits per pixel."); + return false; + } + break; + case 2: + // Truecolor uncompressed + break; + case 3: + // Monochrome uncompressed + if( 8 != mPixelSize ) + { + setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); + return false; + } + break; + case 9: + // Colormapped, RLE + break; + case 10: + // Truecolor, RLE + break; + case 11: + // Monochrome, RLE + if( 8 != mPixelSize ) + { + setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); + return false; + } + break; + default: + setLastError("Unable to load file. Unrecoginzed TGA image type."); + return false; + } + + // discard the ID field, if any + if (mIDLength) + { + memcpy(junk, getData()+mDataOffset, mIDLength); /* Flawfinder: ignore */ + mDataOffset += mIDLength; + } + + // check to see if there's a colormap since even rgb files can have them + S32 color_map_bytes = 0; + if( (1 == mColorMapType) && (mColorMapDepth > 0) ) + { + mColorMapStart = (S32(mColorMapIndexHi) << 8) + mColorMapIndexLo; + mColorMapLength = (S32(mColorMapLengthHi) << 8) + mColorMapLengthLo; + + if( mColorMapDepth > 24 ) + { + mColorMapBytesPerEntry = 4; + } + else + if( mColorMapDepth > 16 ) + { + mColorMapBytesPerEntry = 3; + } + else + if( mColorMapDepth > 8 ) + { + mColorMapBytesPerEntry = 2; + } + else + { + mColorMapBytesPerEntry = 1; + } + color_map_bytes = mColorMapLength * mColorMapBytesPerEntry; + + // Note: although it's legal for TGA files to have color maps and not use them + // (some programs actually do this and use the color map for other ends), we'll + // only allocate memory for one if _we_ intend to use it. + if ( (1 == mImageType) || (9 == mImageType) ) + { + mColorMap = new(std::nothrow) U8[ color_map_bytes ]; + if (!mColorMap) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Out of Memory in bool LLImageTGA::updateData()" << LL_ENDL; - return false; - } - memcpy( mColorMap, getData() + mDataOffset, color_map_bytes ); /* Flawfinder: ignore */ - } - - mDataOffset += color_map_bytes; - } - - // heights are read as bytes to prevent endian problems - S32 height = (S32(mHeightHi) << 8) + mHeightLo; - S32 width = (S32(mWidthHi) << 8) + mWidthLo; - - // make sure that it's a pixel format that we understand - S32 bits_per_pixel; - if( mColorMap ) - { - bits_per_pixel = mColorMapDepth; - } - else - { - bits_per_pixel = mPixelSize; - } - - S32 components; - switch(bits_per_pixel) - { - case 24: - components = 3; - break; - case 32: - components = 4; -// Don't enforce this. ACDSee doesn't bother to set the attributes bits correctly. Arrgh! -// if( mAttributeBits != 8 ) -// { -// setLastError("Unable to load file. 32 bit TGA image does not have 8 bits of alpha."); -// return false; -// } - mAttributeBits = 8; - break; - case 15: - case 16: - components = 3; - mIs15Bit = true; // 16th bit is used for Targa hardware interupts and is ignored. - break; - case 8: - components = 1; - break; - default: - setLastError("Unable to load file. Unknown pixel size."); - return false; - } - setSize(width, height, components); - - return true; + LL_ERRS() << "Out of Memory in bool LLImageTGA::updateData()" << LL_ENDL; + return false; + } + memcpy( mColorMap, getData() + mDataOffset, color_map_bytes ); /* Flawfinder: ignore */ + } + + mDataOffset += color_map_bytes; + } + + // heights are read as bytes to prevent endian problems + S32 height = (S32(mHeightHi) << 8) + mHeightLo; + S32 width = (S32(mWidthHi) << 8) + mWidthLo; + + // make sure that it's a pixel format that we understand + S32 bits_per_pixel; + if( mColorMap ) + { + bits_per_pixel = mColorMapDepth; + } + else + { + bits_per_pixel = mPixelSize; + } + + S32 components; + switch(bits_per_pixel) + { + case 24: + components = 3; + break; + case 32: + components = 4; +// Don't enforce this. ACDSee doesn't bother to set the attributes bits correctly. Arrgh! +// if( mAttributeBits != 8 ) +// { +// setLastError("Unable to load file. 32 bit TGA image does not have 8 bits of alpha."); +// return false; +// } + mAttributeBits = 8; + break; + case 15: + case 16: + components = 3; + mIs15Bit = true; // 16th bit is used for Targa hardware interupts and is ignored. + break; + case 8: + components = 1; + break; + default: + setLastError("Unable to load file. Unknown pixel size."); + return false; + } + setSize(width, height, components); + + return true; } bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time) { - llassert_always(raw_image); - - // Check to make sure that this instance has been initialized with data - if (!getData() || (0 == getDataSize())) - { - setLastError("LLImageTGA trying to decode an image with no data!"); - return false; - } - - // Copy everything after the header. - - if( !raw_image->resize(getWidth(), getHeight(), getComponents())) - { - setLastError("LLImageTGA::out of memory"); - return false; - } - - if( (getComponents() != 1) && - (getComponents() != 3) && - (getComponents() != 4) ) - { - setLastError("TGA images with a number of components other than 1, 3, and 4 are not supported."); - return false; - } - - if( raw_image->isBufferInvalid()) - { - setLastError("LLImageTGA::out of memory"); - return false; - } - - if( mOriginRightBit ) - { - setLastError("TGA images with origin on right side are not supported."); - return false; - } - - bool flipped = (mOriginTopBit != 0); - bool rle_compressed = ((mImageType & 0x08) != 0); - - if( mColorMap ) - { - return decodeColorMap( raw_image, rle_compressed, flipped ); - } - else - { - return decodeTruecolor( raw_image, rle_compressed, flipped ); - } + llassert_always(raw_image); + + // Check to make sure that this instance has been initialized with data + if (!getData() || (0 == getDataSize())) + { + setLastError("LLImageTGA trying to decode an image with no data!"); + return false; + } + + // Copy everything after the header. + + if( !raw_image->resize(getWidth(), getHeight(), getComponents())) + { + setLastError("LLImageTGA::out of memory"); + return false; + } + + if( (getComponents() != 1) && + (getComponents() != 3) && + (getComponents() != 4) ) + { + setLastError("TGA images with a number of components other than 1, 3, and 4 are not supported."); + return false; + } + + if( raw_image->isBufferInvalid()) + { + setLastError("LLImageTGA::out of memory"); + return false; + } + + if( mOriginRightBit ) + { + setLastError("TGA images with origin on right side are not supported."); + return false; + } + + bool flipped = (mOriginTopBit != 0); + bool rle_compressed = ((mImageType & 0x08) != 0); + + if( mColorMap ) + { + return decodeColorMap( raw_image, rle_compressed, flipped ); + } + else + { + return decodeTruecolor( raw_image, rle_compressed, flipped ); + } } bool LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, bool rle, bool flipped ) { - bool success = false; - bool alpha_opaque = false; - if( rle ) - { - - switch( getComponents() ) - { - case 1: - success = decodeTruecolorRle8( raw_image ); - break; - case 3: - if( mIs15Bit ) - { - success = decodeTruecolorRle15( raw_image ); - } - else - { - success = decodeTruecolorRle24( raw_image ); - } - break; - case 4: - success = decodeTruecolorRle32( raw_image, alpha_opaque ); - if (alpha_opaque) - { - // alpha was entirely opaque - // convert to 24 bit image - LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); - if (compacted_image->isBufferInvalid()) - { - success = false; - break; - } - compacted_image->copy(raw_image); - raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); - raw_image->copy(compacted_image); - } - break; - } - } - else - { - bool alpha_opaque; - success = decodeTruecolorNonRle( raw_image, alpha_opaque ); - if (alpha_opaque && raw_image->getComponents() == 4) - { - // alpha was entirely opaque - // convert to 24 bit image - LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); - if (compacted_image->isBufferInvalid()) - { - success = false; - } - else - { - compacted_image->copy(raw_image); - raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); - raw_image->copy(compacted_image); - } - } - } - - if( success && flipped ) - { - // This works because the Targa definition requires that RLE blocks never - // encode pixels from more than one scanline. - // (On the other hand, it's not as fast as writing separate flipped versions as - // we did with TruecolorNonRle.) - raw_image->verticalFlip(); - } - - return success; + bool success = false; + bool alpha_opaque = false; + if( rle ) + { + + switch( getComponents() ) + { + case 1: + success = decodeTruecolorRle8( raw_image ); + break; + case 3: + if( mIs15Bit ) + { + success = decodeTruecolorRle15( raw_image ); + } + else + { + success = decodeTruecolorRle24( raw_image ); + } + break; + case 4: + success = decodeTruecolorRle32( raw_image, alpha_opaque ); + if (alpha_opaque) + { + // alpha was entirely opaque + // convert to 24 bit image + LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); + if (compacted_image->isBufferInvalid()) + { + success = false; + break; + } + compacted_image->copy(raw_image); + raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); + raw_image->copy(compacted_image); + } + break; + } + } + else + { + bool alpha_opaque; + success = decodeTruecolorNonRle( raw_image, alpha_opaque ); + if (alpha_opaque && raw_image->getComponents() == 4) + { + // alpha was entirely opaque + // convert to 24 bit image + LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); + if (compacted_image->isBufferInvalid()) + { + success = false; + } + else + { + compacted_image->copy(raw_image); + raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); + raw_image->copy(compacted_image); + } + } + } + + if( success && flipped ) + { + // This works because the Targa definition requires that RLE blocks never + // encode pixels from more than one scanline. + // (On the other hand, it's not as fast as writing separate flipped versions as + // we did with TruecolorNonRle.) + raw_image->verticalFlip(); + } + + return success; } bool LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, bool &alpha_opaque ) { - alpha_opaque = true; - - // Origin is the bottom left - U8* dst = raw_image->getData(); - U8* src = getData() + mDataOffset; - - S32 pixels = getWidth() * getHeight(); - - if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset) - { //here we have situation when data size in src less than actually needed - return false; - } - - if (getComponents() == 4) - { - while( pixels-- ) - { - // Our data is stored in RGBA. TGA stores them as BGRA (little-endian ARGB) - dst[0] = src[2]; // Red - dst[1] = src[1]; // Green - dst[2] = src[0]; // Blue - dst[3] = src[3]; // Alpha - if (dst[3] != 255) - { - alpha_opaque = false; - } - dst += 4; - src += 4; - } - } - else if (getComponents() == 3) - { - if( mIs15Bit ) - { - while( pixels-- ) - { - decodeTruecolorPixel15( dst, src ); - dst += 3; - src += 2; - } - } - else - { - while( pixels-- ) - { - dst[0] = src[2]; // Red - dst[1] = src[1]; // Green - dst[2] = src[0]; // Blue - dst += 3; - src += 3; - } - } - } - else if (getComponents() == 1) - { - memcpy(dst, src, pixels); /* Flawfinder: ignore */ - } - - return true; + alpha_opaque = true; + + // Origin is the bottom left + U8* dst = raw_image->getData(); + U8* src = getData() + mDataOffset; + + S32 pixels = getWidth() * getHeight(); + + if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset) + { //here we have situation when data size in src less than actually needed + return false; + } + + if (getComponents() == 4) + { + while( pixels-- ) + { + // Our data is stored in RGBA. TGA stores them as BGRA (little-endian ARGB) + dst[0] = src[2]; // Red + dst[1] = src[1]; // Green + dst[2] = src[0]; // Blue + dst[3] = src[3]; // Alpha + if (dst[3] != 255) + { + alpha_opaque = false; + } + dst += 4; + src += 4; + } + } + else if (getComponents() == 3) + { + if( mIs15Bit ) + { + while( pixels-- ) + { + decodeTruecolorPixel15( dst, src ); + dst += 3; + src += 2; + } + } + else + { + while( pixels-- ) + { + dst[0] = src[2]; // Red + dst[1] = src[1]; // Green + dst[2] = src[0]; // Blue + dst += 3; + src += 3; + } + } + } + else if (getComponents() == 1) + { + memcpy(dst, src, pixels); /* Flawfinder: ignore */ + } + + return true; } void LLImageTGA::decodeColorMapPixel8( U8* dst, const U8* src ) { - S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); - dst[0] = mColorMap[ index ]; + S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); + dst[0] = mColorMap[ index ]; } void LLImageTGA::decodeColorMapPixel15( U8* dst, const U8* src ) { - S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); - decodeTruecolorPixel15( dst, mColorMap + 2 * index ); + S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); + decodeTruecolorPixel15( dst, mColorMap + 2 * index ); } void LLImageTGA::decodeColorMapPixel24( U8* dst, const U8* src ) { - S32 index = 3 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); - dst[0] = mColorMap[ index + 2 ]; // Red - dst[1] = mColorMap[ index + 1 ]; // Green - dst[2] = mColorMap[ index + 0 ]; // Blue + S32 index = 3 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); + dst[0] = mColorMap[ index + 2 ]; // Red + dst[1] = mColorMap[ index + 1 ]; // Green + dst[2] = mColorMap[ index + 0 ]; // Blue } void LLImageTGA::decodeColorMapPixel32( U8* dst, const U8* src ) { - S32 index = 4 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); - dst[0] = mColorMap[ index + 2 ]; // Red - dst[1] = mColorMap[ index + 1 ]; // Green - dst[2] = mColorMap[ index + 0 ]; // Blue - dst[3] = mColorMap[ index + 3 ]; // Alpha + S32 index = 4 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); + dst[0] = mColorMap[ index + 2 ]; // Red + dst[1] = mColorMap[ index + 1 ]; // Green + dst[2] = mColorMap[ index + 0 ]; // Blue + dst[3] = mColorMap[ index + 3 ]; // Alpha } bool LLImageTGA::decodeColorMap( LLImageRaw* raw_image, bool rle, bool flipped ) { - // If flipped, origin is the top left. Need to reverse the order of the rows. - // Otherwise the origin is the bottom left. - - if( 8 != mPixelSize ) - { - return false; - } - - U8* src = getData() + mDataOffset; - U8* dst = raw_image->getData(); // start from the top - - void (LLImageTGA::*pixel_decoder)( U8*, const U8* ); - - switch( mColorMapBytesPerEntry ) - { - case 1: pixel_decoder = &LLImageTGA::decodeColorMapPixel8; break; - case 2: pixel_decoder = &LLImageTGA::decodeColorMapPixel15; break; - case 3: pixel_decoder = &LLImageTGA::decodeColorMapPixel24; break; - case 4: pixel_decoder = &LLImageTGA::decodeColorMapPixel32; break; - default: llassert(0); return false; - } - - if( rle ) - { - U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); - while( dst <= last_dst ) - { - // Read RLE block header - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - do - { - (this->*pixel_decoder)( dst, src ); - dst += getComponents(); - block_pixel_count--; - } - while( block_pixel_count > 0 ); - src++; - } - else - { - // Unencoded block - do - { - (this->*pixel_decoder)( dst, src ); - dst += getComponents(); - src++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - - raw_image->verticalFlip(); - } - else - { - S32 src_row_bytes = getWidth(); - S32 dst_row_bytes = getWidth() * getComponents(); - - if( flipped ) - { - U8* src_last_row_start = src + (getHeight() - 1) * src_row_bytes; - src = src_last_row_start; // start from the bottom - src_row_bytes *= -1; - } - - - S32 i; - S32 j; - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( i = 0, j = 0; j < getWidth(); i += getComponents(), j++ ) - { - (this->*pixel_decoder)( dst + i, src + j ); - } - - dst += dst_row_bytes; - src += src_row_bytes; - } - } - - return true; + // If flipped, origin is the top left. Need to reverse the order of the rows. + // Otherwise the origin is the bottom left. + + if( 8 != mPixelSize ) + { + return false; + } + + U8* src = getData() + mDataOffset; + U8* dst = raw_image->getData(); // start from the top + + void (LLImageTGA::*pixel_decoder)( U8*, const U8* ); + + switch( mColorMapBytesPerEntry ) + { + case 1: pixel_decoder = &LLImageTGA::decodeColorMapPixel8; break; + case 2: pixel_decoder = &LLImageTGA::decodeColorMapPixel15; break; + case 3: pixel_decoder = &LLImageTGA::decodeColorMapPixel24; break; + case 4: pixel_decoder = &LLImageTGA::decodeColorMapPixel32; break; + default: llassert(0); return false; + } + + if( rle ) + { + U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); + while( dst <= last_dst ) + { + // Read RLE block header + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + do + { + (this->*pixel_decoder)( dst, src ); + dst += getComponents(); + block_pixel_count--; + } + while( block_pixel_count > 0 ); + src++; + } + else + { + // Unencoded block + do + { + (this->*pixel_decoder)( dst, src ); + dst += getComponents(); + src++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + + raw_image->verticalFlip(); + } + else + { + S32 src_row_bytes = getWidth(); + S32 dst_row_bytes = getWidth() * getComponents(); + + if( flipped ) + { + U8* src_last_row_start = src + (getHeight() - 1) * src_row_bytes; + src = src_last_row_start; // start from the bottom + src_row_bytes *= -1; + } + + + S32 i; + S32 j; + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( i = 0, j = 0; j < getWidth(); i += getComponents(), j++ ) + { + (this->*pixel_decoder)( dst + i, src + j ); + } + + dst += dst_row_bytes; + src += src_row_bytes; + } + } + + return true; } bool LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time) { - llassert_always(raw_image); - - deleteData(); - - setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); - - // Data from header - mIDLength = 0; // Length of identifier string - mColorMapType = 0; // 0 = No Map - - // Supported: 2 = Uncompressed true color, 3 = uncompressed monochrome without colormap - switch( getComponents() ) - { - case 1: - mImageType = 3; - break; - case 2: // Interpret as intensity plus alpha - case 3: - case 4: - mImageType = 2; - break; - default: - return false; - } - - // Color map stuff (unsupported) - mColorMapIndexLo = 0; // First color map entry (low order byte) - mColorMapIndexHi = 0; // First color map entry (high order byte) - mColorMapLengthLo = 0; // Color map length (low order byte) - mColorMapLengthHi = 0; // Color map length (high order byte) - mColorMapDepth = 0; // Size of color map entry (15, 16, 24, or 32 bits) - - // Image offset relative to origin. - mXOffsetLo = 0; // X offset from origin (low order byte) - mXOffsetHi = 0; // X offset from origin (hi order byte) - mYOffsetLo = 0; // Y offset from origin (low order byte) - mYOffsetHi = 0; // Y offset from origin (hi order byte) - - // Height and width - mWidthLo = U8(getWidth() & 0xFF); // Width (low order byte) - mWidthHi = U8((getWidth() >> 8) & 0xFF); // Width (hi order byte) - mHeightLo = U8(getHeight() & 0xFF); // Height (low order byte) - mHeightHi = U8((getHeight() >> 8) & 0xFF); // Height (hi order byte) - - S32 bytes_per_pixel; - switch( getComponents() ) - { - case 1: - bytes_per_pixel = 1; - break; - case 3: - bytes_per_pixel = 3; - break; - case 2: // Interpret as intensity plus alpha. Store as RGBA. - case 4: - bytes_per_pixel = 4; - break; - default: - return false; - } - mPixelSize = U8(bytes_per_pixel * 8); // 8, 16, 24, 32 bits per pixel - - mAttributeBits = (4 == bytes_per_pixel) ? 8 : 0; // 4 bits: number of attribute bits (alpha) per pixel - mOriginRightBit = 0; // 1 bit: origin, 0 = left, 1 = right - mOriginTopBit = 0; // 1 bit: origin, 0 = bottom, 1 = top - mInterleave = 0; // 2 bits: interleaved flag, 0 = none, 1 = interleaved 2, 2 = interleaved 4 - - - const S32 TGA_HEADER_SIZE = 18; - const S32 COLOR_MAP_SIZE = 0; - mDataOffset = TGA_HEADER_SIZE + mIDLength + COLOR_MAP_SIZE; // Offset from start of data to the actual header. - - S32 pixels = getWidth() * getHeight(); - S32 datasize = mDataOffset + bytes_per_pixel * pixels; - U8* dst = allocateData(datasize); - - // Write header - *(dst++) = mIDLength; - *(dst++) = mColorMapType; - *(dst++) = mImageType; - *(dst++) = mColorMapIndexLo; - *(dst++) = mColorMapIndexHi; - *(dst++) = mColorMapLengthLo; - *(dst++) = mColorMapLengthHi; - *(dst++) = mColorMapDepth; - *(dst++) = mXOffsetLo; - *(dst++) = mXOffsetHi; - *(dst++) = mYOffsetLo; - *(dst++) = mYOffsetHi; - *(dst++) = mWidthLo; - *(dst++) = mWidthHi; - *(dst++) = mHeightLo; - *(dst++) = mHeightHi; - *(dst++) = mPixelSize; - *(dst++) = - ((mInterleave & 3) << 5) | - ((mOriginTopBit & 1) << 4) | - ((mOriginRightBit & 1) << 3) | - ((mAttributeBits & 0xF) << 0); - - // Write pixels - const U8* src = raw_image->getData(); - llassert( dst == getData() + mDataOffset ); - S32 i = 0; - S32 j = 0; - switch( getComponents() ) - { - case 1: - memcpy( dst, src, bytes_per_pixel * pixels ); /* Flawfinder: ignore */ - break; - - case 2: - while( pixels-- ) - { - dst[i + 0] = src[j + 0]; // intensity - dst[i + 1] = src[j + 0]; // intensity - dst[i + 2] = src[j + 0]; // intensity - dst[i + 3] = src[j + 1]; // alpha - i += 4; - j += 2; - } - break; - - case 3: - while( pixels-- ) - { - dst[i + 0] = src[i + 2]; // blue - dst[i + 1] = src[i + 1]; // green - dst[i + 2] = src[i + 0]; // red - i += 3; - } - break; - - case 4: - while( pixels-- ) - { - dst[i + 0] = src[i + 2]; // blue - dst[i + 1] = src[i + 1]; // green - dst[i + 2] = src[i + 0]; // red - dst[i + 3] = src[i + 3]; // alpha - i += 4; - } - break; - } - - return true; + llassert_always(raw_image); + + deleteData(); + + setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); + + // Data from header + mIDLength = 0; // Length of identifier string + mColorMapType = 0; // 0 = No Map + + // Supported: 2 = Uncompressed true color, 3 = uncompressed monochrome without colormap + switch( getComponents() ) + { + case 1: + mImageType = 3; + break; + case 2: // Interpret as intensity plus alpha + case 3: + case 4: + mImageType = 2; + break; + default: + return false; + } + + // Color map stuff (unsupported) + mColorMapIndexLo = 0; // First color map entry (low order byte) + mColorMapIndexHi = 0; // First color map entry (high order byte) + mColorMapLengthLo = 0; // Color map length (low order byte) + mColorMapLengthHi = 0; // Color map length (high order byte) + mColorMapDepth = 0; // Size of color map entry (15, 16, 24, or 32 bits) + + // Image offset relative to origin. + mXOffsetLo = 0; // X offset from origin (low order byte) + mXOffsetHi = 0; // X offset from origin (hi order byte) + mYOffsetLo = 0; // Y offset from origin (low order byte) + mYOffsetHi = 0; // Y offset from origin (hi order byte) + + // Height and width + mWidthLo = U8(getWidth() & 0xFF); // Width (low order byte) + mWidthHi = U8((getWidth() >> 8) & 0xFF); // Width (hi order byte) + mHeightLo = U8(getHeight() & 0xFF); // Height (low order byte) + mHeightHi = U8((getHeight() >> 8) & 0xFF); // Height (hi order byte) + + S32 bytes_per_pixel; + switch( getComponents() ) + { + case 1: + bytes_per_pixel = 1; + break; + case 3: + bytes_per_pixel = 3; + break; + case 2: // Interpret as intensity plus alpha. Store as RGBA. + case 4: + bytes_per_pixel = 4; + break; + default: + return false; + } + mPixelSize = U8(bytes_per_pixel * 8); // 8, 16, 24, 32 bits per pixel + + mAttributeBits = (4 == bytes_per_pixel) ? 8 : 0; // 4 bits: number of attribute bits (alpha) per pixel + mOriginRightBit = 0; // 1 bit: origin, 0 = left, 1 = right + mOriginTopBit = 0; // 1 bit: origin, 0 = bottom, 1 = top + mInterleave = 0; // 2 bits: interleaved flag, 0 = none, 1 = interleaved 2, 2 = interleaved 4 + + + const S32 TGA_HEADER_SIZE = 18; + const S32 COLOR_MAP_SIZE = 0; + mDataOffset = TGA_HEADER_SIZE + mIDLength + COLOR_MAP_SIZE; // Offset from start of data to the actual header. + + S32 pixels = getWidth() * getHeight(); + S32 datasize = mDataOffset + bytes_per_pixel * pixels; + U8* dst = allocateData(datasize); + + // Write header + *(dst++) = mIDLength; + *(dst++) = mColorMapType; + *(dst++) = mImageType; + *(dst++) = mColorMapIndexLo; + *(dst++) = mColorMapIndexHi; + *(dst++) = mColorMapLengthLo; + *(dst++) = mColorMapLengthHi; + *(dst++) = mColorMapDepth; + *(dst++) = mXOffsetLo; + *(dst++) = mXOffsetHi; + *(dst++) = mYOffsetLo; + *(dst++) = mYOffsetHi; + *(dst++) = mWidthLo; + *(dst++) = mWidthHi; + *(dst++) = mHeightLo; + *(dst++) = mHeightHi; + *(dst++) = mPixelSize; + *(dst++) = + ((mInterleave & 3) << 5) | + ((mOriginTopBit & 1) << 4) | + ((mOriginRightBit & 1) << 3) | + ((mAttributeBits & 0xF) << 0); + + // Write pixels + const U8* src = raw_image->getData(); + llassert( dst == getData() + mDataOffset ); + S32 i = 0; + S32 j = 0; + switch( getComponents() ) + { + case 1: + memcpy( dst, src, bytes_per_pixel * pixels ); /* Flawfinder: ignore */ + break; + + case 2: + while( pixels-- ) + { + dst[i + 0] = src[j + 0]; // intensity + dst[i + 1] = src[j + 0]; // intensity + dst[i + 2] = src[j + 0]; // intensity + dst[i + 3] = src[j + 1]; // alpha + i += 4; + j += 2; + } + break; + + case 3: + while( pixels-- ) + { + dst[i + 0] = src[i + 2]; // blue + dst[i + 1] = src[i + 1]; // green + dst[i + 2] = src[i + 0]; // red + i += 3; + } + break; + + case 4: + while( pixels-- ) + { + dst[i + 0] = src[i + 2]; // blue + dst[i + 1] = src[i + 1]; // green + dst[i + 2] = src[i + 0]; // red + dst[i + 3] = src[i + 3]; // alpha + i += 4; + } + break; + } + + return true; } bool LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, bool &alpha_opaque ) { - llassert( getComponents() == 4 ); - alpha_opaque = true; - - U8* dst = raw_image->getData(); - U32* dst_pixels = (U32*) dst; - - U8* src = getData() + mDataOffset; - U8* last_src = src + getDataSize(); - - U32 rgba; - U8* rgba_byte_p = (U8*) &rgba; - - U32* last_dst_pixel = dst_pixels + getHeight() * getWidth() - 1; - while( dst_pixels <= last_dst_pixel ) - { - // Read RLE block header - - if (src >= last_src) - return false; - - U8 block_header_byte = *src; - src++; - - U32 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - - if (src + 3 >= last_src) - return false; - - rgba_byte_p[0] = src[2]; - rgba_byte_p[1] = src[1]; - rgba_byte_p[2] = src[0]; - rgba_byte_p[3] = src[3]; - if (rgba_byte_p[3] != 255) - { - alpha_opaque = false; - } - - src += 4; - U32 value = rgba; - do - { - *dst_pixels = value; - dst_pixels++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - else - { - // Unencoded block - do - { - if (src + 3 >= last_src) - return false; - - ((U8*)dst_pixels)[0] = src[2]; - ((U8*)dst_pixels)[1] = src[1]; - ((U8*)dst_pixels)[2] = src[0]; - ((U8*)dst_pixels)[3] = src[3]; - if (src[3] != 255) - { - alpha_opaque = false; - } - src += 4; - dst_pixels++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - - return true; + llassert( getComponents() == 4 ); + alpha_opaque = true; + + U8* dst = raw_image->getData(); + U32* dst_pixels = (U32*) dst; + + U8* src = getData() + mDataOffset; + U8* last_src = src + getDataSize(); + + U32 rgba; + U8* rgba_byte_p = (U8*) &rgba; + + U32* last_dst_pixel = dst_pixels + getHeight() * getWidth() - 1; + while( dst_pixels <= last_dst_pixel ) + { + // Read RLE block header + + if (src >= last_src) + return false; + + U8 block_header_byte = *src; + src++; + + U32 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + + if (src + 3 >= last_src) + return false; + + rgba_byte_p[0] = src[2]; + rgba_byte_p[1] = src[1]; + rgba_byte_p[2] = src[0]; + rgba_byte_p[3] = src[3]; + if (rgba_byte_p[3] != 255) + { + alpha_opaque = false; + } + + src += 4; + U32 value = rgba; + do + { + *dst_pixels = value; + dst_pixels++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + else + { + // Unencoded block + do + { + if (src + 3 >= last_src) + return false; + + ((U8*)dst_pixels)[0] = src[2]; + ((U8*)dst_pixels)[1] = src[1]; + ((U8*)dst_pixels)[2] = src[0]; + ((U8*)dst_pixels)[3] = src[3]; + if (src[3] != 255) + { + alpha_opaque = false; + } + src += 4; + dst_pixels++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + + return true; } bool LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image ) { - llassert( getComponents() == 3 ); - llassert( mIs15Bit ); - - U8* dst = raw_image->getData(); - U8* src = getData() + mDataOffset; - - U8* last_src = src + getDataSize(); - U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); - - while( dst <= last_dst ) - { - // Read RLE block header - - if (src >= last_src) - return false; - - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - do - { - if (src + 2 >= last_src) - return false; - - decodeTruecolorPixel15( dst, src ); // slow - dst += 3; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - src += 2; - } - else - { - // Unencoded block - do - { - if (src + 2 >= last_src) - return false; - - decodeTruecolorPixel15( dst, src ); - dst += 3; - src += 2; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - - return true; + llassert( getComponents() == 3 ); + llassert( mIs15Bit ); + + U8* dst = raw_image->getData(); + U8* src = getData() + mDataOffset; + + U8* last_src = src + getDataSize(); + U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); + + while( dst <= last_dst ) + { + // Read RLE block header + + if (src >= last_src) + return false; + + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + do + { + if (src + 2 >= last_src) + return false; + + decodeTruecolorPixel15( dst, src ); // slow + dst += 3; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + src += 2; + } + else + { + // Unencoded block + do + { + if (src + 2 >= last_src) + return false; + + decodeTruecolorPixel15( dst, src ); + dst += 3; + src += 2; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + + return true; } bool LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image ) { - llassert( getComponents() == 3 ); - - U8* dst = raw_image->getData(); - U8* src = getData() + mDataOffset; - - U8* last_src = src + getDataSize(); - U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); - - while( dst <= last_dst ) - { - // Read RLE block header - - if (src >= last_src) - return false; - - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - do - { - if (src + 2 >= last_src) - return false; - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - dst += 3; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - src += 3; - } - else - { - // Unencoded block - do - { - if (src + 2 >= last_src) - return false; - - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - dst += 3; - src += 3; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - - return true; + llassert( getComponents() == 3 ); + + U8* dst = raw_image->getData(); + U8* src = getData() + mDataOffset; + + U8* last_src = src + getDataSize(); + U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); + + while( dst <= last_dst ) + { + // Read RLE block header + + if (src >= last_src) + return false; + + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + do + { + if (src + 2 >= last_src) + return false; + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + dst += 3; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + src += 3; + } + else + { + // Unencoded block + do + { + if (src + 2 >= last_src) + return false; + + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + dst += 3; + src += 3; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + + return true; } bool LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image ) { - llassert( getComponents() == 1 ); - - U8* dst = raw_image->getData(); - U8* src = getData() + mDataOffset; - - U8* last_src = src + getDataSize(); - U8* last_dst = dst + getHeight() * getWidth() - 1; - - while( dst <= last_dst ) - { - // Read RLE block header - - if (src >= last_src) - return false; - - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - if (src >= last_src) - return false; - - // Encoded (duplicate-pixel) block - memset( dst, *src, block_pixel_count ); - dst += block_pixel_count; - src++; - } - else - { - // Unencoded block - do - { - if (src >= last_src) - return false; - - *dst = *src; - dst++; - src++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - - return true; + llassert( getComponents() == 1 ); + + U8* dst = raw_image->getData(); + U8* src = getData() + mDataOffset; + + U8* last_src = src + getDataSize(); + U8* last_dst = dst + getHeight() * getWidth() - 1; + + while( dst <= last_dst ) + { + // Read RLE block header + + if (src >= last_src) + return false; + + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + if (src >= last_src) + return false; + + // Encoded (duplicate-pixel) block + memset( dst, *src, block_pixel_count ); + dst += block_pixel_count; + src++; + } + else + { + // Unencoded block + do + { + if (src >= last_src) + return false; + + *dst = *src; + dst++; + src++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + + return true; } @@ -1044,174 +1044,174 @@ bool LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image ) // Processing happens during the decode for speed. bool LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight ) { - llassert_always(raw_image); - - // "Domain" isn't really the right word. It refers to the width of the - // ramp portion of the function that relates input and output pixel values. - // A domain of 0 gives a step function. - // - // | /---------------- - // O| / | - // u| / | - // t| / | - // p|------------------/ | - // u| | | - // t|<---------------->|<-->| - // | "offset" "domain" - // | - // --+---Input-------------------------------- - // | - - if (!getData() || (0 == getDataSize())) - { - setLastError("LLImageTGA trying to decode an image with no data!"); - return false; - } - - // Only works for unflipped monochrome RLE images - if( (getComponents() != 1) || (mImageType != 11) || mOriginTopBit || mOriginRightBit ) - { - LL_ERRS() << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << LL_ENDL; - return false; - } - - if( !raw_image->resize(getWidth(), getHeight(), getComponents()) ) - { - LL_ERRS() << "LLImageTGA: Failed to resize image" << LL_ENDL; - return false; - } - - U8* dst = raw_image->getData(); - U8* src = getData() + mDataOffset; - U8* last_dst = dst + getHeight() * getWidth() - 1; - - if( domain > 0 ) - { - // Process using a look-up table (lut) - const S32 LUT_LEN = 256; - U8 lut[LUT_LEN]; - S32 i; - - F32 scale = 1.f / domain; - F32 offset = (1.f - domain) * llclampf( 1.f - weight ); - F32 bias = -(scale * offset); - - for( i = 0; i < LUT_LEN; i++ ) - { - lut[i] = (U8)llclampb( 255.f * ( i/255.f * scale + bias ) ); - } - - while( dst <= last_dst ) - { - // Read RLE block header - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - memset( dst, lut[ *src ], block_pixel_count ); - dst += block_pixel_count; - src++; - } - else - { - // Unencoded block - do - { - *dst = lut[ *src ]; - dst++; - src++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - } - else - { - // Process using a simple comparison agains a threshold - const U8 threshold = (U8)(0xFF * llclampf( 1.f - weight )); - - while( dst <= last_dst ) - { - // Read RLE block header - U8 block_header_byte = *src; - src++; - - U8 block_pixel_count = (block_header_byte & 0x7F) + 1; - if( block_header_byte & 0x80 ) - { - // Encoded (duplicate-pixel) block - memset( dst, ((*src >= threshold) ? 0xFF : 0), block_pixel_count ); - dst += block_pixel_count; - src++; - } - else - { - // Unencoded block - do - { - *dst = (*src >= threshold) ? 0xFF : 0; - dst++; - src++; - block_pixel_count--; - } - while( block_pixel_count > 0 ); - } - } - } - return true; + llassert_always(raw_image); + + // "Domain" isn't really the right word. It refers to the width of the + // ramp portion of the function that relates input and output pixel values. + // A domain of 0 gives a step function. + // + // | /---------------- + // O| / | + // u| / | + // t| / | + // p|------------------/ | + // u| | | + // t|<---------------->|<-->| + // | "offset" "domain" + // | + // --+---Input-------------------------------- + // | + + if (!getData() || (0 == getDataSize())) + { + setLastError("LLImageTGA trying to decode an image with no data!"); + return false; + } + + // Only works for unflipped monochrome RLE images + if( (getComponents() != 1) || (mImageType != 11) || mOriginTopBit || mOriginRightBit ) + { + LL_ERRS() << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << LL_ENDL; + return false; + } + + if( !raw_image->resize(getWidth(), getHeight(), getComponents()) ) + { + LL_ERRS() << "LLImageTGA: Failed to resize image" << LL_ENDL; + return false; + } + + U8* dst = raw_image->getData(); + U8* src = getData() + mDataOffset; + U8* last_dst = dst + getHeight() * getWidth() - 1; + + if( domain > 0 ) + { + // Process using a look-up table (lut) + const S32 LUT_LEN = 256; + U8 lut[LUT_LEN]; + S32 i; + + F32 scale = 1.f / domain; + F32 offset = (1.f - domain) * llclampf( 1.f - weight ); + F32 bias = -(scale * offset); + + for( i = 0; i < LUT_LEN; i++ ) + { + lut[i] = (U8)llclampb( 255.f * ( i/255.f * scale + bias ) ); + } + + while( dst <= last_dst ) + { + // Read RLE block header + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + memset( dst, lut[ *src ], block_pixel_count ); + dst += block_pixel_count; + src++; + } + else + { + // Unencoded block + do + { + *dst = lut[ *src ]; + dst++; + src++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + } + else + { + // Process using a simple comparison agains a threshold + const U8 threshold = (U8)(0xFF * llclampf( 1.f - weight )); + + while( dst <= last_dst ) + { + // Read RLE block header + U8 block_header_byte = *src; + src++; + + U8 block_pixel_count = (block_header_byte & 0x7F) + 1; + if( block_header_byte & 0x80 ) + { + // Encoded (duplicate-pixel) block + memset( dst, ((*src >= threshold) ? 0xFF : 0), block_pixel_count ); + dst += block_pixel_count; + src++; + } + else + { + // Unencoded block + do + { + *dst = (*src >= threshold) ? 0xFF : 0; + dst++; + src++; + block_pixel_count--; + } + while( block_pixel_count > 0 ); + } + } + } + return true; } // Reads a .tga file and creates an LLImageTGA with its data. bool LLImageTGA::loadFile( const std::string& path ) { - S32 len = path.size(); - if( len < 5 ) - { - return false; - } - - std::string extension = gDirUtilp->getExtension(path); - if( "tga" != extension ) - { - return false; - } - - LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ - if( !file ) - { - LL_WARNS() << "Couldn't open file " << path << LL_ENDL; - return false; - } - - S32 file_size = 0; - if (!fseek(file, 0, SEEK_END)) - { - file_size = ftell(file); - fseek(file, 0, SEEK_SET); - } - - U8* buffer = allocateData(file_size); - S32 bytes_read = fread(buffer, 1, file_size, file); - if( bytes_read != file_size ) - { - deleteData(); - LL_WARNS() << "Couldn't read file " << path << LL_ENDL; - return false; - } - - fclose( file ); - - if( !updateData() ) - { - LL_WARNS() << "Couldn't decode file " << path << LL_ENDL; - deleteData(); - return false; - } - return true; + S32 len = path.size(); + if( len < 5 ) + { + return false; + } + + std::string extension = gDirUtilp->getExtension(path); + if( "tga" != extension ) + { + return false; + } + + LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ + if( !file ) + { + LL_WARNS() << "Couldn't open file " << path << LL_ENDL; + return false; + } + + S32 file_size = 0; + if (!fseek(file, 0, SEEK_END)) + { + file_size = ftell(file); + fseek(file, 0, SEEK_SET); + } + + U8* buffer = allocateData(file_size); + S32 bytes_read = fread(buffer, 1, file_size, file); + if( bytes_read != file_size ) + { + deleteData(); + LL_WARNS() << "Couldn't read file " << path << LL_ENDL; + return false; + } + + fclose( file ); + + if( !updateData() ) + { + LL_WARNS() << "Couldn't decode file " << path << LL_ENDL; + deleteData(); + return false; + } + return true; } |