aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llimage/llimagebmp.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llimage/llimagebmp.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llimage/llimagebmp.cpp')
-rw-r--r--linden/indra/llimage/llimagebmp.cpp643
1 files changed, 643 insertions, 0 deletions
diff --git a/linden/indra/llimage/llimagebmp.cpp b/linden/indra/llimage/llimagebmp.cpp
new file mode 100644
index 0000000..fc9532e
--- /dev/null
+++ b/linden/indra/llimage/llimagebmp.cpp
@@ -0,0 +1,643 @@
1/**
2 * @file llimagebmp.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "llimagebmp.h"
30#include "llerror.h"
31
32#include "llendianswizzle.h"
33
34
35/**
36 * @struct LLBMPHeader
37 *
38 * This struct helps deal with bmp files.
39 */
40struct LLBMPHeader
41{
42 S32 mSize;
43 S32 mWidth;
44 S32 mHeight;
45 S16 mPlanes;
46 S16 mBitsPerPixel;
47 S16 mCompression;
48 S16 mAlignmentPadding; // pads out to next word boundary
49 S32 mImageSize;
50 S32 mHorzPelsPerMeter;
51 S32 mVertPelsPerMeter;
52 S32 mNumColors;
53 S32 mNumColorsImportant;
54};
55
56/**
57 * @struct Win95BmpHeaderExtension
58 */
59struct Win95BmpHeaderExtension
60{
61 U32 mReadMask;
62 U32 mGreenMask;
63 U32 mBlueMask;
64 U32 mAlphaMask;
65 U32 mColorSpaceType;
66 U16 mRed[3]; // Red CIE endpoint
67 U16 mGreen[3]; // Green CIE endpoint
68 U16 mBlue[3]; // Blue CIE endpoint
69 U32 mGamma[3]; // Gamma scale for r g and b
70};
71
72/**
73 * LLImageBMP
74 */
75LLImageBMP::LLImageBMP()
76 :
77 LLImageFormatted(IMG_CODEC_BMP),
78 mColorPaletteColors( 0 ),
79 mColorPalette( NULL ),
80 mBitmapOffset( 0 ),
81 mBitsPerPixel( 0 ),
82 mOriginAtTop( FALSE )
83{
84 mBitfieldMask[0] = 0;
85 mBitfieldMask[1] = 0;
86 mBitfieldMask[2] = 0;
87 mBitfieldMask[3] = 0;
88}
89
90LLImageBMP::~LLImageBMP()
91{
92 delete[] mColorPalette;
93}
94
95
96BOOL LLImageBMP::updateData()
97{
98 resetLastError();
99
100 // Check to make sure that this instance has been initialized with data
101 U8* mdata = getData();
102 if (!mdata || (0 == getDataSize()))
103 {
104 setLastError("Uninitialized instance of LLImageBMP");
105 return FALSE;
106 }
107
108 // Read the bitmap headers in order to get all the useful info
109 // about this image
110
111 ////////////////////////////////////////////////////////////////////
112 // Part 1: "File Header"
113 // 14 bytes consisting of
114 // 2 bytes: either BM or BA
115 // 4 bytes: file size in bytes
116 // 4 bytes: reserved (always 0)
117 // 4 bytes: bitmap offset (starting position of image data in bytes)
118 const S32 FILE_HEADER_SIZE = 14;
119 if ((mdata[0] != 'B') || (mdata[1] != 'M'))
120 {
121 if ((mdata[0] != 'B') || (mdata[1] != 'A'))
122 {
123 setLastError("OS/2 bitmap array BMP files are not supported");
124 return FALSE;
125 }
126 else
127 {
128 setLastError("Does not appear to be a bitmap file");
129 return FALSE;
130 }
131 }
132
133 mBitmapOffset = mdata[13];
134 mBitmapOffset <<= 8; mBitmapOffset += mdata[12];
135 mBitmapOffset <<= 8; mBitmapOffset += mdata[11];
136 mBitmapOffset <<= 8; mBitmapOffset += mdata[10];
137
138
139 ////////////////////////////////////////////////////////////////////
140 // Part 2: "Bitmap Header"
141 const S32 BITMAP_HEADER_SIZE = 40;
142 LLBMPHeader header;
143 llassert( sizeof( header ) == BITMAP_HEADER_SIZE );
144
145 memcpy((void *)&header, mdata + FILE_HEADER_SIZE, BITMAP_HEADER_SIZE);
146
147 // convert BMP header from little endian (no-op on little endian builds)
148 llendianswizzleone(header.mSize);
149 llendianswizzleone(header.mWidth);
150 llendianswizzleone(header.mHeight);
151 llendianswizzleone(header.mPlanes);
152 llendianswizzleone(header.mBitsPerPixel);
153 llendianswizzleone(header.mCompression);
154 llendianswizzleone(header.mAlignmentPadding);
155 llendianswizzleone(header.mImageSize);
156 llendianswizzleone(header.mHorzPelsPerMeter);
157 llendianswizzleone(header.mVertPelsPerMeter);
158 llendianswizzleone(header.mNumColors);
159 llendianswizzleone(header.mNumColorsImportant);
160
161 BOOL windows_nt_version = FALSE;
162 BOOL windows_95_version = FALSE;
163 if( 12 == header.mSize )
164 {
165 setLastError("Windows 2.x and OS/2 1.x BMP files are not supported");
166 return FALSE;
167 }
168 else
169 if( 40 == header.mSize )
170 {
171 if( 3 == header.mCompression )
172 {
173 // Windows NT
174 windows_nt_version = TRUE;
175 }
176 else
177 {
178 // Windows 3.x
179 }
180 }
181 else
182 if( 12 <= header.mSize && 64 <= header.mSize )
183 {
184 setLastError("OS/2 2.x BMP files are not supported");
185 return FALSE;
186 }
187 else
188 if( 108 == header.mSize )
189 {
190 // BITMAPV4HEADER
191 windows_95_version = TRUE;
192 }
193 else
194 if( 108 < header.mSize )
195 {
196 // BITMAPV5HEADER or greater
197 // Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5)
198 windows_95_version = TRUE;
199 }
200
201 S32 width = header.mWidth;
202 S32 height = header.mHeight;
203 if (height < 0)
204 {
205 mOriginAtTop = TRUE;
206 height = -height;
207 }
208 else
209 {
210 mOriginAtTop = FALSE;
211 }
212
213 mBitsPerPixel = header.mBitsPerPixel;
214 S32 components;
215 switch( mBitsPerPixel )
216 {
217 case 8:
218 components = 1;
219 break;
220 case 24:
221 case 32:
222 components = 3;
223 break;
224 case 1:
225 case 4:
226 case 16: // Started work on 16, but doesn't work yet
227 // These are legal, but we don't support them yet.
228 setLastError("Unsupported bit depth");
229 return FALSE;
230 default:
231 setLastError("Unrecognized bit depth");
232 return FALSE;
233 }
234
235 setSize(width, height, components);
236
237 switch( header.mCompression )
238 {
239 case 0:
240 // Uncompressed
241 break;
242
243 case 1:
244 setLastError("8 bit RLE compression not supported.");
245 return FALSE;
246
247 case 2:
248 setLastError("4 bit RLE compression not supported.");
249 return FALSE;
250
251 case 3:
252 // Windows NT or Windows 95
253 break;
254
255 default:
256 setLastError("Unsupported compression format.");
257 return FALSE;
258 }
259
260 ////////////////////////////////////////////////////////////////////
261 // Part 3: Bitfield Masks and other color data
262 S32 extension_size = 0;
263 if( windows_nt_version )
264 {
265 if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) )
266 {
267 setLastError("Bitfield encoding requires 16 or 32 bits per pixel.");
268 return FALSE;
269 }
270
271 if( 0 != header.mNumColors )
272 {
273 setLastError("Bitfield encoding is not compatible with a color table.");
274 return FALSE;
275 }
276
277
278 extension_size = 4 * 3;
279 memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, extension_size);
280 }
281 else
282 if( windows_95_version )
283 {
284 Win95BmpHeaderExtension win_95_extension;
285 extension_size = sizeof( win_95_extension );
286
287 llassert( sizeof( win_95_extension ) + BITMAP_HEADER_SIZE == 108 );
288 memcpy( &win_95_extension, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, sizeof( win_95_extension ) );
289
290 if( 3 == header.mCompression )
291 {
292 memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4);
293 }
294
295 // Color correction ignored for now
296 }
297
298
299 ////////////////////////////////////////////////////////////////////
300 // Part 4: Color Palette (optional)
301 // Note: There's no color palette if there are 16 or more bits per pixel
302 S32 color_palette_size = 0;
303 mColorPaletteColors = 0;
304 if( header.mBitsPerPixel < 16 )
305 {
306 if( 0 == header.mNumColors )
307 {
308 mColorPaletteColors = (1 << header.mBitsPerPixel);
309 }
310 else
311 {
312 mColorPaletteColors = header.mNumColors;
313 }
314 }
315 color_palette_size = mColorPaletteColors * 4;
316
317 if( 0 != mColorPaletteColors )
318 {
319 mColorPalette = new U8[color_palette_size];
320 memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size );
321 }
322
323 return TRUE;
324}
325
326BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
327{
328 llassert_always(raw_image);
329
330 resetLastError();
331
332 // Check to make sure that this instance has been initialized with data
333 U8* mdata = getData();
334 if (!mdata || (0 == getDataSize()))
335 {
336 setLastError("llimagebmp trying to decode an image with no data!");
337 return FALSE;
338 }
339
340 raw_image->resize(getWidth(), getHeight(), 3);
341
342 U8* src = mdata + mBitmapOffset;
343 U8* dst = raw_image->getData();
344
345 BOOL success = FALSE;
346
347 switch( mBitsPerPixel )
348 {
349 case 8:
350 if( mColorPaletteColors >= 256 )
351 {
352 success = decodeColorTable8( dst, src );
353 }
354 break;
355
356 case 16:
357 success = decodeColorMask16( dst, src );
358 break;
359
360 case 24:
361 success = decodeTruecolor24( dst, src );
362 break;
363
364 case 32:
365 success = decodeColorMask32( dst, src );
366 break;
367 }
368
369 if( success && mOriginAtTop )
370 {
371 raw_image->verticalFlip();
372 }
373
374 return success;
375}
376
377U32 LLImageBMP::countTrailingZeros( U32 m )
378{
379 U32 shift_count = 0;
380 while( !(m & 1) )
381 {
382 shift_count++;
383 m >>= 1;
384 }
385 return shift_count;
386}
387
388
389BOOL LLImageBMP::decodeColorMask16( U8* dst, U8* src )
390{
391 llassert( 16 == mBitsPerPixel );
392
393 if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] )
394 {
395 // Use default values
396 mBitfieldMask[0] = 0x00007C00;
397 mBitfieldMask[1] = 0x000003E0;
398 mBitfieldMask[2] = 0x0000001F;
399 }
400
401 S32 src_row_span = getWidth() * 2;
402 S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
403
404 U32 r_shift = countTrailingZeros( mBitfieldMask[2] );
405 U32 g_shift = countTrailingZeros( mBitfieldMask[1] );
406 U32 b_shift = countTrailingZeros( mBitfieldMask[0] );
407
408 for( S32 row = 0; row < getHeight(); row++ )
409 {
410 for( S32 col = 0; col < getWidth(); col++ )
411 {
412 U32 value = *((U16*)src);
413 dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red
414 dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
415 dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue
416 src += 2;
417 dst += 3;
418 }
419 src += alignment_bytes;
420 }
421
422 return TRUE;
423}
424
425BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
426{
427 // Note: alpha is not supported
428
429 llassert( 32 == mBitsPerPixel );
430
431 if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] )
432 {
433 // Use default values
434 mBitfieldMask[0] = 0x00FF0000;
435 mBitfieldMask[1] = 0x0000FF00;
436 mBitfieldMask[2] = 0x000000FF;
437 }
438
439
440 S32 src_row_span = getWidth() * 4;
441 S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
442
443 U32 r_shift = countTrailingZeros( mBitfieldMask[0] );
444 U32 g_shift = countTrailingZeros( mBitfieldMask[1] );
445 U32 b_shift = countTrailingZeros( mBitfieldMask[2] );
446
447 for( S32 row = 0; row < getHeight(); row++ )
448 {
449 for( S32 col = 0; col < getWidth(); col++ )
450 {
451 U32 value = *((U32*)src);
452 dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red
453 dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
454 dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue
455 src += 4;
456 dst += 3;
457 }
458 src += alignment_bytes;
459 }
460
461 return TRUE;
462}
463
464
465BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
466{
467 llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) );
468
469 S32 src_row_span = getWidth() * 1;
470 S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
471
472 for( S32 row = 0; row < getHeight(); row++ )
473 {
474 for( S32 col = 0; col < getWidth(); col++ )
475 {
476 S32 index = 4 * src[0];
477 dst[0] = mColorPalette[index + 2]; // Red
478 dst[1] = mColorPalette[index + 1]; // Green
479 dst[2] = mColorPalette[index + 0]; // Blue
480 src++;
481 dst += 3;
482 }
483 src += alignment_bytes;
484 }
485
486 return TRUE;
487}
488
489
490BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
491{
492 llassert( 24 == mBitsPerPixel );
493 llassert( 3 == getComponents() );
494 S32 src_row_span = getWidth() * 3;
495 S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
496
497 for( S32 row = 0; row < getHeight(); row++ )
498 {
499 for( S32 col = 0; col < getWidth(); col++ )
500 {
501 dst[0] = src[2]; // Red
502 dst[1] = src[1]; // Green
503 dst[2] = src[0]; // Blue
504 src += 3;
505 dst += 3;
506 }
507 src += alignment_bytes;
508 }
509
510 return TRUE;
511}
512
513BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
514{
515 llassert_always(raw_image);
516
517 resetLastError();
518
519 S32 src_components = raw_image->getComponents();
520 S32 dst_components = ( src_components < 3 ) ? 1 : 3;
521
522 if( (2 == src_components) || (4 == src_components) )
523 {
524 llinfos << "Dropping alpha information during BMP encoding" << llendl;
525 }
526
527 setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);
528
529 U8 magic[14];
530 LLBMPHeader header;
531 int header_bytes = 14+sizeof(header);
532 llassert(header_bytes == 54);
533 if (getComponents() == 1)
534 {
535 header_bytes += 1024; // Need colour LUT.
536 }
537 int line_bytes = getComponents() * getWidth();
538 int alignment_bytes = (3 * line_bytes) % 4;
539 line_bytes += alignment_bytes;
540 int file_bytes = line_bytes*getHeight() + header_bytes;
541
542 // Allocate the new buffer for the data.
543 allocateData(file_bytes);
544
545 magic[0] = 'B'; magic[1] = 'M';
546 magic[2] = (U8) file_bytes;
547 magic[3] = (U8)(file_bytes>>8);
548 magic[4] = (U8)(file_bytes>>16);
549 magic[5] = (U8)(file_bytes>>24);
550 magic[6] = magic[7] = magic[8] = magic[9] = 0;
551 magic[10] = (U8) header_bytes;
552 magic[11] = (U8)(header_bytes>>8);
553 magic[12] = (U8)(header_bytes>>16);
554 magic[13] = (U8)(header_bytes>>24);
555 header.mSize = 40;
556 header.mWidth = getWidth();
557 header.mHeight = getHeight();
558 header.mPlanes = 1;
559 header.mBitsPerPixel = (getComponents()==1)?8:24;
560 header.mCompression = 0;
561 header.mAlignmentPadding = 0;
562 header.mImageSize = 0;
563#if LL_DARWIN
564 header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834; // 72dpi
565#else
566 header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0;
567#endif
568 header.mNumColors = header.mNumColorsImportant = 0;
569
570 // convert BMP header to little endian (no-op on little endian builds)
571 llendianswizzleone(header.mSize);
572 llendianswizzleone(header.mWidth);
573 llendianswizzleone(header.mHeight);
574 llendianswizzleone(header.mPlanes);
575 llendianswizzleone(header.mBitsPerPixel);
576 llendianswizzleone(header.mCompression);
577 llendianswizzleone(header.mAlignmentPadding);
578 llendianswizzleone(header.mImageSize);
579 llendianswizzleone(header.mHorzPelsPerMeter);
580 llendianswizzleone(header.mVertPelsPerMeter);
581 llendianswizzleone(header.mNumColors);
582 llendianswizzleone(header.mNumColorsImportant);
583
584 U8* mdata = getData();
585
586 // Output magic, then header, then the palette table, then the data.
587 U32 cur_pos = 0;
588 memcpy(mdata, magic, 14);
589 cur_pos += 14;
590 memcpy(mdata+cur_pos, &header, 40);
591 cur_pos += 40;
592 if (getComponents() == 1)
593 {
594 S32 n;
595 for (n=0; n < 256; n++)
596 {
597 mdata[cur_pos++] = (U8)n;
598 mdata[cur_pos++] = (U8)n;
599 mdata[cur_pos++] = (U8)n;
600 mdata[cur_pos++] = 0;
601 }
602 }
603
604 // Need to iterate through, because we need to flip the RGB.
605 const U8* src = raw_image->getData();
606 U8* dst = mdata + cur_pos;
607
608 for( S32 row = 0; row < getHeight(); row++ )
609 {
610 for( S32 col = 0; col < getWidth(); col++ )
611 {
612 switch( src_components )
613 {
614 case 1:
615 *dst++ = *src++;
616 break;
617 case 2:
618 {
619 U32 lum = src[0];
620 U32 alpha = src[1];
621 *dst++ = (U8)(lum * alpha / 255);
622 src += 2;
623 break;
624 }
625 case 3:
626 case 4:
627 dst[0] = src[2];
628 dst[1] = src[1];
629 dst[2] = src[0];
630 src += src_components;
631 dst += 3;
632 break;
633 }
634
635 for( S32 i = 0; i < alignment_bytes; i++ )
636 {
637 *dst++ = 0;
638 }
639 }
640 }
641
642 return TRUE;
643}