gfxconversion/bmconv_s60/src/PBMTOBM.CPP
changeset 0 f453ebb75370
equal deleted inserted replaced
-1:000000000000 0:f453ebb75370
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <assert.h>
       
    19 #include "BMCONV.H"
       
    20 
       
    21 EpocLoader::EpocLoader():
       
    22 	iPbmBits(NULL)
       
    23 	{}
       
    24 
       
    25 EpocLoader::~EpocLoader()
       
    26 	{
       
    27 	delete iPbmBits;
       
    28 	}
       
    29 
       
    30 int EpocLoader::EpocBitmapCount(char* aFileName, int& aCount, int& isRomFormat)
       
    31     {
       
    32 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) || defined(__CW32__)
       
    33 	fstream file(aFileName, ios::in | ios::binary);
       
    34 #else //!__MSVCDOTNET__
       
    35 	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
       
    36 #endif //__MSVCDOTNET__
       
    37 
       
    38 	if (file.is_open()==0)
       
    39 		return Files;
       
    40 
       
    41 	long int wordbuffer;
       
    42 	file.read((char *)&wordbuffer,4);
       
    43 	if (file.gcount()!=4)
       
    44 		return SourceFile;
       
    45 	if (wordbuffer==KMultiBitmapRomImageUid)
       
    46 		{
       
    47 		// ROM format file - next 4 bytes are the number of bitmaps
       
    48 		isRomFormat=1;
       
    49 		}
       
    50 	else
       
    51 		{
       
    52 		if (wordbuffer!=KWriteOnceFileStoreUid)
       
    53 			return SourceFile;
       
    54 		isRomFormat=0;
       
    55 		file.read((char *)&wordbuffer,4);
       
    56 		if (file.gcount()!=4 || wordbuffer!=KMultiBitmapFileImageUid)
       
    57 			return SourceFile;
       
    58 		file.read((char *)&wordbuffer,4);
       
    59 		if (file.gcount()!=4 || wordbuffer!=0)
       
    60 			return SourceFile;
       
    61 		file.read((char *)&wordbuffer,4);
       
    62 		if (file.gcount()!=4 || wordbuffer!=KMultiBitmapFileImageChecksum)
       
    63 			return SourceFile;
       
    64 		file.read((char *)&wordbuffer,4);
       
    65 		if (file.gcount()!=4)
       
    66 			return SourceFile;
       
    67 		file.seekg(wordbuffer,ios::beg);
       
    68 		}
       
    69 	file.read((char *)&wordbuffer,4);
       
    70 	if (file.gcount()!=4)
       
    71 		return SourceFile;
       
    72 	aCount=wordbuffer;
       
    73 	return NoError;
       
    74     }
       
    75 
       
    76 int EpocLoader::LoadEpocBitmap(char* aFileName,int aIndex)
       
    77 	{
       
    78 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) || defined(__CW32__)
       
    79 	fstream file(aFileName, ios::in | ios::binary);
       
    80 #else //!__MSVCDOTNET__
       
    81 	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
       
    82 #endif //__MSVCDOTNET__
       
    83 
       
    84 	if (file.is_open()==0)
       
    85 		return Files;
       
    86 
       
    87 	long int wordbuffer;
       
    88 	file.read((char *)&wordbuffer,4);
       
    89 	if (file.gcount()!=4)
       
    90 		return SourceFile;
       
    91 	file.close();
       
    92 
       
    93 	if (wordbuffer==KMultiBitmapRomImageUid)
       
    94 		return LoadRom(aFileName,aIndex);
       
    95 
       
    96 	return LoadFile(aFileName,aIndex);
       
    97 	}
       
    98 
       
    99 int EpocLoader::LoadFile(char* aFileName,int aIndex)
       
   100 	{
       
   101 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) || defined(__CW32__)
       
   102 	fstream file(aFileName, ios::in | ios::binary);
       
   103 #else //!__MSVCDOTNET__
       
   104 	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
       
   105 #endif //__MSVCDOTNET__
       
   106 
       
   107 	if (file.is_open()==0)
       
   108 		return Files;
       
   109 
       
   110 	long int wordbuffer;
       
   111 	file.read((char *)&wordbuffer,4);
       
   112 	if (file.gcount()!=4 || wordbuffer!=KWriteOnceFileStoreUid)
       
   113 		return SourceFile;
       
   114 	file.read((char *)&wordbuffer,4);
       
   115 	if (file.gcount()!=4 || wordbuffer!=KMultiBitmapFileImageUid)
       
   116 		return SourceFile;
       
   117 	file.read((char *)&wordbuffer,4);
       
   118 	if (file.gcount()!=4 || wordbuffer!=0)
       
   119 		return SourceFile;
       
   120 	file.read((char *)&wordbuffer,4);
       
   121 	if (file.gcount()!=4 || wordbuffer!=KMultiBitmapFileImageChecksum)
       
   122 		return SourceFile;
       
   123 	file.read((char *)&wordbuffer,4);
       
   124 	if (file.gcount()!=4)
       
   125 		return SourceFile;
       
   126 	file.seekg(wordbuffer,ios::beg);
       
   127 	file.read((char *)&wordbuffer,4);
       
   128 	if (file.gcount()!=4)
       
   129 		return SourceFile;
       
   130 
       
   131 	int numsources=wordbuffer;
       
   132 	if (aIndex >= numsources)
       
   133 		return OutOfRange;
       
   134 	file.seekg(aIndex*4,ios::cur);
       
   135 	file.read((char *)&wordbuffer,4);
       
   136 	if (file.gcount()!=4)
       
   137 		return SourceFile;
       
   138 	file.seekg(wordbuffer,ios::beg);
       
   139 	int ret = DoLoadFile(file);
       
   140 	file.close();
       
   141 	return ret;
       
   142 	}
       
   143 
       
   144 int EpocLoader::LoadRom(char* aFileName,int aIndex)
       
   145 	{
       
   146 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) || defined(__CW32__)
       
   147 	fstream file(aFileName, ios::in | ios::binary);
       
   148 #else //!__MSVCDOTNET__
       
   149 	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
       
   150 #endif //__MSVCDOTNET__
       
   151 
       
   152 	if (file.is_open()==0)
       
   153 		return Files;
       
   154 
       
   155 	long int wordbuffer;
       
   156 	file.read((char *)&wordbuffer,4);
       
   157 	if (file.gcount()!=4)
       
   158 		return SourceFile;
       
   159 	if (wordbuffer!=KMultiBitmapRomImageUid)
       
   160 		return SourceFile;
       
   161 	file.read((char *)&wordbuffer,4);
       
   162 	if (file.gcount()!=4)
       
   163 		return SourceFile;
       
   164 	if (aIndex>=wordbuffer)
       
   165 		return OutOfRange;
       
   166 	file.seekg(aIndex*4,ios::cur);
       
   167 	file.read((char *)&wordbuffer,4);
       
   168 	if (file.gcount()!=4)
       
   169 		return SourceFile;
       
   170 	file.seekg(wordbuffer,ios::beg);
       
   171 	int ret=DoLoadRom(file);
       
   172 	file.close();
       
   173 	return ret;
       
   174 	}
       
   175 
       
   176 int EpocLoader::DoLoadFile(fstream& aFile)
       
   177 	{
       
   178 	long size = sizeof(SEpocBitmapHeader);
       
   179 	aFile.read((char *)&iPbmHeader,size);
       
   180 	if (aFile.gcount()!=size)
       
   181 		return SourceFile;
       
   182 	iOriginalPbmHeader = iPbmHeader;
       
   183 	size=iPbmHeader.iBitmapSize-iPbmHeader.iStructSize;
       
   184 
       
   185 	iPbmBits=new char[size];
       
   186 	if (iPbmBits==NULL)
       
   187 		return NoMemory;
       
   188 	memset(iPbmBits,0xff,size);
       
   189 	aFile.read(iPbmBits,size);
       
   190 	aFile.close();
       
   191 	if (aFile.gcount() != size)
       
   192 		return SourceFile;
       
   193 
       
   194 	if (iPbmHeader.iCompression != ENoBitmapCompression)
       
   195 		{
       
   196 		return Decompress(size);
       
   197 		}
       
   198 
       
   199 	return NoError;
       
   200 	}
       
   201 
       
   202 int EpocLoader::DoLoadRom(fstream& aFile)
       
   203 	{
       
   204 	Bitmap bmp;
       
   205 	long size=sizeof(Bitmap);
       
   206 	aFile.read((char*)&bmp,size);
       
   207 	if (aFile.gcount() != size)
       
   208 		return SourceFile;
       
   209 
       
   210 	size = bmp.iHeader.iBitmapSize - sizeof(SEpocBitmapHeader);
       
   211 	iPbmBits = new char[size];
       
   212 	if (iPbmBits == NULL)
       
   213 		return NoMemory;
       
   214 	memset(iPbmBits,0xff,size);
       
   215 
       
   216 	aFile.read(iPbmBits,size);
       
   217 	if (aFile.gcount() != size)
       
   218 		return SourceFile;
       
   219 	iPbmHeader = bmp.iHeader;
       
   220 	iOriginalPbmHeader = iPbmHeader;
       
   221 
       
   222 	if (iPbmHeader.iCompression != ENoBitmapCompression)
       
   223 		{
       
   224 		return Decompress(size);
       
   225 		}
       
   226 
       
   227 	return NoError;
       
   228 	}
       
   229 
       
   230 int EpocLoader::Decompress(int aSize)
       
   231 	{
       
   232 	int byteWidth = BitmapUtils::ByteWidth(iPbmHeader.iWidthInPixels,iPbmHeader.iBitsPerPixel);
       
   233 	int expandedsize = byteWidth * iPbmHeader.iHeightInPixels;
       
   234 	char* newbits = new char[expandedsize];
       
   235 	if (newbits == NULL)
       
   236 		return NoMemory;
       
   237 	memset(newbits,0xff,expandedsize);
       
   238 	int ret = NoError;
       
   239 	switch (iPbmHeader.iCompression)
       
   240 		{
       
   241 	case EByteRLECompression:
       
   242 		ret = ExpandByteRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   243 		break;
       
   244 	case ETwelveBitRLECompression:
       
   245 		ret = ExpandTwelveBitRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   246 		break;
       
   247 	case ESixteenBitRLECompression:
       
   248 		ret = ExpandSixteenBitRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   249 		break;
       
   250 	case ETwentyFourBitRLECompression:
       
   251 		ret = ExpandTwentyFourBitRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   252 		break;
       
   253 	case EThirtyTwoUBitRLECompression:
       
   254 		ret = ExpandThirtyTwoUBitRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   255 		break;
       
   256 	case EThirtyTwoABitRLECompression:
       
   257 		ret = ExpandThirtyTwoABitRLEData(newbits,expandedsize,iPbmBits,aSize);
       
   258 		break;
       
   259 	default:
       
   260 		ret = UnknownCompression;
       
   261 		break;
       
   262 		}
       
   263 	delete iPbmBits;
       
   264 	iPbmBits = newbits;
       
   265 	iPbmHeader.iCompression = ENoBitmapCompression;
       
   266 	iPbmHeader.iBitmapSize += expandedsize-aSize;
       
   267 	return ret;
       
   268 	}
       
   269 
       
   270 int EpocLoader::ExpandByteRLEData(char* aDest,int aDestSize,char* aSrce,int aSrceSize)
       
   271 	{
       
   272 	char* srcelimit=aSrce+aSrceSize;
       
   273 	char* destlimit=aDest+aDestSize;
       
   274 	while(aSrce<srcelimit && aDest<destlimit)
       
   275 		{
       
   276 		char count=*aSrce++;
       
   277 		if (count<0)
       
   278 			{
       
   279 			int runLength=-count;
       
   280 			memcpy(aDest,aSrce,runLength);
       
   281 			aSrce+=runLength;
       
   282 			aDest+=runLength;
       
   283 			}
       
   284 		else
       
   285 			{
       
   286 			char value=*aSrce++;
       
   287 			while(count>=0)
       
   288 				{
       
   289 				*aDest++=value;
       
   290 				count--;
       
   291 				}
       
   292 			}
       
   293 		}
       
   294 	if (aSrce!=srcelimit || aDest!=destlimit)
       
   295 		return DecompressionError;
       
   296 	return NoError;
       
   297 	}
       
   298 
       
   299 int EpocLoader::ExpandTwelveBitRLEData(char* aDest,int aDestSizeInBytes,char* aSrce,int aSrceSizeInBytes)
       
   300 	{
       
   301 	unsigned short* srcePtr = (unsigned short*)aSrce;
       
   302 	unsigned short* destPtr = (unsigned short*)aDest;
       
   303 	unsigned short* srcePtrLimit = srcePtr + (aSrceSizeInBytes / 2);
       
   304 	unsigned short* destPtrLimit = destPtr + (aDestSizeInBytes / 2);
       
   305 
       
   306 	while (srcePtr < srcePtrLimit && destPtr < destPtrLimit)
       
   307 		{
       
   308 		unsigned short value = *srcePtr++;
       
   309 		int runLength = (value >> 12) + 1;
       
   310 		value &= 0x0fff;
       
   311 
       
   312 		for (;runLength > 0;runLength--)
       
   313 			*destPtr++ = value;
       
   314 		}
       
   315 
       
   316 	if (srcePtr != srcePtrLimit || destPtr != destPtrLimit)
       
   317 		return DecompressionError;
       
   318 
       
   319 	return NoError;
       
   320 	}
       
   321 
       
   322 int EpocLoader::ExpandSixteenBitRLEData(char* aDest,int aDestSizeInBytes,char* aSrce,int aSrceSizeInBytes)
       
   323 	{
       
   324 	char* srcePtrLimit = aSrce + aSrceSizeInBytes;
       
   325 	unsigned short* destPtr = (unsigned short*)aDest;
       
   326 	unsigned short* destPtrLimit = destPtr + (aDestSizeInBytes / 2);
       
   327 
       
   328 	while (aSrce < srcePtrLimit && destPtr < destPtrLimit)
       
   329 		{
       
   330 		int runLength = *aSrce++;
       
   331 
       
   332 		if (runLength >= 0)
       
   333 			{
       
   334 			unsigned short value = *((unsigned short*)(aSrce));
       
   335 			aSrce += 2;
       
   336 			for (runLength++; runLength > 0; runLength--)
       
   337 				*destPtr++ = value;
       
   338 			}
       
   339 		else
       
   340 			{
       
   341 			runLength = -runLength;
       
   342 			int byteLength = runLength * 2;
       
   343 			memcpy(destPtr,aSrce,byteLength);
       
   344 			aSrce += byteLength;
       
   345 			destPtr += runLength;
       
   346 			}
       
   347 		}
       
   348 
       
   349 	if (aSrce != srcePtrLimit || destPtr != destPtrLimit)
       
   350 		return DecompressionError;
       
   351 
       
   352 	return NoError;
       
   353 	}
       
   354 
       
   355 int EpocLoader::ExpandTwentyFourBitRLEData(char* aDest,int aDestSizeInBytes,char* aSrce,int aSrceSizeInBytes)
       
   356 	{
       
   357 	char* srcePtrLimit = aSrce + aSrceSizeInBytes;
       
   358 	char* destPtrLimit = aDest + aDestSizeInBytes;
       
   359 
       
   360 	while (aSrce < srcePtrLimit && aDest < destPtrLimit)
       
   361 		{
       
   362 		int runLength = *aSrce++;
       
   363 
       
   364 		if (runLength >= 0)
       
   365 			{
       
   366 			char component1 = *aSrce++;
       
   367 			char component2 = *aSrce++;
       
   368 			char component3 = *aSrce++;
       
   369 			for (runLength++; runLength > 0; runLength--)
       
   370 				{
       
   371 				*aDest++ = component1;
       
   372 				*aDest++ = component2;
       
   373 				*aDest++ = component3;
       
   374 				}
       
   375 			}
       
   376 		else
       
   377 			{
       
   378 			runLength = -runLength;
       
   379 			int byteLength = runLength * 3;
       
   380 			memcpy(aDest,aSrce,byteLength);
       
   381 			aSrce += byteLength;
       
   382 			aDest += byteLength;
       
   383 			}
       
   384 		}
       
   385 
       
   386 	if (aSrce != srcePtrLimit || aDest != destPtrLimit)
       
   387 		return DecompressionError;
       
   388 
       
   389 	return NoError;
       
   390 	}
       
   391 
       
   392 /** The function decodes 24-bit compressed pixel buffer into the 32-bit buffer, where top bytes are unused*/
       
   393 int EpocLoader::ExpandThirtyTwoUBitRLEData(char* aDest,int aDestSizeInBytes,char* aSrce,int aSrceSizeInBytes)
       
   394 	{
       
   395 	char* srcePtrLimit = aSrce + aSrceSizeInBytes;
       
   396 	char* destPtrLimit = aDest + aDestSizeInBytes;
       
   397 
       
   398 	while (aSrce < srcePtrLimit && aDest < destPtrLimit)
       
   399 		{
       
   400 		int runLength = *aSrce++;
       
   401 
       
   402 		if (runLength >= 0)
       
   403 			{
       
   404 			char component1 = *aSrce++;
       
   405 			char component2 = *aSrce++;
       
   406 			char component3 = *aSrce++;
       
   407 			for (runLength++; runLength > 0; runLength--)
       
   408 				{
       
   409 				*aDest++ = component1;
       
   410 				*aDest++ = component2;
       
   411 				*aDest++ = component3;
       
   412 				aDest++;
       
   413 				}
       
   414 			}
       
   415 		else 
       
   416 			{
       
   417 			runLength = -runLength;
       
   418 			for(int ii = 0; ii < runLength; ii++)
       
   419 				{
       
   420 				memcpy(aDest,aSrce,3);
       
   421 				aSrce += 3;
       
   422 				aDest += 4;
       
   423 				}
       
   424 			}
       
   425 		}
       
   426 
       
   427 	if (aSrce != srcePtrLimit || aDest != destPtrLimit)
       
   428 		return DecompressionError;
       
   429 
       
   430 	return NoError;
       
   431 	}
       
   432 
       
   433 /** The function decodes 32-bit compressed pixel buffer into the 32-bit buffer, where top bytes are alpha channel*/
       
   434 int EpocLoader::ExpandThirtyTwoABitRLEData(char* aDest,int aDestSizeInBytes,char* aSrce,int aSrceSizeInBytes)
       
   435 	{
       
   436 	char* srcePtrLimit = aSrce + aSrceSizeInBytes;
       
   437 	char* destPtrLimit = aDest + aDestSizeInBytes;
       
   438 
       
   439 	while (aSrce < srcePtrLimit && aDest < destPtrLimit)
       
   440 		{
       
   441 		int runLength = *aSrce++;
       
   442 
       
   443 		if (runLength >= 0)
       
   444 			{
       
   445 			char component1 = *aSrce++;
       
   446 			char component2 = *aSrce++;
       
   447 			char component3 = *aSrce++;
       
   448 			char component4 = *aSrce++;
       
   449 			for (runLength++; runLength > 0; runLength--)
       
   450 				{
       
   451 				*aDest++ = component1;
       
   452 				*aDest++ = component2;
       
   453 				*aDest++ = component3;
       
   454 				*aDest++ = component4;
       
   455 				}
       
   456 			}
       
   457 		else 
       
   458 			{
       
   459 			runLength = -runLength;
       
   460 			memcpy(aDest,aSrce,4*runLength);
       
   461 			aSrce += 4*runLength;
       
   462 			aDest += 4*runLength;
       
   463 			}
       
   464 		}
       
   465 
       
   466 	if (aSrce != srcePtrLimit || aDest != destPtrLimit)
       
   467 		return DecompressionError;
       
   468 
       
   469 	return NoError;
       
   470 	}
       
   471 
       
   472 TRgb EpocLoader::GetPixel(int aXCoord,int aYCoord)
       
   473 	{
       
   474 	unsigned char col;
       
   475 	aXCoord%=iPbmHeader.iWidthInPixels;
       
   476 	aYCoord%=iPbmHeader.iHeightInPixels;
       
   477 	int byteWidth = BitmapUtils::ByteWidth(iPbmHeader.iWidthInPixels,iPbmHeader.iBitsPerPixel);
       
   478 	int yOffset = aYCoord * byteWidth;
       
   479 
       
   480 	switch(iPbmHeader.iBitsPerPixel)
       
   481 		{
       
   482 		case 1:
       
   483 			col = iPbmBits[yOffset + (aXCoord / 8)];
       
   484 			col >>= (aXCoord&7);
       
   485 			return TRgb::Gray2(col & 1);
       
   486 		case 2:
       
   487 			col = iPbmBits[yOffset + (aXCoord / 4)];
       
   488 			col = (unsigned char)(col>>(2*(aXCoord%4)));
       
   489 			return TRgb::Gray4(col & 3);
       
   490 		case 4:
       
   491 			col = iPbmBits[yOffset + (aXCoord / 2)];
       
   492 			if (aXCoord & 1)
       
   493 				col >>= 4;
       
   494 			col &= 0xf;
       
   495 			if (iPbmHeader.iColor==EColorBitmap)
       
   496 				return TRgb::Color16(col);
       
   497 			else
       
   498 				return TRgb::Gray16(col);
       
   499 		case 8:
       
   500 			col=iPbmBits[yOffset + aXCoord];
       
   501 			if (iPbmHeader.iColor==EColorBitmap)
       
   502 				return TRgb::Color256(col);
       
   503 			else
       
   504 				return TRgb::Gray256(col);
       
   505 		case 12:
       
   506 		case 16:
       
   507 			{
       
   508 			unsigned short* shortPtr = (unsigned short*)&iPbmBits[yOffset + (aXCoord * 2)];
       
   509 			if (iPbmHeader.iBitsPerPixel == 12)
       
   510 				return TRgb::Color4K(*shortPtr);
       
   511 			else
       
   512 				return TRgb::Color64K(*shortPtr);
       
   513 			}
       
   514 		case 24:
       
   515 			{
       
   516 			char* pixelPtr = iPbmBits + yOffset + (aXCoord * 3);
       
   517 			TRgb pixelColor;
       
   518 			pixelColor.iBlue = *pixelPtr++;
       
   519 			pixelColor.iGreen = *pixelPtr++;
       
   520 			pixelColor.iRed = *pixelPtr;
       
   521 			return pixelColor;
       
   522 			}
       
   523 		case 32:
       
   524 			{
       
   525 			char* pixelPtr = iPbmBits + yOffset + (aXCoord * 4);
       
   526 			TRgb pixelColor;
       
   527 			pixelColor.iBlue = *pixelPtr++;
       
   528 			pixelColor.iGreen = *pixelPtr++;
       
   529 			pixelColor.iRed = *pixelPtr++;
       
   530 			pixelColor.iSpare = *pixelPtr;
       
   531 			return pixelColor;
       
   532 			}
       
   533 		default:
       
   534 			return TRgb(0);
       
   535 		}
       
   536 	}
       
   537 
       
   538 unsigned char EpocLoader::GetAlpha(int aXCoord,int aYCoord)
       
   539 	{
       
   540 	aXCoord%=iPbmHeader.iWidthInPixels;
       
   541 	aYCoord%=iPbmHeader.iHeightInPixels;
       
   542 	int byteWidth = BitmapUtils::ByteWidth(iPbmHeader.iWidthInPixels,iPbmHeader.iBitsPerPixel);
       
   543 	int yOffset = aYCoord * byteWidth;
       
   544 
       
   545 	assert(iPbmHeader.iBitsPerPixel == 32); // this method must only be called for 32bpp bitmaps!
       
   546 
       
   547 	char* pixelPtr = iPbmBits + yOffset + (aXCoord * 4);
       
   548 	pixelPtr += 3; // skip over RGB
       
   549 	unsigned char col = *pixelPtr;
       
   550 	return col;	
       
   551 	}
       
   552 
       
   553 int EpocLoader::SaveBitmap(char* aFileName)
       
   554 	{
       
   555 	TBitmapFileHeader fileheader;
       
   556 	TBitmapInfoHeader bmpHeader;
       
   557 	char* bmpBits;
       
   558 
       
   559 	bmpHeader.biSize = sizeof(TBitmapInfoHeader);
       
   560 	bmpHeader.biWidth = iPbmHeader.iWidthInPixels;
       
   561 	bmpHeader.biHeight = iPbmHeader.iHeightInPixels;
       
   562 	bmpHeader.biPlanes = 1;
       
   563 	bmpHeader.biBitCount = 24;
       
   564 	bmpHeader.biCompression = 0;
       
   565 	bmpHeader.biSizeImage = 0;
       
   566 	bmpHeader.biXPelsPerMeter = 0;
       
   567 	bmpHeader.biYPelsPerMeter = 0;
       
   568 	bmpHeader.biClrUsed = 0;
       
   569 	bmpHeader.biClrImportant = 0;
       
   570 
       
   571 	long byteWidth = ((bmpHeader.biWidth * 3) + 3) & ~3;
       
   572 	long destlength = bmpHeader.biHeight * byteWidth;
       
   573 
       
   574 	fileheader.bfType = 'B'+('M'<<8);
       
   575 	fileheader.bfSize = sizeof(TBitmapFileHeader)+sizeof(TBitmapInfoHeader)+destlength;
       
   576 	fileheader.bfReserved1 = 0;
       
   577 	fileheader.bfReserved2 = 0;
       
   578 	fileheader.bfOffBits = sizeof(TBitmapFileHeader)+sizeof(TBitmapInfoHeader);
       
   579 
       
   580 	bmpBits = new char[destlength];
       
   581 	if (bmpBits == NULL)
       
   582 		return NoMemory;
       
   583 	memset(bmpBits,0xff,destlength);
       
   584 
       
   585 	for(long y=0;y<bmpHeader.biHeight;y++)
       
   586 		{
       
   587 		char* dest=&bmpBits[(bmpHeader.biHeight-y-1)*byteWidth];
       
   588 		for(long x=0;x<bmpHeader.biWidth;x++)
       
   589 			{
       
   590 			TRgb pixel=GetPixel(x,y);
       
   591 			*dest++=pixel.iBlue;
       
   592 			*dest++=pixel.iGreen;
       
   593 			*dest++=pixel.iRed;
       
   594 			}
       
   595 		}
       
   596 
       
   597 	fstream file(aFileName, ios::out | ios::binary);
       
   598 
       
   599 	if (file.is_open()==0)
       
   600 		{
       
   601 		delete bmpBits;
       
   602 		return DestFile;
       
   603 		}
       
   604 
       
   605 	file.write((char *)&fileheader,sizeof(TBitmapFileHeader));
       
   606 	file.write((char *)&bmpHeader,sizeof(TBitmapInfoHeader));
       
   607 	file.write((char *)bmpBits,destlength);
       
   608 	file.close();
       
   609 
       
   610 	delete bmpBits;
       
   611 
       
   612 	if (iPbmHeader.iColor == EColorBitmapAlpha)
       
   613 		SaveAlpha(aFileName);
       
   614 	return NoError;
       
   615 	}
       
   616 
       
   617 
       
   618 int EpocLoader::SaveAlpha(char* aFileName)
       
   619 	{
       
   620 	TBitmapFileHeader fileheader;
       
   621 	TBitmapInfoHeader alphaHeader;
       
   622 
       
   623 	alphaHeader.biSize = sizeof(TBitmapInfoHeader);
       
   624 	alphaHeader.biWidth = iPbmHeader.iWidthInPixels;
       
   625 	alphaHeader.biHeight = iPbmHeader.iHeightInPixels;
       
   626 	alphaHeader.biPlanes = 1;
       
   627 	alphaHeader.biBitCount = 8;
       
   628 	alphaHeader.biCompression = 0;
       
   629 	alphaHeader.biSizeImage = 0;
       
   630 	alphaHeader.biXPelsPerMeter = 0;
       
   631 	alphaHeader.biYPelsPerMeter = 0;
       
   632 	alphaHeader.biClrUsed = 256;
       
   633 	alphaHeader.biClrImportant = 0;
       
   634 
       
   635 	const long paletteSize = 1024;
       
   636 
       
   637 	// ensure bytes-per-scanline is a large enough multiple of 4
       
   638 	long byteWidth = (alphaHeader.biWidth + 3) & ~3; 
       
   639 	long destlength = alphaHeader.biHeight * byteWidth;
       
   640 	alphaHeader.biSizeImage = destlength;
       
   641 
       
   642 	fileheader.bfType = 'B'+('M'<<8);
       
   643 	fileheader.bfSize = sizeof(TBitmapFileHeader)+sizeof(TBitmapInfoHeader)+paletteSize+destlength;
       
   644 	fileheader.bfReserved1 = 0;
       
   645 	fileheader.bfReserved2 = 0;
       
   646 	fileheader.bfOffBits = sizeof(TBitmapFileHeader)+sizeof(TBitmapInfoHeader)+paletteSize;
       
   647 
       
   648 	// we need to output the grayscale palette before the actual alpha data as this is an 8bpp BMP
       
   649 	char* palette = new char[paletteSize]; // 256 colors x 4bytes/color (r,g,b,unused)
       
   650 	if (palette == NULL)
       
   651 		return NoMemory;
       
   652 	memset(palette,0,paletteSize);
       
   653 	char* pEnt = palette;
       
   654 	for (long p=0;p<256;++p)
       
   655 		{
       
   656 		unsigned char col = (unsigned char)p;
       
   657 		*pEnt++=col;
       
   658 		*pEnt++=col;
       
   659 		*pEnt++=col;
       
   660 		pEnt++;
       
   661 		}
       
   662 
       
   663 	char* alphaBits = new char[destlength];
       
   664 	if (alphaBits == NULL)
       
   665 		{
       
   666 		delete [] palette;
       
   667 		return NoMemory;
       
   668 		}
       
   669 	memset(alphaBits,0,destlength);
       
   670 
       
   671 	for(long y=0;y<alphaHeader.biHeight;y++)
       
   672 		{
       
   673 		char* dest=&alphaBits[(alphaHeader.biHeight-y-1)*byteWidth];
       
   674 		for(long x=0;x<alphaHeader.biWidth;x++)
       
   675 			{
       
   676 			unsigned char alphaVal=GetAlpha(x,y);
       
   677 			*dest++=alphaVal;
       
   678 			}
       
   679 		}
       
   680 
       
   681 	int fileNameLen = strlen(aFileName);
       
   682 	char* alphaFileName = new char[fileNameLen + 7];// -alpha suffix is 6 chars, plus NUL termination
       
   683 	if (alphaFileName == NULL)
       
   684 		{
       
   685 		delete [] palette;
       
   686 		delete [] alphaBits;
       
   687 		return NoMemory;
       
   688 		}
       
   689 	int dotPos = -1;
       
   690 	for (int i = 0; i < fileNameLen; ++i)
       
   691 		if (aFileName[i]=='.')
       
   692 			dotPos=i;
       
   693 	int prefixLen = (dotPos>=0?dotPos:fileNameLen);
       
   694 	memcpy(alphaFileName,aFileName,prefixLen);
       
   695 	const char* suffix = "-alpha";
       
   696 	memcpy(alphaFileName+prefixLen,suffix,6);
       
   697 	if (dotPos>=0)
       
   698 		memcpy(alphaFileName+prefixLen+6,aFileName+dotPos,fileNameLen-dotPos);
       
   699 	*(alphaFileName + fileNameLen + 6) = '\0';
       
   700 	fstream file(alphaFileName, ios::out | ios::binary);
       
   701 	if (file.is_open()==0)
       
   702 		{
       
   703 		delete [] alphaFileName;
       
   704 		delete [] alphaBits;
       
   705 		delete [] palette;
       
   706 		return DestFile;
       
   707 		}
       
   708 
       
   709 	file.write((char *)&fileheader,sizeof(TBitmapFileHeader));
       
   710 	file.write((char *)&alphaHeader,sizeof(TBitmapInfoHeader));
       
   711 	file.write((char *)palette,paletteSize);
       
   712 	file.write((char *)alphaBits,destlength);
       
   713 	file.close();
       
   714 
       
   715 	delete [] alphaFileName;
       
   716 	delete [] alphaBits;
       
   717 	delete [] palette;
       
   718 	return NoError;
       
   719 	}
       
   720 
       
   721 int EpocLoader::DupBitmap(SEpocBitmapHeader*& aPbm)
       
   722 	{
       
   723 	char* newPbm = new char[iPbmHeader.iBitmapSize];
       
   724 	if (newPbm == NULL)
       
   725 		return NoMemory;
       
   726 	memcpy(newPbm, &iPbmHeader, sizeof(SEpocBitmapHeader));
       
   727 	memcpy(newPbm+sizeof(SEpocBitmapHeader), iPbmBits, iPbmHeader.iBitmapSize - sizeof(SEpocBitmapHeader));
       
   728 	aPbm = (SEpocBitmapHeader*)newPbm;
       
   729 	return NoError;
       
   730 	}