llimagebmp.cpp

Go to the documentation of this file.
00001 
00031 #include "linden_common.h"
00032 
00033 #include "llimagebmp.h"
00034 #include "llerror.h"
00035 
00036 #include "llendianswizzle.h"
00037 
00038 
00044 struct LLBMPHeader
00045 {
00046         S32 mSize;
00047         S32 mWidth;
00048         S32 mHeight;
00049         S16 mPlanes;
00050         S16 mBitsPerPixel;
00051         S16 mCompression;
00052         S16 mAlignmentPadding; // pads out to next word boundary
00053         S32 mImageSize;
00054         S32 mHorzPelsPerMeter;
00055         S32 mVertPelsPerMeter;
00056         S32 mNumColors;
00057         S32 mNumColorsImportant;
00058 };
00059 
00063 struct Win95BmpHeaderExtension
00064 {
00065         U32 mReadMask;
00066         U32 mGreenMask;
00067         U32 mBlueMask;
00068         U32 mAlphaMask;
00069         U32 mColorSpaceType;
00070         U16     mRed[3];        // Red CIE endpoint
00071         U16 mGreen[3];  // Green CIE endpoint
00072         U16 mBlue[3];   // Blue CIE endpoint
00073         U32 mGamma[3];  // Gamma scale for r g and b
00074 };
00075 
00079 LLImageBMP::LLImageBMP() 
00080         :
00081         LLImageFormatted(IMG_CODEC_BMP),
00082         mColorPaletteColors( 0 ),
00083         mColorPalette( NULL ),
00084         mBitmapOffset( 0 ),
00085         mBitsPerPixel( 0 ),
00086         mOriginAtTop( FALSE )
00087 {
00088         mBitfieldMask[0] = 0;
00089         mBitfieldMask[1] = 0;
00090         mBitfieldMask[2] = 0;
00091         mBitfieldMask[3] = 0;
00092 }
00093 
00094 LLImageBMP::~LLImageBMP()
00095 {
00096         delete[] mColorPalette;
00097 }
00098 
00099 
00100 BOOL LLImageBMP::updateData()
00101 {
00102         resetLastError();
00103 
00104         // Check to make sure that this instance has been initialized with data
00105         U8* mdata = getData();
00106         if (!mdata || (0 == getDataSize()))
00107         {
00108                 setLastError("Uninitialized instance of LLImageBMP");
00109                 return FALSE;
00110         }
00111 
00112         // Read the bitmap headers in order to get all the useful info
00113         // about this image
00114 
00116         // Part 1: "File Header"
00117         // 14 bytes consisting of
00118         // 2 bytes: either BM or BA
00119         // 4 bytes: file size in bytes
00120         // 4 bytes: reserved (always 0)
00121         // 4 bytes: bitmap offset (starting position of image data in bytes)
00122         const S32 FILE_HEADER_SIZE = 14;
00123         if ((mdata[0] != 'B') || (mdata[1] != 'M'))
00124     {
00125                 if ((mdata[0] != 'B') || (mdata[1] != 'A'))
00126                 {
00127                         setLastError("OS/2 bitmap array BMP files are not supported");
00128                         return FALSE;
00129                 }
00130                 else
00131                 {
00132                         setLastError("Does not appear to be a bitmap file");
00133                         return FALSE;
00134                 }
00135         }
00136 
00137         mBitmapOffset = mdata[13];
00138         mBitmapOffset <<= 8; mBitmapOffset += mdata[12];
00139         mBitmapOffset <<= 8; mBitmapOffset += mdata[11];
00140         mBitmapOffset <<= 8; mBitmapOffset += mdata[10];
00141 
00142 
00144         // Part 2: "Bitmap Header"
00145         const S32 BITMAP_HEADER_SIZE = 40;
00146         LLBMPHeader header;
00147         llassert( sizeof( header ) == BITMAP_HEADER_SIZE );
00148 
00149         memcpy( /* Flawfinder: ignore */
00150                 (void*)&header,
00151                 mdata + FILE_HEADER_SIZE,
00152                 BITMAP_HEADER_SIZE);
00153 
00154         // convert BMP header from little endian (no-op on little endian builds)
00155         llendianswizzleone(header.mSize);
00156         llendianswizzleone(header.mWidth);
00157         llendianswizzleone(header.mHeight);
00158         llendianswizzleone(header.mPlanes);
00159         llendianswizzleone(header.mBitsPerPixel);
00160         llendianswizzleone(header.mCompression);
00161         llendianswizzleone(header.mAlignmentPadding);
00162         llendianswizzleone(header.mImageSize);
00163         llendianswizzleone(header.mHorzPelsPerMeter);
00164         llendianswizzleone(header.mVertPelsPerMeter);
00165         llendianswizzleone(header.mNumColors);
00166         llendianswizzleone(header.mNumColorsImportant);
00167 
00168         BOOL windows_nt_version = FALSE;
00169         BOOL windows_95_version = FALSE;
00170         if( 12 == header.mSize )
00171         {
00172                 setLastError("Windows 2.x and OS/2 1.x BMP files are not supported");
00173                 return FALSE;
00174         }
00175         else
00176         if( 40 == header.mSize )
00177         {
00178                 if( 3 == header.mCompression )
00179                 {
00180                         // Windows NT
00181                         windows_nt_version = TRUE;
00182                 }
00183                 else
00184                 {
00185                         // Windows 3.x
00186                 }
00187         }
00188         else
00189         if( 12 <= header.mSize && 64 <= header.mSize )
00190         {
00191                 setLastError("OS/2 2.x BMP files are not supported");
00192                 return FALSE;
00193         }
00194         else
00195         if( 108 == header.mSize )
00196         {
00197                 // BITMAPV4HEADER
00198                 windows_95_version = TRUE;
00199         }
00200         else
00201         if( 108 < header.mSize )
00202         {
00203                 // BITMAPV5HEADER or greater
00204                 // Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5)
00205                 windows_95_version = TRUE;
00206         }
00207 
00208         S32 width = header.mWidth;
00209         S32 height = header.mHeight;
00210         if (height < 0)
00211         {
00212                 mOriginAtTop = TRUE;
00213                 height = -height;
00214         }
00215         else
00216         {
00217                 mOriginAtTop = FALSE;
00218         }
00219 
00220         mBitsPerPixel = header.mBitsPerPixel;
00221         S32 components;
00222         switch( mBitsPerPixel )
00223         {
00224         case 8:
00225                 components = 1;
00226                 break;
00227         case 24:
00228         case 32:
00229                 components = 3;
00230                 break;
00231         case 1:
00232         case 4:
00233         case 16: // Started work on 16, but doesn't work yet
00234                 // These are legal, but we don't support them yet.
00235                 setLastError("Unsupported bit depth");
00236                 return FALSE;
00237         default:
00238                 setLastError("Unrecognized bit depth");
00239                 return FALSE;
00240         }
00241 
00242         setSize(width, height, components);
00243         
00244         switch( header.mCompression )
00245         {
00246         case 0:
00247                 // Uncompressed
00248                 break;
00249 
00250         case 1:
00251                 setLastError("8 bit RLE compression not supported.");
00252                 return FALSE;
00253 
00254         case 2: 
00255                 setLastError("4 bit RLE compression not supported.");
00256                 return FALSE;
00257 
00258         case 3:
00259                 // Windows NT or Windows 95
00260                 break;
00261 
00262         default:
00263                 setLastError("Unsupported compression format.");
00264                 return FALSE;
00265         }
00266 
00268         // Part 3: Bitfield Masks and other color data
00269         S32 extension_size = 0;
00270         if( windows_nt_version )
00271         {
00272                 if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) )
00273                 {
00274                         setLastError("Bitfield encoding requires 16 or 32 bits per pixel.");
00275                         return FALSE;
00276                 }
00277 
00278                 if( 0 != header.mNumColors )
00279                 {
00280                         setLastError("Bitfield encoding is not compatible with a color table.");
00281                         return FALSE;
00282                 }
00283 
00284                 
00285                 extension_size = 4 * 3;
00286                 memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, extension_size);  /* Flawfinder: ignore */
00287         }
00288         else
00289         if( windows_95_version )
00290         {
00291                 Win95BmpHeaderExtension win_95_extension;
00292                 extension_size = sizeof( win_95_extension );
00293 
00294                 llassert( sizeof( win_95_extension ) + BITMAP_HEADER_SIZE == 108 );
00295                 memcpy( &win_95_extension, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, sizeof( win_95_extension ) ); /* Flawfinder: ignore */
00296 
00297                 if( 3 == header.mCompression )
00298                 {
00299                         memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4);   /* Flawfinder: ignore */
00300                 }
00301 
00302                 // Color correction ignored for now
00303         }
00304         
00305 
00307         // Part 4: Color Palette (optional)
00308         // Note: There's no color palette if there are 16 or more bits per pixel
00309         S32 color_palette_size = 0;
00310         mColorPaletteColors = 0;
00311         if( header.mBitsPerPixel < 16 )
00312         {
00313                 if( 0 == header.mNumColors )
00314                 {
00315                         mColorPaletteColors = (1 << header.mBitsPerPixel);
00316                 }
00317                 else
00318                 {
00319                         mColorPaletteColors = header.mNumColors;
00320                 }
00321         }
00322         color_palette_size = mColorPaletteColors * 4;
00323 
00324         if( 0 != mColorPaletteColors )
00325         {
00326                 mColorPalette = new U8[color_palette_size];
00327                 if (!mColorPalette)
00328                 {
00329                         llerrs << "Out of memory in LLImageBMP::updateData()" << llendl;
00330                         return FALSE;
00331                 }
00332                 memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size );    /* Flawfinder: ignore */
00333         }
00334 
00335         return TRUE;
00336 }
00337 
00338 BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
00339 {
00340         llassert_always(raw_image);
00341         
00342         resetLastError();
00343 
00344         // Check to make sure that this instance has been initialized with data
00345         U8* mdata = getData();
00346         if (!mdata || (0 == getDataSize()))
00347         {
00348                 setLastError("llimagebmp trying to decode an image with no data!");
00349                 return FALSE;
00350         }
00351         
00352         raw_image->resize(getWidth(), getHeight(), 3);
00353 
00354         U8* src = mdata + mBitmapOffset;
00355         U8* dst = raw_image->getData();
00356 
00357         BOOL success = FALSE;
00358 
00359         switch( mBitsPerPixel )
00360         {
00361         case 8:
00362                 if( mColorPaletteColors >= 256 )
00363                 {
00364                         success = decodeColorTable8( dst, src );
00365                 }
00366                 break;
00367         
00368         case 16:
00369                 success = decodeColorMask16( dst, src );
00370                 break;
00371         
00372         case 24:
00373                 success = decodeTruecolor24( dst, src );
00374                 break;
00375 
00376         case 32:
00377                 success = decodeColorMask32( dst, src );
00378                 break;
00379         }
00380 
00381         if( success && mOriginAtTop )
00382         {
00383                 raw_image->verticalFlip();
00384         }
00385 
00386         return success;
00387 }
00388 
00389 U32 LLImageBMP::countTrailingZeros( U32 m )
00390 {
00391         U32 shift_count = 0;
00392         while( !(m & 1) )
00393         {
00394                 shift_count++;
00395                 m >>= 1;
00396         }
00397         return shift_count;
00398 }
00399 
00400 
00401 BOOL LLImageBMP::decodeColorMask16( U8* dst, U8* src )
00402 {
00403         llassert( 16 == mBitsPerPixel );
00404 
00405         if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] )
00406         {
00407                 // Use default values
00408                 mBitfieldMask[0] = 0x00007C00;
00409                 mBitfieldMask[1] = 0x000003E0;
00410                 mBitfieldMask[2] = 0x0000001F;
00411         }
00412 
00413         S32 src_row_span = getWidth() * 2;
00414         S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4
00415 
00416         U32 r_shift = countTrailingZeros( mBitfieldMask[2] );
00417         U32 g_shift = countTrailingZeros( mBitfieldMask[1] );
00418         U32 b_shift = countTrailingZeros( mBitfieldMask[0] );
00419 
00420         for( S32 row = 0; row < getHeight(); row++ )
00421         {
00422                 for( S32 col = 0; col < getWidth(); col++ )
00423                 {
00424                         U32 value = *((U16*)src);
00425                         dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red
00426                         dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
00427                         dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue
00428                         src += 2;
00429                         dst += 3;
00430                 }
00431                 src += alignment_bytes;
00432         }
00433 
00434         return TRUE;
00435 }
00436 
00437 BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
00438 {
00439         // Note: alpha is not supported
00440 
00441         llassert( 32 == mBitsPerPixel );
00442 
00443         if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] )
00444         {
00445                 // Use default values
00446                 mBitfieldMask[0] = 0x00FF0000;
00447                 mBitfieldMask[1] = 0x0000FF00;
00448                 mBitfieldMask[2] = 0x000000FF;
00449         }
00450 
00451 
00452         S32 src_row_span = getWidth() * 4;
00453         S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4
00454 
00455         U32 r_shift = countTrailingZeros( mBitfieldMask[0] );
00456         U32 g_shift = countTrailingZeros( mBitfieldMask[1] );
00457         U32 b_shift = countTrailingZeros( mBitfieldMask[2] );
00458 
00459         for( S32 row = 0; row < getHeight(); row++ )
00460         {
00461                 for( S32 col = 0; col < getWidth(); col++ )
00462                 {
00463                         U32 value = *((U32*)src);
00464                         dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red
00465                         dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
00466                         dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue
00467                         src += 4;
00468                         dst += 3;
00469                 }
00470                 src += alignment_bytes;
00471         }
00472 
00473         return TRUE;
00474 }
00475 
00476 
00477 BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
00478 {
00479         llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) );
00480 
00481         S32 src_row_span = getWidth() * 1;
00482         S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4
00483 
00484         for( S32 row = 0; row < getHeight(); row++ )
00485         {
00486                 for( S32 col = 0; col < getWidth(); col++ )
00487                 {
00488                         S32 index = 4 * src[0];
00489                         dst[0] = mColorPalette[index + 2];      // Red
00490                         dst[1] = mColorPalette[index + 1];      // Green
00491                         dst[2] = mColorPalette[index + 0];      // Blue
00492                         src++;
00493                         dst += 3;
00494                 }
00495                 src += alignment_bytes;
00496         }
00497 
00498         return TRUE;
00499 }
00500 
00501 
00502 BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
00503 {
00504         llassert( 24 == mBitsPerPixel );
00505         llassert( 3 == getComponents() );
00506         S32 src_row_span = getWidth() * 3;
00507         S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4
00508 
00509         for( S32 row = 0; row < getHeight(); row++ )
00510         {
00511                 for( S32 col = 0; col < getWidth(); col++ )
00512                 {
00513                         dst[0] = src[2];        // Red
00514                         dst[1] = src[1];        // Green
00515                         dst[2] = src[0];        // Blue
00516                         src += 3;
00517                         dst += 3;
00518                 }
00519                 src += alignment_bytes;
00520         }
00521 
00522         return TRUE;
00523 }
00524 
00525 BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
00526 {
00527         llassert_always(raw_image);
00528         
00529         resetLastError();
00530 
00531         S32 src_components = raw_image->getComponents();
00532         S32 dst_components =  ( src_components < 3 ) ? 1 : 3;
00533 
00534         if( (2 == src_components) || (4 == src_components) )
00535         {
00536                 llinfos << "Dropping alpha information during BMP encoding" << llendl;
00537         }
00538 
00539         setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);
00540         
00541         U8 magic[14];
00542         LLBMPHeader header;
00543         int header_bytes = 14+sizeof(header);
00544         llassert(header_bytes == 54);
00545         if (getComponents() == 1)
00546         {
00547                 header_bytes += 1024; // Need colour LUT.
00548         }
00549         int line_bytes = getComponents() * getWidth();
00550         int alignment_bytes = (3 * line_bytes) % 4;
00551         line_bytes += alignment_bytes;
00552         int file_bytes = line_bytes*getHeight() + header_bytes;
00553 
00554         // Allocate the new buffer for the data.
00555         allocateData(file_bytes);
00556 
00557         magic[0] = 'B'; magic[1] = 'M';
00558         magic[2] = (U8) file_bytes;
00559         magic[3] = (U8)(file_bytes>>8);
00560         magic[4] = (U8)(file_bytes>>16);
00561         magic[5] = (U8)(file_bytes>>24);
00562         magic[6] = magic[7] = magic[8] = magic[9] = 0;
00563         magic[10] = (U8) header_bytes;
00564         magic[11] = (U8)(header_bytes>>8);
00565         magic[12] = (U8)(header_bytes>>16);
00566         magic[13] = (U8)(header_bytes>>24);
00567         header.mSize = 40;
00568         header.mWidth = getWidth();
00569         header.mHeight = getHeight();
00570         header.mPlanes = 1;
00571         header.mBitsPerPixel = (getComponents()==1)?8:24;
00572         header.mCompression = 0;
00573         header.mAlignmentPadding = 0;
00574         header.mImageSize = 0;
00575 #if LL_DARWIN
00576         header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834;     // 72dpi
00577 #else
00578         header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0;
00579 #endif
00580         header.mNumColors = header.mNumColorsImportant = 0;
00581 
00582         // convert BMP header to little endian (no-op on little endian builds)
00583         llendianswizzleone(header.mSize);
00584         llendianswizzleone(header.mWidth);
00585         llendianswizzleone(header.mHeight);
00586         llendianswizzleone(header.mPlanes);
00587         llendianswizzleone(header.mBitsPerPixel);
00588         llendianswizzleone(header.mCompression);
00589         llendianswizzleone(header.mAlignmentPadding);
00590         llendianswizzleone(header.mImageSize);
00591         llendianswizzleone(header.mHorzPelsPerMeter);
00592         llendianswizzleone(header.mVertPelsPerMeter);
00593         llendianswizzleone(header.mNumColors);
00594         llendianswizzleone(header.mNumColorsImportant);
00595 
00596         U8* mdata = getData();
00597         
00598         // Output magic, then header, then the palette table, then the data.
00599         U32 cur_pos = 0;
00600         memcpy(mdata, magic, 14);
00601         cur_pos += 14;
00602         memcpy(mdata+cur_pos, &header, 40);     /* Flawfinder: ignore */
00603         cur_pos += 40;
00604         if (getComponents() == 1)
00605         {
00606                 S32 n;
00607                 for (n=0; n < 256; n++)
00608                 {
00609                         mdata[cur_pos++] = (U8)n;
00610                         mdata[cur_pos++] = (U8)n;
00611                         mdata[cur_pos++] = (U8)n;
00612                         mdata[cur_pos++] = 0;
00613                 }
00614         }
00615         
00616         // Need to iterate through, because we need to flip the RGB.
00617         const U8* src = raw_image->getData();
00618         U8* dst = mdata + cur_pos;
00619 
00620         for( S32 row = 0; row < getHeight(); row++ )
00621         {
00622                 for( S32 col = 0; col < getWidth(); col++ )
00623                 {
00624                         switch( src_components )
00625                         {
00626                         case 1:
00627                                 *dst++ = *src++;
00628                                 break;
00629                         case 2:
00630                                 {
00631                                         U32 lum = src[0];
00632                                         U32 alpha = src[1];
00633                                         *dst++ = (U8)(lum * alpha / 255);
00634                                         src += 2;
00635                                         break;
00636                                 }
00637                         case 3:
00638                         case 4:
00639                                 dst[0] = src[2];
00640                                 dst[1] = src[1];
00641                                 dst[2] = src[0];
00642                                 src += src_components;
00643                                 dst += 3;
00644                                 break;
00645                         }
00646 
00647                         for( S32 i = 0; i < alignment_bytes; i++ )
00648                         {
00649                                 *dst++ = 0;
00650                         }
00651                 }
00652         }
00653 
00654         return TRUE;
00655 }

Generated on Thu Jul 1 06:08:43 2010 for Second Life Viewer by  doxygen 1.4.7