PageRenderTime 77ms CodeModel.GetById 2ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llimage/llimagebmp.cpp

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