diff options
Diffstat (limited to 'indra/llimage/llimagebmp.cpp')
-rw-r--r-- | indra/llimage/llimagebmp.cpp | 1154 |
1 files changed, 577 insertions, 577 deletions
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index cdea0da68d..08fcdf39da 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llimagebmp.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$ */ @@ -38,18 +38,18 @@ */ struct LLBMPHeader { - S32 mSize; - S32 mWidth; - S32 mHeight; - S16 mPlanes; - S16 mBitsPerPixel; - S16 mCompression; - S16 mAlignmentPadding; // pads out to next word boundary - S32 mImageSize; - S32 mHorzPelsPerMeter; - S32 mVertPelsPerMeter; - S32 mNumColors; - S32 mNumColorsImportant; + S32 mSize; + S32 mWidth; + S32 mHeight; + S16 mPlanes; + S16 mBitsPerPixel; + S16 mCompression; + S16 mAlignmentPadding; // pads out to next word boundary + S32 mImageSize; + S32 mHorzPelsPerMeter; + S32 mVertPelsPerMeter; + S32 mNumColors; + S32 mNumColorsImportant; }; /** @@ -57,616 +57,616 @@ struct LLBMPHeader */ struct Win95BmpHeaderExtension { - U32 mReadMask; - U32 mGreenMask; - U32 mBlueMask; - U32 mAlphaMask; - U32 mColorSpaceType; - U16 mRed[3]; // Red CIE endpoint - U16 mGreen[3]; // Green CIE endpoint - U16 mBlue[3]; // Blue CIE endpoint - U32 mGamma[3]; // Gamma scale for r g and b + U32 mReadMask; + U32 mGreenMask; + U32 mBlueMask; + U32 mAlphaMask; + U32 mColorSpaceType; + U16 mRed[3]; // Red CIE endpoint + U16 mGreen[3]; // Green CIE endpoint + U16 mBlue[3]; // Blue CIE endpoint + U32 mGamma[3]; // Gamma scale for r g and b }; /** * LLImageBMP */ -LLImageBMP::LLImageBMP() - : - LLImageFormatted(IMG_CODEC_BMP), - mColorPaletteColors( 0 ), - mColorPalette( NULL ), - mBitmapOffset( 0 ), - mBitsPerPixel( 0 ), - mOriginAtTop( false ) +LLImageBMP::LLImageBMP() + : + LLImageFormatted(IMG_CODEC_BMP), + mColorPaletteColors( 0 ), + mColorPalette( NULL ), + mBitmapOffset( 0 ), + mBitsPerPixel( 0 ), + mOriginAtTop( false ) { - mBitfieldMask[0] = 0; - mBitfieldMask[1] = 0; - mBitfieldMask[2] = 0; - mBitfieldMask[3] = 0; + mBitfieldMask[0] = 0; + mBitfieldMask[1] = 0; + mBitfieldMask[2] = 0; + mBitfieldMask[3] = 0; } LLImageBMP::~LLImageBMP() { - delete[] mColorPalette; + delete[] mColorPalette; } bool LLImageBMP::updateData() { - resetLastError(); - - // Check to make sure that this instance has been initialized with data - U8* mdata = getData(); - if (!mdata || (0 == getDataSize())) - { - setLastError("Uninitialized instance of LLImageBMP"); - return false; - } - - // Read the bitmap headers in order to get all the useful info - // about this image - - //////////////////////////////////////////////////////////////////// - // Part 1: "File Header" - // 14 bytes consisting of - // 2 bytes: either BM or BA - // 4 bytes: file size in bytes - // 4 bytes: reserved (always 0) - // 4 bytes: bitmap offset (starting position of image data in bytes) - const S32 FILE_HEADER_SIZE = 14; - if ((mdata[0] != 'B') || (mdata[1] != 'M')) + resetLastError(); + + // Check to make sure that this instance has been initialized with data + U8* mdata = getData(); + if (!mdata || (0 == getDataSize())) + { + setLastError("Uninitialized instance of LLImageBMP"); + return false; + } + + // Read the bitmap headers in order to get all the useful info + // about this image + + //////////////////////////////////////////////////////////////////// + // Part 1: "File Header" + // 14 bytes consisting of + // 2 bytes: either BM or BA + // 4 bytes: file size in bytes + // 4 bytes: reserved (always 0) + // 4 bytes: bitmap offset (starting position of image data in bytes) + const S32 FILE_HEADER_SIZE = 14; + if ((mdata[0] != 'B') || (mdata[1] != 'M')) + { + if ((mdata[0] != 'B') || (mdata[1] != 'A')) + { + setLastError("OS/2 bitmap array BMP files are not supported"); + return false; + } + else + { + setLastError("Does not appear to be a bitmap file"); + return false; + } + } + + mBitmapOffset = mdata[13]; + mBitmapOffset <<= 8; mBitmapOffset += mdata[12]; + mBitmapOffset <<= 8; mBitmapOffset += mdata[11]; + mBitmapOffset <<= 8; mBitmapOffset += mdata[10]; + + + //////////////////////////////////////////////////////////////////// + // Part 2: "Bitmap Header" + const S32 BITMAP_HEADER_SIZE = 40; + LLBMPHeader header; + llassert( sizeof( header ) == BITMAP_HEADER_SIZE ); + + memcpy( /* Flawfinder: ignore */ + (void*)&header, + mdata + FILE_HEADER_SIZE, + BITMAP_HEADER_SIZE); + + // convert BMP header from little endian (no-op on little endian builds) + llendianswizzleone(header.mSize); + llendianswizzleone(header.mWidth); + llendianswizzleone(header.mHeight); + llendianswizzleone(header.mPlanes); + llendianswizzleone(header.mBitsPerPixel); + llendianswizzleone(header.mCompression); + llendianswizzleone(header.mAlignmentPadding); + llendianswizzleone(header.mImageSize); + llendianswizzleone(header.mHorzPelsPerMeter); + llendianswizzleone(header.mVertPelsPerMeter); + llendianswizzleone(header.mNumColors); + llendianswizzleone(header.mNumColorsImportant); + + bool windows_nt_version = false; + bool windows_95_version = false; + if( 12 == header.mSize ) + { + setLastError("Windows 2.x and OS/2 1.x BMP files are not supported"); + return false; + } + else + if( 40 == header.mSize ) + { + if( 3 == header.mCompression ) + { + // Windows NT + windows_nt_version = true; + } + else + { + // Windows 3.x + } + } + else + if( 12 <= header.mSize && header.mSize <= 64 ) + { + setLastError("OS/2 2.x BMP files are not supported"); + return false; + } + else + if( 108 == header.mSize ) + { + // BITMAPV4HEADER + windows_95_version = true; + } + else + if( 108 < header.mSize ) + { + // BITMAPV5HEADER or greater + // Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5) + windows_95_version = true; + } + + S32 width = header.mWidth; + S32 height = header.mHeight; + if (height < 0) + { + mOriginAtTop = true; + height = -height; + } + else + { + mOriginAtTop = false; + } + + mBitsPerPixel = header.mBitsPerPixel; + S32 components; + switch( mBitsPerPixel ) + { + case 8: + components = 1; + break; + case 24: + case 32: + components = 3; + break; + case 1: + case 4: + case 16: // Started work on 16, but doesn't work yet + // These are legal, but we don't support them yet. + setLastError("Unsupported bit depth"); + return false; + default: + setLastError("Unrecognized bit depth"); + return false; + } + + setSize(width, height, components); + + switch( header.mCompression ) + { + case 0: + // Uncompressed + break; + + case 1: + setLastError("8 bit RLE compression not supported."); + return false; + + case 2: + setLastError("4 bit RLE compression not supported."); + return false; + + case 3: + // Windows NT or Windows 95 + break; + + default: + setLastError("Unsupported compression format."); + return false; + } + + //////////////////////////////////////////////////////////////////// + // Part 3: Bitfield Masks and other color data + S32 extension_size = 0; + if( windows_nt_version ) { - if ((mdata[0] != 'B') || (mdata[1] != 'A')) - { - setLastError("OS/2 bitmap array BMP files are not supported"); - return false; - } - else - { - setLastError("Does not appear to be a bitmap file"); - return false; - } - } - - mBitmapOffset = mdata[13]; - mBitmapOffset <<= 8; mBitmapOffset += mdata[12]; - mBitmapOffset <<= 8; mBitmapOffset += mdata[11]; - mBitmapOffset <<= 8; mBitmapOffset += mdata[10]; - - - //////////////////////////////////////////////////////////////////// - // Part 2: "Bitmap Header" - const S32 BITMAP_HEADER_SIZE = 40; - LLBMPHeader header; - llassert( sizeof( header ) == BITMAP_HEADER_SIZE ); - - memcpy( /* Flawfinder: ignore */ - (void*)&header, - mdata + FILE_HEADER_SIZE, - BITMAP_HEADER_SIZE); - - // convert BMP header from little endian (no-op on little endian builds) - llendianswizzleone(header.mSize); - llendianswizzleone(header.mWidth); - llendianswizzleone(header.mHeight); - llendianswizzleone(header.mPlanes); - llendianswizzleone(header.mBitsPerPixel); - llendianswizzleone(header.mCompression); - llendianswizzleone(header.mAlignmentPadding); - llendianswizzleone(header.mImageSize); - llendianswizzleone(header.mHorzPelsPerMeter); - llendianswizzleone(header.mVertPelsPerMeter); - llendianswizzleone(header.mNumColors); - llendianswizzleone(header.mNumColorsImportant); - - bool windows_nt_version = false; - bool windows_95_version = false; - if( 12 == header.mSize ) - { - setLastError("Windows 2.x and OS/2 1.x BMP files are not supported"); - return false; - } - else - if( 40 == header.mSize ) - { - if( 3 == header.mCompression ) - { - // Windows NT - windows_nt_version = true; - } - else - { - // Windows 3.x - } - } - else - if( 12 <= header.mSize && header.mSize <= 64 ) - { - setLastError("OS/2 2.x BMP files are not supported"); - return false; - } - else - if( 108 == header.mSize ) - { - // BITMAPV4HEADER - windows_95_version = true; - } - else - if( 108 < header.mSize ) - { - // BITMAPV5HEADER or greater - // Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5) - windows_95_version = true; - } - - S32 width = header.mWidth; - S32 height = header.mHeight; - if (height < 0) - { - mOriginAtTop = true; - height = -height; - } - else - { - mOriginAtTop = false; - } - - mBitsPerPixel = header.mBitsPerPixel; - S32 components; - switch( mBitsPerPixel ) - { - case 8: - components = 1; - break; - case 24: - case 32: - components = 3; - break; - case 1: - case 4: - case 16: // Started work on 16, but doesn't work yet - // These are legal, but we don't support them yet. - setLastError("Unsupported bit depth"); - return false; - default: - setLastError("Unrecognized bit depth"); - return false; - } - - setSize(width, height, components); - - switch( header.mCompression ) - { - case 0: - // Uncompressed - break; - - case 1: - setLastError("8 bit RLE compression not supported."); - return false; - - case 2: - setLastError("4 bit RLE compression not supported."); - return false; - - case 3: - // Windows NT or Windows 95 - break; - - default: - setLastError("Unsupported compression format."); - return false; - } - - //////////////////////////////////////////////////////////////////// - // Part 3: Bitfield Masks and other color data - S32 extension_size = 0; - if( windows_nt_version ) - { - if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) ) - { - setLastError("Bitfield encoding requires 16 or 32 bits per pixel."); - return false; - } - - if( 0 != header.mNumColors ) - { - setLastError("Bitfield encoding is not compatible with a color table."); - return false; - } - - - extension_size = 4 * 3; - memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, extension_size); /* Flawfinder: ignore */ - } - else - if( windows_95_version ) - { - Win95BmpHeaderExtension win_95_extension; - extension_size = sizeof( win_95_extension ); - - llassert( sizeof( win_95_extension ) + BITMAP_HEADER_SIZE == 108 ); - memcpy( &win_95_extension, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, sizeof( win_95_extension ) ); /* Flawfinder: ignore */ - - if( 3 == header.mCompression ) - { - memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4); /* Flawfinder: ignore */ - } - - // Color correction ignored for now - } - - - //////////////////////////////////////////////////////////////////// - // Part 4: Color Palette (optional) - // Note: There's no color palette if there are 16 or more bits per pixel - S32 color_palette_size = 0; - mColorPaletteColors = 0; - if( header.mBitsPerPixel < 16 ) - { - if( 0 == header.mNumColors ) - { - mColorPaletteColors = (1 << header.mBitsPerPixel); - } - else - { - mColorPaletteColors = header.mNumColors; - } - } - color_palette_size = mColorPaletteColors * 4; - - if( 0 != mColorPaletteColors ) - { - mColorPalette = new(std::nothrow) U8[color_palette_size]; - if (!mColorPalette) - { + if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) ) + { + setLastError("Bitfield encoding requires 16 or 32 bits per pixel."); + return false; + } + + if( 0 != header.mNumColors ) + { + setLastError("Bitfield encoding is not compatible with a color table."); + return false; + } + + + extension_size = 4 * 3; + memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, extension_size); /* Flawfinder: ignore */ + } + else + if( windows_95_version ) + { + Win95BmpHeaderExtension win_95_extension; + extension_size = sizeof( win_95_extension ); + + llassert( sizeof( win_95_extension ) + BITMAP_HEADER_SIZE == 108 ); + memcpy( &win_95_extension, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, sizeof( win_95_extension ) ); /* Flawfinder: ignore */ + + if( 3 == header.mCompression ) + { + memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4); /* Flawfinder: ignore */ + } + + // Color correction ignored for now + } + + + //////////////////////////////////////////////////////////////////// + // Part 4: Color Palette (optional) + // Note: There's no color palette if there are 16 or more bits per pixel + S32 color_palette_size = 0; + mColorPaletteColors = 0; + if( header.mBitsPerPixel < 16 ) + { + if( 0 == header.mNumColors ) + { + mColorPaletteColors = (1 << header.mBitsPerPixel); + } + else + { + mColorPaletteColors = header.mNumColors; + } + } + color_palette_size = mColorPaletteColors * 4; + + if( 0 != mColorPaletteColors ) + { + mColorPalette = new(std::nothrow) U8[color_palette_size]; + if (!mColorPalette) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Out of memory in LLImageBMP::updateData()" << LL_ENDL; - return false; - } - memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size ); /* Flawfinder: ignore */ - } + LL_ERRS() << "Out of memory in LLImageBMP::updateData()" << LL_ENDL; + return false; + } + memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size ); /* Flawfinder: ignore */ + } - return true; + return true; } bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) { - llassert_always(raw_image); - - resetLastError(); - - // Check to make sure that this instance has been initialized with data - U8* mdata = getData(); - if (!mdata || (0 == getDataSize())) - { - setLastError("llimagebmp trying to decode an image with no data!"); - return false; - } - - if (!raw_image->resize(getWidth(), getHeight(), 3)) - { - setLastError("llimagebmp failed to resize image!"); - return false; - } - - U8* src = mdata + mBitmapOffset; - U8* dst = raw_image->getData(); - - bool success = false; - - switch( mBitsPerPixel ) - { - case 8: - if( mColorPaletteColors >= 256 ) - { - success = decodeColorTable8( dst, src ); - } - break; - - case 16: - success = decodeColorMask16( dst, src ); - break; - - case 24: - success = decodeTruecolor24( dst, src ); - break; - - case 32: - success = decodeColorMask32( dst, src ); - break; - } - - if( success && mOriginAtTop ) - { - raw_image->verticalFlip(); - } - - return success; + llassert_always(raw_image); + + resetLastError(); + + // Check to make sure that this instance has been initialized with data + U8* mdata = getData(); + if (!mdata || (0 == getDataSize())) + { + setLastError("llimagebmp trying to decode an image with no data!"); + return false; + } + + if (!raw_image->resize(getWidth(), getHeight(), 3)) + { + setLastError("llimagebmp failed to resize image!"); + return false; + } + + U8* src = mdata + mBitmapOffset; + U8* dst = raw_image->getData(); + + bool success = false; + + switch( mBitsPerPixel ) + { + case 8: + if( mColorPaletteColors >= 256 ) + { + success = decodeColorTable8( dst, src ); + } + break; + + case 16: + success = decodeColorMask16( dst, src ); + break; + + case 24: + success = decodeTruecolor24( dst, src ); + break; + + case 32: + success = decodeColorMask32( dst, src ); + break; + } + + if( success && mOriginAtTop ) + { + raw_image->verticalFlip(); + } + + return success; } U32 LLImageBMP::countTrailingZeros( U32 m ) { - U32 shift_count = 0; - while( !(m & 1) ) - { - shift_count++; - m >>= 1; - } - return shift_count; + U32 shift_count = 0; + while( !(m & 1) ) + { + shift_count++; + m >>= 1; + } + return shift_count; } bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) { - llassert( 16 == mBitsPerPixel ); - - if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) - { - // Use default values - mBitfieldMask[0] = 0x00007C00; - mBitfieldMask[1] = 0x000003E0; - mBitfieldMask[2] = 0x0000001F; - } - - S32 src_row_span = getWidth() * 2; - S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 - - U32 r_shift = countTrailingZeros( mBitfieldMask[2] ); - U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); - U32 b_shift = countTrailingZeros( mBitfieldMask[0] ); - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( S32 col = 0; col < getWidth(); col++ ) - { - U32 value = *((U16*)src); - dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red - dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green - dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue - src += 2; - dst += 3; - } - src += alignment_bytes; - } - - return true; + llassert( 16 == mBitsPerPixel ); + + if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) + { + // Use default values + mBitfieldMask[0] = 0x00007C00; + mBitfieldMask[1] = 0x000003E0; + mBitfieldMask[2] = 0x0000001F; + } + + S32 src_row_span = getWidth() * 2; + S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + + U32 r_shift = countTrailingZeros( mBitfieldMask[2] ); + U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); + U32 b_shift = countTrailingZeros( mBitfieldMask[0] ); + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( S32 col = 0; col < getWidth(); col++ ) + { + U32 value = *((U16*)src); + dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red + dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green + dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue + src += 2; + dst += 3; + } + src += alignment_bytes; + } + + return true; } bool LLImageBMP::decodeColorMask32( U8* dst, U8* src ) { - // Note: alpha is not supported - - llassert( 32 == mBitsPerPixel ); - - if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) - { - // Use default values - mBitfieldMask[0] = 0x00FF0000; - mBitfieldMask[1] = 0x0000FF00; - mBitfieldMask[2] = 0x000000FF; - } - - if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset) - { //here we have situation when data size in src less than actually needed - return false; - } - - S32 src_row_span = getWidth() * 4; - S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 - - U32 r_shift = countTrailingZeros( mBitfieldMask[0] ); - U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); - U32 b_shift = countTrailingZeros( mBitfieldMask[2] ); - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( S32 col = 0; col < getWidth(); col++ ) - { - U32 value = *((U32*)src); - dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red - dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green - dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue - src += 4; - dst += 3; - } - src += alignment_bytes; - } - - return true; + // Note: alpha is not supported + + llassert( 32 == mBitsPerPixel ); + + if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) + { + // Use default values + mBitfieldMask[0] = 0x00FF0000; + mBitfieldMask[1] = 0x0000FF00; + mBitfieldMask[2] = 0x000000FF; + } + + if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return false; + } + + S32 src_row_span = getWidth() * 4; + S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + + U32 r_shift = countTrailingZeros( mBitfieldMask[0] ); + U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); + U32 b_shift = countTrailingZeros( mBitfieldMask[2] ); + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( S32 col = 0; col < getWidth(); col++ ) + { + U32 value = *((U32*)src); + dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red + dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green + dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue + src += 4; + dst += 3; + } + src += alignment_bytes; + } + + return true; } bool LLImageBMP::decodeColorTable8( U8* dst, U8* src ) { - llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) ); - - S32 src_row_span = getWidth() * 1; - S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 - - if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) - { //here we have situation when data size in src less than actually needed - return false; - } - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( S32 col = 0; col < getWidth(); col++ ) - { - S32 index = 4 * src[0]; - dst[0] = mColorPalette[index + 2]; // Red - dst[1] = mColorPalette[index + 1]; // Green - dst[2] = mColorPalette[index + 0]; // Blue - src++; - dst += 3; - } - src += alignment_bytes; - } - - return true; + llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) ); + + S32 src_row_span = getWidth() * 1; + S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + + if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return false; + } + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( S32 col = 0; col < getWidth(); col++ ) + { + S32 index = 4 * src[0]; + dst[0] = mColorPalette[index + 2]; // Red + dst[1] = mColorPalette[index + 1]; // Green + dst[2] = mColorPalette[index + 0]; // Blue + src++; + dst += 3; + } + src += alignment_bytes; + } + + return true; } bool LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) { - llassert( 24 == mBitsPerPixel ); - llassert( 3 == getComponents() ); - S32 src_row_span = getWidth() * 3; - S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 - - if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) - { //here we have situation when data size in src less than actually needed - return false; - } - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( S32 col = 0; col < getWidth(); col++ ) - { - dst[0] = src[2]; // Red - dst[1] = src[1]; // Green - dst[2] = src[0]; // Blue - src += 3; - dst += 3; - } - src += alignment_bytes; - } - - return true; + llassert( 24 == mBitsPerPixel ); + llassert( 3 == getComponents() ); + S32 src_row_span = getWidth() * 3; + S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + + if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return false; + } + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( S32 col = 0; col < getWidth(); col++ ) + { + dst[0] = src[2]; // Red + dst[1] = src[1]; // Green + dst[2] = src[0]; // Blue + src += 3; + dst += 3; + } + src += alignment_bytes; + } + + return true; } bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) { - llassert_always(raw_image); - - resetLastError(); - - S32 src_components = raw_image->getComponents(); - S32 dst_components = ( src_components < 3 ) ? 1 : 3; - - if( (2 == src_components) || (4 == src_components) ) - { - LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL; - } - - setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components); - - U8 magic[14]; - LLBMPHeader header; - int header_bytes = 14+sizeof(header); - llassert(header_bytes == 54); - if (getComponents() == 1) - { - header_bytes += 1024; // Need colour LUT. - } - int line_bytes = getComponents() * getWidth(); - int alignment_bytes = (3 * line_bytes) % 4; - line_bytes += alignment_bytes; - int file_bytes = line_bytes*getHeight() + header_bytes; - - // Allocate the new buffer for the data. - if(!allocateData(file_bytes)) //memory allocation failed - { - return false ; - } - - magic[0] = 'B'; magic[1] = 'M'; - magic[2] = (U8) file_bytes; - magic[3] = (U8)(file_bytes>>8); - magic[4] = (U8)(file_bytes>>16); - magic[5] = (U8)(file_bytes>>24); - magic[6] = magic[7] = magic[8] = magic[9] = 0; - magic[10] = (U8) header_bytes; - magic[11] = (U8)(header_bytes>>8); - magic[12] = (U8)(header_bytes>>16); - magic[13] = (U8)(header_bytes>>24); - header.mSize = 40; - header.mWidth = getWidth(); - header.mHeight = getHeight(); - header.mPlanes = 1; - header.mBitsPerPixel = (getComponents()==1)?8:24; - header.mCompression = 0; - header.mAlignmentPadding = 0; - header.mImageSize = 0; + llassert_always(raw_image); + + resetLastError(); + + S32 src_components = raw_image->getComponents(); + S32 dst_components = ( src_components < 3 ) ? 1 : 3; + + if( (2 == src_components) || (4 == src_components) ) + { + LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL; + } + + setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components); + + U8 magic[14]; + LLBMPHeader header; + int header_bytes = 14+sizeof(header); + llassert(header_bytes == 54); + if (getComponents() == 1) + { + header_bytes += 1024; // Need colour LUT. + } + int line_bytes = getComponents() * getWidth(); + int alignment_bytes = (3 * line_bytes) % 4; + line_bytes += alignment_bytes; + int file_bytes = line_bytes*getHeight() + header_bytes; + + // Allocate the new buffer for the data. + if(!allocateData(file_bytes)) //memory allocation failed + { + return false ; + } + + magic[0] = 'B'; magic[1] = 'M'; + magic[2] = (U8) file_bytes; + magic[3] = (U8)(file_bytes>>8); + magic[4] = (U8)(file_bytes>>16); + magic[5] = (U8)(file_bytes>>24); + magic[6] = magic[7] = magic[8] = magic[9] = 0; + magic[10] = (U8) header_bytes; + magic[11] = (U8)(header_bytes>>8); + magic[12] = (U8)(header_bytes>>16); + magic[13] = (U8)(header_bytes>>24); + header.mSize = 40; + header.mWidth = getWidth(); + header.mHeight = getHeight(); + header.mPlanes = 1; + header.mBitsPerPixel = (getComponents()==1)?8:24; + header.mCompression = 0; + header.mAlignmentPadding = 0; + header.mImageSize = 0; #if LL_DARWIN - header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834; // 72dpi + header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834; // 72dpi #else - header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0; + header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0; #endif - header.mNumColors = header.mNumColorsImportant = 0; - - // convert BMP header to little endian (no-op on little endian builds) - llendianswizzleone(header.mSize); - llendianswizzleone(header.mWidth); - llendianswizzleone(header.mHeight); - llendianswizzleone(header.mPlanes); - llendianswizzleone(header.mBitsPerPixel); - llendianswizzleone(header.mCompression); - llendianswizzleone(header.mAlignmentPadding); - llendianswizzleone(header.mImageSize); - llendianswizzleone(header.mHorzPelsPerMeter); - llendianswizzleone(header.mVertPelsPerMeter); - llendianswizzleone(header.mNumColors); - llendianswizzleone(header.mNumColorsImportant); - - U8* mdata = getData(); - - // Output magic, then header, then the palette table, then the data. - U32 cur_pos = 0; - memcpy(mdata, magic, 14); - cur_pos += 14; - memcpy(mdata+cur_pos, &header, 40); /* Flawfinder: ignore */ - cur_pos += 40; - if (getComponents() == 1) - { - S32 n; - for (n=0; n < 256; n++) - { - mdata[cur_pos++] = (U8)n; - mdata[cur_pos++] = (U8)n; - mdata[cur_pos++] = (U8)n; - mdata[cur_pos++] = 0; - } - } - - // Need to iterate through, because we need to flip the RGB. - const U8* src = raw_image->getData(); - U8* dst = mdata + cur_pos; - - for( S32 row = 0; row < getHeight(); row++ ) - { - for( S32 col = 0; col < getWidth(); col++ ) - { - switch( src_components ) - { - case 1: - *dst++ = *src++; - break; - case 2: - { - U32 lum = src[0]; - U32 alpha = src[1]; - *dst++ = (U8)(lum * alpha / 255); - src += 2; - break; - } - case 3: - case 4: - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - src += src_components; - dst += 3; - break; - } - - } - for( S32 i = 0; i < alignment_bytes; i++ ) - { - *dst++ = 0; - } - } - - return true; + header.mNumColors = header.mNumColorsImportant = 0; + + // convert BMP header to little endian (no-op on little endian builds) + llendianswizzleone(header.mSize); + llendianswizzleone(header.mWidth); + llendianswizzleone(header.mHeight); + llendianswizzleone(header.mPlanes); + llendianswizzleone(header.mBitsPerPixel); + llendianswizzleone(header.mCompression); + llendianswizzleone(header.mAlignmentPadding); + llendianswizzleone(header.mImageSize); + llendianswizzleone(header.mHorzPelsPerMeter); + llendianswizzleone(header.mVertPelsPerMeter); + llendianswizzleone(header.mNumColors); + llendianswizzleone(header.mNumColorsImportant); + + U8* mdata = getData(); + + // Output magic, then header, then the palette table, then the data. + U32 cur_pos = 0; + memcpy(mdata, magic, 14); + cur_pos += 14; + memcpy(mdata+cur_pos, &header, 40); /* Flawfinder: ignore */ + cur_pos += 40; + if (getComponents() == 1) + { + S32 n; + for (n=0; n < 256; n++) + { + mdata[cur_pos++] = (U8)n; + mdata[cur_pos++] = (U8)n; + mdata[cur_pos++] = (U8)n; + mdata[cur_pos++] = 0; + } + } + + // Need to iterate through, because we need to flip the RGB. + const U8* src = raw_image->getData(); + U8* dst = mdata + cur_pos; + + for( S32 row = 0; row < getHeight(); row++ ) + { + for( S32 col = 0; col < getWidth(); col++ ) + { + switch( src_components ) + { + case 1: + *dst++ = *src++; + break; + case 2: + { + U32 lum = src[0]; + U32 alpha = src[1]; + *dst++ = (U8)(lum * alpha / 255); + src += 2; + break; + } + case 3: + case 4: + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + src += src_components; + dst += 3; + break; + } + + } + for( S32 i = 0; i < alignment_bytes; i++ ) + { + *dst++ = 0; + } + } + + return true; } |