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;
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];
00071 U16 mGreen[3];
00072 U16 mBlue[3];
00073 U32 mGamma[3];
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
00105 U8* mdata = getData();
00106 if (!mdata || (0 == getDataSize()))
00107 {
00108 setLastError("Uninitialized instance of LLImageBMP");
00109 return FALSE;
00110 }
00111
00112
00113
00114
00116
00117
00118
00119
00120
00121
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
00145 const S32 BITMAP_HEADER_SIZE = 40;
00146 LLBMPHeader header;
00147 llassert( sizeof( header ) == BITMAP_HEADER_SIZE );
00148
00149 memcpy(
00150 (void*)&header,
00151 mdata + FILE_HEADER_SIZE,
00152 BITMAP_HEADER_SIZE);
00153
00154
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
00181 windows_nt_version = TRUE;
00182 }
00183 else
00184 {
00185
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
00198 windows_95_version = TRUE;
00199 }
00200 else
00201 if( 108 < header.mSize )
00202 {
00203
00204
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:
00234
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
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
00260 break;
00261
00262 default:
00263 setLastError("Unsupported compression format.");
00264 return FALSE;
00265 }
00266
00268
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);
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 ) );
00296
00297 if( 3 == header.mCompression )
00298 {
00299 memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4);
00300 }
00301
00302
00303 }
00304
00305
00307
00308
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 );
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
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
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;
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);
00426 dst[1] = U8((value & mBitfieldMask[1]) >> g_shift);
00427 dst[2] = U8((value & mBitfieldMask[0]) >> b_shift);
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
00440
00441 llassert( 32 == mBitsPerPixel );
00442
00443 if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] )
00444 {
00445
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;
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);
00465 dst[1] = U8((value & mBitfieldMask[1]) >> g_shift);
00466 dst[2] = U8((value & mBitfieldMask[2]) >> b_shift);
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;
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];
00490 dst[1] = mColorPalette[index + 1];
00491 dst[2] = mColorPalette[index + 0];
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;
00508
00509 for( S32 row = 0; row < getHeight(); row++ )
00510 {
00511 for( S32 col = 0; col < getWidth(); col++ )
00512 {
00513 dst[0] = src[2];
00514 dst[1] = src[1];
00515 dst[2] = src[0];
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;
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
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;
00577 #else
00578 header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0;
00579 #endif
00580 header.mNumColors = header.mNumColorsImportant = 0;
00581
00582
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
00599 U32 cur_pos = 0;
00600 memcpy(mdata, magic, 14);
00601 cur_pos += 14;
00602 memcpy(mdata+cur_pos, &header, 40);
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
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 }