graphicstools/gdi_tools/bmconv/BMTOPBM.CPP
author Faisal Memon <faisal.memon@nokia.com>
Fri, 14 May 2010 15:41:33 +0100
branchNewGraphicsArchitecture
changeset 64 5c983aa672ea
parent 0 5d03bc08d59c
permissions -rw-r--r--
Merge 1. Pull in cpp files in the performance enhanced Khronos RI OVG files which are newly added. I've ignored platform-specific cpp files for linux, macosx, and null operating systems because this local solution has its own platform glue (i.e. facility to target Bitmaps but no full windowing support). I've ignored sfEGLInterface.cpp because this is used as a bridge to go from EGL to Nokia's Platsim which offers an EGL service. That's not relevant to this implementation because this is ARM side code, not Intel side. I just left a comment to sfEGLInterface.cpp in case we need to pick up this later on. The current code compiles on winscw. Prior to this fix, the code works on winscw, and can launch the SVG tiger (tiger.exe). That takes about 20 seconds to render. I hope to always be able to show this icon on each commit, and the plan is for the render time to reduce with this series of submissions. On this commit, the tiger renders ok in 20 seconds.

// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include "BMCONV.H"

BitmapLoader::BitmapLoader():
	iNumBmpColors(0),
	iBmpColors(NULL),
	iBmpBits(NULL),
	iAlphaBits(NULL)
	{}

BitmapLoader::~BitmapLoader()
	{
	delete [] iBmpColors;
	delete [] iBmpBits;
	delete [] iAlphaBits;
	}

int BitmapLoader::LoadBitmap(char* aFileName,int aBpp,TBitmapColor aColor,SEpocBitmapHeader*& aPbm)
	{
	char sig[2];

#if defined(__MSVCDOTNET__) || defined(__LINUX__) || defined(__TOOLS2__)
	fstream file(aFileName, ios::in | ios::binary);
#else //!__MSVCDOTNET__
	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
#endif //__MSVCDOTNET__

	if (file.is_open()==0)
		return Files;
	file.read(sig,2);
	file.close();
	if (file.gcount()!=2)
		return SourceFile ;
	if (sig[0]!='B'||sig[1]!='M')
		return SourceFile;

	int ret = DoLoad(aFileName);
	if (!ret && aColor==EColorBitmapAlpha)
		{
		int fileNameLen = strlen(aFileName);
		char* alphaFileName = new char[fileNameLen + 7];// -alpha suffix is 6 chars, plus NUL termination
		if (alphaFileName == NULL)
			return NoMemory;
		int dotPos = -1;
		for (int i = 0; i < fileNameLen; ++i)
			if (aFileName[i]=='.')
				dotPos=i;
		int prefixLen = (dotPos>=0?dotPos:fileNameLen);
		memcpy(alphaFileName,aFileName,prefixLen);
		const char* suffix = "-alpha";
		memcpy(alphaFileName+prefixLen,suffix,6);
		if (dotPos>=0)
			memcpy(alphaFileName+prefixLen+6,aFileName+dotPos,fileNameLen-dotPos);
		*(alphaFileName + fileNameLen + 6) = '\0';
		ret = DoLoadAlpha(alphaFileName); // overlay alpha data from separate file
		delete [] alphaFileName;
		}
	if (!ret)
		ret = DoConvert(aBpp,aColor,aPbm);
	return ret;
	}

int BitmapLoader::DoLoad(char* aFileName)
	{
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
	fstream file(aFileName, ios::in | ios::binary);
#else //!__MSVCDOTNET__
	fstream file(aFileName, ios::in | ios::binary | ios::nocreate);
#endif //__MSVCDOTNET__
	if (file.is_open()==0)
		return Files;
	TBitmapFileHeader bmpfile;
	long size=sizeof(TBitmapFileHeader);
	file.read((char *)&bmpfile,size);
	if (file.gcount()!=size)
		return SourceFile;
	size=sizeof(TBitmapInfoHeader);
	file.read((char *)&iBmpHeader,size);
	if (file.gcount()!=size)
		return SourceFile;
	if (iBmpHeader.biCompression != 0)
		return UnknownCompression;
	size=bmpfile.bfSize-sizeof(TBitmapInfoHeader)-sizeof(TBitmapFileHeader);
	long bitcount=iBmpHeader.biBitCount;
	long colors=iBmpHeader.biClrUsed;
	if (colors==0)
		{
		if (bitcount==24)
			iNumBmpColors=0;
		else if (bitcount==32)
			iNumBmpColors=0;//See MSDN - BITMAPFILEHEADER and BITMAPINFOHEADER structures.
                            //If biCompression is 0 - we don't have TRgbQuad array! 
		else
			iNumBmpColors=1<<bitcount;
		}
	else
		iNumBmpColors=colors;
	if (iNumBmpColors > 256)
		return SourceFile;
	if (iNumBmpColors>0)
		{
		iBmpColors = new TRgbQuad[iNumBmpColors];
		if (iBmpColors == NULL)
			return NoMemory;
		memset(iBmpColors,0,iNumBmpColors*sizeof(TRgbQuad));
		}
	size-=iNumBmpColors*sizeof(TRgbQuad);
	iBmpBits = new char[size];
	if (iBmpBits == NULL)
		return NoMemory;
	memset(iBmpBits,0xff,size);
	// DEF102183: Graphics tools fail to run after building with MS VC8.
	if(iBmpColors != NULL)
	    {
		file.read((char *)iBmpColors,iNumBmpColors*sizeof(TRgbQuad));
		if (file.gcount()!=(int)(iNumBmpColors*sizeof(TRgbQuad)))
			return SourceFile;
	    }
	file.read(iBmpBits,size);
	file.close();
	if (file.gcount()!=size)
		return SourceFile;
	return NoError;
	}

int BitmapLoader::DoLoadAlpha(char* aAlphaFileName)
	{
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
	fstream file(aAlphaFileName, ios::in | ios::binary);
#else //!__MSVCDOTNET__
	fstream file(aAlphaFileName, ios::in | ios::binary | ios::nocreate);
#endif //__MSVCDOTNET__
	if (file.is_open()==0)
		return AlphaFiles;
	TBitmapFileHeader alphaBmpfile;
	long size=sizeof(TBitmapFileHeader);
	file.read((char *)&alphaBmpfile,size);
	if (file.gcount()!=size)
		return SourceFile;
	size=sizeof(TBitmapInfoHeader);
	TBitmapInfoHeader alphaBmpInfo;
	file.read((char *)&alphaBmpInfo,size);
	if (file.gcount()!=size)
		return SourceFile;
	if (alphaBmpInfo.biCompression != 0)
		return UnknownCompression;
	if (alphaBmpInfo.biWidth != iBmpHeader.biWidth || alphaBmpInfo.biHeight != iBmpHeader.biHeight)
		return AlphaDimensions;
	if (alphaBmpInfo.biBitCount != 8)
		return AlphaBpp;
	size=alphaBmpfile.bfSize-sizeof(TBitmapInfoHeader)-sizeof(TBitmapFileHeader);
	long numBmpColors=alphaBmpInfo.biClrUsed;
	if (numBmpColors == 0)
		numBmpColors = 256;
	if (numBmpColors != 256)
		return SourceFile;
	size-=numBmpColors*sizeof(TRgbQuad);
	iAlphaBits = new char[size];
	if (iAlphaBits == NULL)
		{
		return NoMemory;
		}
	memset(iAlphaBits,0xff,size);
	char* bmpColors = new char[numBmpColors*sizeof(TRgbQuad)];
	file.read((char *)bmpColors,numBmpColors*sizeof(TRgbQuad));
	delete [] bmpColors; // we aren't interested in the palette data for the 8bpp grayscale alpha bmp
	if (file.gcount()!=(int)(numBmpColors*sizeof(TRgbQuad)))
		return SourceFile;
	file.read(iAlphaBits,size);
	file.close();
	if (file.gcount()!=size)
		return SourceFile;
	return NoError;
	}

TRgb BitmapLoader::GetBmpPixel(long aXCoord,long aYCoord)
	{
	TRgb darkgray(128,128,128);
	TRgb darkgrayex(127,127,127);
	TRgb lightgray(192,192,192);
	TRgb lightgrayex(187,187,187);
	unsigned char col;
	TRgb color;

	switch(iBmpHeader.biBitCount)
		{
		case 1:
			col=iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*(((iBmpHeader.biWidth+31)>>5)<<2)+(aXCoord>>3)];
			col&=(0x80>>(aXCoord%8));
			if (iBmpColors)
				{
				TRgbQuad rgbq;
				if (col)
					rgbq = iBmpColors[1];
				else
					rgbq = iBmpColors[0];
				color = TRgb(rgbq.iRed,rgbq.iGreen,rgbq.iBlue);
				}
			else
				{
				if (col)
					color = TRgb(0x00ffffff);
				else
					color = TRgb(0);
				}
			break;
		case 4:
			col=iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*(((iBmpHeader.biWidth+7)>>3)<<2)+(aXCoord>>1)];
			if (aXCoord%2==0)
				col=(unsigned char)(col>>4);
			col&=0x0f;
			if (iBmpColors)
				{
				TRgbQuad rgbq = iBmpColors[col];
				color = TRgb(rgbq.iRed,rgbq.iGreen,rgbq.iBlue);
				}
			else
				{
				col *= 17;
				color = TRgb(col,col,col);
				}
			break;
		case 8:
			col=iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*((iBmpHeader.biWidth+3)&~3)+aXCoord];
			if (iBmpColors)
				{
				TRgbQuad rgbq = iBmpColors[col];
				color = TRgb(rgbq.iRed,rgbq.iGreen,rgbq.iBlue);
				}
			else
				color = TRgb(col,col,col);
			break;
		case 16:
			{
			unsigned short int* wordptr = (unsigned short int*)&iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*(((iBmpHeader.biWidth+1)&~1)<<1)+(aXCoord<<1)];
			color = TRgb((*wordptr&0x7c)>>10,(*wordptr&0x3e)>>5,(*wordptr&0x1f));
			}
			break;
		case 24:
			{
			TRgbTriple rgbcol = *((TRgbTriple *)&(iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*((3*iBmpHeader.biWidth+3)&~3)+aXCoord+(aXCoord<<1)]));
			color = TRgb(rgbcol.rgbtRed,rgbcol.rgbtGreen,rgbcol.rgbtBlue);
			}
			break;
		case 32:
			{
			unsigned long int* dwordptr = (unsigned long int*)&iBmpBits[(iBmpHeader.biHeight-aYCoord-1)*((iBmpHeader.biWidth)<<2)+(aXCoord<<2)];
			color = TRgb((*dwordptr&0xff0000)>>16,(*dwordptr&0xff00)>>8,*dwordptr&0xff);
			}
			break;
		default:
			break;
		}
	if (color == darkgray)
		color = darkgrayex;
	else if (color == lightgray)
		color = lightgrayex;
	return color;
	}

unsigned char BitmapLoader::GetAlphaPixel(long aXCoord,long aYCoord)
	{
	return iAlphaBits[(iBmpHeader.biHeight-aYCoord-1)*((iBmpHeader.biWidth+3)&~3)+aXCoord];
	}

int BitmapLoader::DoConvert(int aBpp,TBitmapColor aColor,SEpocBitmapHeader*& aPbm)
	{
	bool useAlpha = (aColor==EColorBitmapAlpha || aColor==EColorBitmapAlphaPM);
	long desttwipswidth = 0;
	long desttwipsheight = 0;

	long bytewidth = BitmapUtils::ByteWidth(iBmpHeader.biWidth,aBpp);
	long destlength = iBmpHeader.biHeight * bytewidth;

	if (iBmpHeader.biXPelsPerMeter>0)
		desttwipswidth = iBmpHeader.biWidth*1440000/254/iBmpHeader.biXPelsPerMeter;
	if (iBmpHeader.biYPelsPerMeter>0)
		desttwipsheight = iBmpHeader.biHeight*1440000/254/iBmpHeader.biYPelsPerMeter;

	aPbm = (SEpocBitmapHeader*)new char[sizeof(SEpocBitmapHeader) + destlength];
	if (aPbm == NULL)
		return NoMemory;
	memset(aPbm,0,sizeof(SEpocBitmapHeader));

	// aBitmap->iByteWidth = bytewidth;
	// aBitmap->iDataOffset = sizeof(Bitmap);

	aPbm->iBitmapSize = sizeof(SEpocBitmapHeader) + destlength;
	aPbm->iStructSize = sizeof(SEpocBitmapHeader);
	aPbm->iWidthInPixels = iBmpHeader.biWidth;
	aPbm->iHeightInPixels = iBmpHeader.biHeight;
	aPbm->iWidthInTwips = desttwipswidth;
	aPbm->iHeightInTwips = desttwipsheight;
	aPbm->iBitsPerPixel = aBpp;
	aPbm->iColor = aColor;
	aPbm->iPaletteEntries = 0;
	aPbm->iCompression = ENoBitmapCompression;

	char* pbmBits = ((char*)aPbm) + sizeof(SEpocBitmapHeader);
	memset(pbmBits,0xff,destlength);

	long col = 0;
	char* pixadd = 0;

	switch(aBpp)
		{
	case 1:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				col=color.Gray2();
				pixadd=&(pbmBits[ycrd*bytewidth+(xcrd>>3)]);
				(*pixadd)&=~(1<<((xcrd&7)));
				(*pixadd)|=(unsigned char)(col<<(xcrd&7));
				}
		}
		break;
	case 2:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				col=color.Gray4();
				pixadd=&(pbmBits[ycrd*bytewidth+(xcrd>>2)]);
				(*pixadd)&=~(0x3<<(2*(xcrd%4)));
				(*pixadd)|=(unsigned char)(col<<(2*(xcrd%4)));
				}
		}
		break;
	case 4:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				if (aColor == EMonochromeBitmap)
					col = color.Gray16();
				else
					col = color.Color16();
				pixadd=&(pbmBits[ycrd*bytewidth+(xcrd>>1)]);
				if (xcrd%2!=0)
					*pixadd=(unsigned char)((unsigned char)((col<<4)|(*pixadd&0x0f)));
				else
					*pixadd=(unsigned char)((unsigned char)(col|(*pixadd&0xf0)));
				}
		}
		break;
	case 8:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				if (aColor == EMonochromeBitmap)
					col = color.Gray256();
				else
					col = color.Color256();
				pixadd=&(pbmBits[ycrd*((iBmpHeader.biWidth+3)&~3)+xcrd]);
				*pixadd=(unsigned char)col;
				}
		}
		break;
	case 12:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				col=color.Color4K();
				pixadd=&(pbmBits[ycrd*bytewidth+(xcrd<<1)]);
				unsigned short* wordadd=(unsigned short*)pixadd;
				*wordadd=(unsigned short)col;
				}
		}
		break;
	case 16:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb color=GetBmpPixel(xcrd,ycrd);
				col=color.Color64K();
				pixadd=&(pbmBits[ycrd*bytewidth+(xcrd<<1)]);
				unsigned short* wordadd=(unsigned short*)pixadd;
				*wordadd=(unsigned short)col;
				}
		}
		break;
	case 24:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			{
			unsigned char* bytePtr = (unsigned char*)&pbmBits[ycrd*bytewidth];
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb col = GetBmpPixel(xcrd,ycrd);
				*bytePtr++ = (unsigned char) col.iBlue;
				*bytePtr++ = (unsigned char) col.iGreen;
				*bytePtr++ = (unsigned char) col.iRed;
				}
			}
		}
		break;
	case 32:
		{
		for(long ycrd=0;ycrd<iBmpHeader.biHeight;ycrd++)
			{
			unsigned char* bytePtr = (unsigned char*)&pbmBits[ycrd*bytewidth];
			for(long xcrd=0;xcrd<iBmpHeader.biWidth;xcrd++)
				{
				TRgb col = GetBmpPixel(xcrd,ycrd);
				unsigned char alpha = useAlpha?GetAlphaPixel(xcrd,ycrd):(unsigned char)0;
				*bytePtr++ = (unsigned char) col.iBlue;
				*bytePtr++ = (unsigned char) col.iGreen;
				*bytePtr++ = (unsigned char) col.iRed;
				*bytePtr++ = alpha;	
				}
			}
		}
		break;
		};

	return NoError;
	}