예제 #1
0
bool CxImageIG::decodeSubLayer (CxFile& file, IGLibrary::IGLayer *pSubLayerOwner, IGSECTIONHEADER_LAYER *pLayerSection)
{
	CxImage cxSubLayer;
	if (!file.Seek (pLayerSection->commonHeader.nFirstByteOffset, SEEK_SET))
		throw IGEXCEPTION (CxImageIGException, "decodeSubLayer", "file.Seek failed");
	// read sub-layer pixels
	BYTE *pBufImg = new BYTE [pLayerSection->commonHeader.nSizeBuf];
	file.Read (pBufImg, pLayerSection->commonHeader.nSizeBuf, 1);
	if (!cxSubLayer.Decode (pBufImg, pLayerSection->commonHeader.nSizeBuf, CXIMAGEIG_LAYERFORMAT))
		throw IGEXCEPTION (CxImageIGException, "decodeSubLayer", "cxSubLayer.Decode failed");
	delete [] pBufImg;
	// read sub-layer alpha
	cxSubLayer.AlphaCreate (255);
	file.Read (cxSubLayer.pAlpha, cxSubLayer.GetWidth() * cxSubLayer.GetHeight(), 1);
	// decode sub-layer into layer
	BYTE *pLayerBits = NULL;
	BYTE *pSubLayerBits = NULL;
	for (int i = 0; i < pLayerSection->ptSize.y; i++)
	{
		pSubLayerBits = cxSubLayer.GetBits (i);
		pLayerBits = pSubLayerOwner->GetBits (pLayerSection->ptOffset.y + i) + 3 * pLayerSection->ptOffset.x;
		::memcpy (pLayerBits, pSubLayerBits, (pLayerSection->ptSize.x) * 3);			
	}
	BYTE *pLayerAlpha = NULL;
	BYTE *pSubLayerAlpha = NULL;
	for (int i = 0; i < (pLayerSection->ptSize.y); i++)
	{
		pLayerAlpha = pSubLayerOwner->AlphaGetPointer (pLayerSection->ptOffset.x, pLayerSection->ptOffset.y + i);
		pSubLayerAlpha = cxSubLayer.AlphaGetPointer (0, i);	
		::memcpy (pLayerAlpha, pSubLayerAlpha, (pLayerSection->ptSize.x));
	}
	return true;
}
예제 #2
0
void ModelOpened::ExportPNG(wxString val, wxString suffix)
{
	if (val == wxEmptyString)
		return;
	wxFileName fn = fixMPQPath(val);
	if (fn.GetExt().Lower() != wxT("blp"))
		return;
	TextureID temptex = texturemanager.add(val);
	Texture &tex = *((Texture*)texturemanager.items[temptex]);
	if (tex.w == 0 || tex.h == 0)
		return;

	wxString temp;

	unsigned char *tempbuf = (unsigned char*)malloc(tex.w*tex.h*4);
	tex.getPixels(tempbuf, GL_BGRA_EXT);

	CxImage *newImage = new CxImage(0);
	newImage->AlphaCreate();	// Create the alpha layer
	newImage->IncreaseBpp(32);	// set image to 32bit 
	newImage->CreateFromArray(tempbuf, tex.w, tex.h, 32, (tex.w*4), true);
	if (bPathPreserved) {
		wxFileName::Mkdir(wxGetCwd()+SLASH+wxT("Export")+SLASH+fn.GetPath(), 0755, wxPATH_MKDIR_FULL);
		temp = wxGetCwd()+SLASH+wxT("Export")+SLASH+fn.GetPath()+SLASH+fn.GetName()+wxT(".")+suffix;
	} else {
		temp = wxGetCwd()+SLASH+wxT("Export")+SLASH+fn.GetName()+wxT(".")+suffix;
	}
	//wxLogMessage(wxT("Info: Exporting texture to %s..."), temp.c_str());
	if (suffix == wxT("tga"))
#ifndef _MINGW
		newImage->Save(temp.mb_str(), CXIMAGE_FORMAT_TGA);
#else
		newImage->Save(temp.wc_str(), CXIMAGE_FORMAT_TGA);
#endif
	else
예제 #3
0
bool IGFrameManager::Cut(LPCWSTR pcwGuid)
{
	IGSmartPtr <IGFrame> spFrame;
	if (!GetFrame(pcwGuid, spFrame))
		return false;
	CxImage *pCxLayer = spFrame->GetWorkingLayer();
	if (!pCxLayer)
		return false;
	RECT rcSel;
	if (pCxLayer->SelectionIsValid())
		pCxLayer->SelectionGetBox (rcSel);
	else{
		rcSel.bottom = 0;
		rcSel.left = 0;
		rcSel.top = pCxLayer->GetHeight();
		rcSel.right = pCxLayer->GetWidth();
	}
	m_spClipboardLayer = new IGLayer(NULL);
	m_spClipboardLayer->Create (rcSel.right - rcSel.left, rcSel.top - rcSel.bottom, 24);
	m_spClipboardLayer->AlphaCreate();
	pCxLayer->AlphaCreate();
	RGBQUAD qGray; qGray.rgbBlue = CXIMAGE_GRAY; qGray.rgbGreen = CXIMAGE_GRAY; qGray.rgbRed = CXIMAGE_GRAY;
	for(long y=rcSel.bottom; y<rcSel.top; y++){
		for(long x=rcSel.left; x<rcSel.right; x++){
			if (pCxLayer->BlindSelectionIsInside(x,y)){
				m_spClipboardLayer->BlindSetPixelColor(x - rcSel.left, y - rcSel.bottom, pCxLayer->BlindGetPixelColor(x,y));
				pCxLayer->BlindSetPixelColor(x, y, qGray);
				pCxLayer->AlphaSet(x, y, 0);
			}
			else
				m_spClipboardLayer->AlphaSet (x - rcSel.left, y - rcSel.bottom, 0);
		}
	}
	return true;
}
예제 #4
0
bool CxImageIG::DecodeLayer (CxFile &file, int nLayerIdx, int nLayerPos, RECT *p_rcSubLayer, bool bUndo, int nSubLayerId)
{	
	// read current header
	IGHEADER igHeader;
	if (!decodeHeader (&file, &igHeader))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "decodeHeader failed");
	if (nLayerIdx < 0)
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "nLayerIdx failed");
	if ((nLayerPos < 0) || (nLayerPos >= info.nNumLayers))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "nLayerPos failed");

	IGSECTIONHEADER_LAYER *pLayerSections = new IGSECTIONHEADER_LAYER [CXIMAGEIG_MAX_NBLAYERS];
	IGSECTIONHEADER_SELECTION *pSelectionSections  = new IGSECTIONHEADER_SELECTION [CXIMAGEIG_MAX_NBSELECTIONS];
	if (!decodeSections (&file, &igHeader, &pLayerSections[0], &pSelectionSections[0]))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "decodeSections failed");

	IGLibrary::IGLayer *pLayer = GetLayer (nLayerPos);
	if (!pLayer)
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "GetLayer failed");
	CxImage cxSubLayer;
	CxImage *pDecodingLayer = p_rcSubLayer ? &cxSubLayer : pLayer;
	bool bIsSubLayerOwner = bUndo && p_rcSubLayer; // no need to find sub-layer owner in do mode
	int nLayerSectionIndex = findLayerSectionIndex (&igHeader, pLayerSections, nLayerIdx, bIsSubLayerOwner);
	if ((nLayerSectionIndex < 0) || (nLayerSectionIndex >= igHeader.nNbLayers))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "findLayerSectionIndex failed");

	// in undo mode, if a sub-layer owner is found, decode it
	if (bUndo){
		if (bIsSubLayerOwner)
		{
			// decode sub-layer owner
			if (!DecodeLayer (file, pLayerSections [nLayerSectionIndex].commonHeader.nId, nLayerPos))
				throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "DecodeLayer failed");
			// decode sub-layers
			int nSubLayerSectionIndex = findLayerSectionIndex (&igHeader, pLayerSections, nLayerIdx, bIsSubLayerOwner);
			if ((nSubLayerSectionIndex < 0) || (nSubLayerSectionIndex >= igHeader.nNbLayers))
				throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "findLayerSectionIndex failed");
			RECT rcSubLayer;
			rcSubLayer.left = pLayerSections[nSubLayerSectionIndex].ptOffset.x;
			rcSubLayer.right = pLayerSections[nSubLayerSectionIndex].ptOffset.x + pLayerSections[nSubLayerSectionIndex].ptSize.x - 1;
			rcSubLayer.top = pLayerSections[nSubLayerSectionIndex].ptOffset.y;
			rcSubLayer.bottom = pLayerSections[nSubLayerSectionIndex].ptOffset.y + pLayerSections[nSubLayerSectionIndex].ptSize.y - 1;
			return DecodeLayer (file, pLayerSections [nLayerSectionIndex].commonHeader.nId, nLayerPos, &rcSubLayer, true, nLayerIdx);
		}
	}

	if (!file.Seek (pLayerSections [nLayerSectionIndex].commonHeader.nFirstByteOffset, SEEK_SET))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "file.Seek failed");
	// read layer pixels
	BYTE *pBufImg = new BYTE [pLayerSections [nLayerSectionIndex].commonHeader.nSizeBuf];
	file.Read (pBufImg, pLayerSections [nLayerSectionIndex].commonHeader.nSizeBuf, 1);
	if (!pDecodingLayer->Decode (pBufImg, pLayerSections [nLayerSectionIndex].commonHeader.nSizeBuf, CXIMAGEIG_LAYERFORMAT))
		throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "pDecodingLayer->Decode failed");
	delete [] pBufImg;

	// read layer alpha
	pDecodingLayer->AlphaCreate (255);
	file.Read (pDecodingLayer->pAlpha, pDecodingLayer->GetWidth() * pDecodingLayer->GetHeight(), 1);
	
	int nSubLayerWidth = 0;
	int nSubLayerHeight = 0;
	if (p_rcSubLayer)
	{
		// decode sub-layer
		nSubLayerWidth = p_rcSubLayer->right - p_rcSubLayer->left + 1;
		nSubLayerHeight = p_rcSubLayer->bottom - p_rcSubLayer->top + 1;
		BYTE *pLayerBits = NULL;
		BYTE *pSubLayerBits = NULL;
		for (int i = 0; i < nSubLayerHeight; i++)
		{
			// if undo, then sub-layer == original layer
			pSubLayerBits = bUndo ? pDecodingLayer->GetBits (p_rcSubLayer->top + i) + 3 * p_rcSubLayer->left : pDecodingLayer->GetBits (i);
			pLayerBits = pLayer->GetBits (p_rcSubLayer->top + i) + 3 * p_rcSubLayer->left;
			::memcpy (pLayerBits, pSubLayerBits, nSubLayerWidth * 3);			
		}
		BYTE *pLayerAlpha = NULL;
		BYTE *pSubLayerAlpha = NULL;
		for (int i = 0; i < nSubLayerHeight; i++)
		{
			pLayerAlpha = pLayer->AlphaGetPointer (p_rcSubLayer->left, p_rcSubLayer->top + i);
			pSubLayerAlpha = bUndo ? pDecodingLayer->AlphaGetPointer (p_rcSubLayer->left, p_rcSubLayer->top + i) : pDecodingLayer->AlphaGetPointer (0, i);
			::memcpy (pLayerAlpha, pSubLayerAlpha, nSubLayerWidth);
		}
		if (bUndo)
		{
			// original layer is now decoded. decode sub-layers
			bIsSubLayerOwner = false;
			int nMaxSubLayerSectionIndex = findLayerSectionIndex (&igHeader, pLayerSections, nSubLayerId, bIsSubLayerOwner); // we always have bIsSubLayerOwner = false, its used for the reference only
			if (nMaxSubLayerSectionIndex < 0)
				throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "findLayerSectionIndex failed");
			if (nMaxSubLayerSectionIndex <= igHeader.nNbLayers)
			{
				for (int i = 0; i < pLayerSections [nLayerSectionIndex].nSubLayers; i++)
				{
					if (pLayerSections [nLayerSectionIndex].pnSubLayers [i] <= nMaxSubLayerSectionIndex)
					{
						if (!decodeSubLayer (file, pLayer, &pLayerSections [pLayerSections [nLayerSectionIndex].pnSubLayers [i]]))
							throw IGEXCEPTION (CxImageIGException, "DecodeLayer", "decodeSubLayer failed");
					}
				}
			}
		}
	}
	else
	{
		pLayer->info.xOffset = pLayerSections [nLayerSectionIndex].ptOffset.x;
		pLayer->info.yOffset = pLayerSections [nLayerSectionIndex].ptOffset.y;
	}
	pLayer->SetId (nLayerIdx);
	pLayer->UpdateImageParameters();
	delete [] pLayerSections;
	delete [] pSelectionSections;
	return true;
}
예제 #5
0
bool CxImageIG::EncodeLayer (const wchar_t *pcwFilePath, int nLayerIdx, int nLayerPos, RECT *p_rcSubLayer, int nSubLayerOwnerId)
{
	CxIOFile file;
	if (!file.Open (pcwFilePath, L"r+b"))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "file.Open failed");
	// read current header
	IGHEADER igHeader;	
	if (!decodeHeader (&file, &igHeader))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "decodeHeader failed");

	IGSECTIONHEADER_LAYER *pLayerSections = new IGSECTIONHEADER_LAYER[CXIMAGEIG_MAX_NBLAYERS];
	IGSECTIONHEADER_SELECTION *pSelectionSections = new IGSECTIONHEADER_SELECTION[CXIMAGEIG_MAX_NBSELECTIONS];
	if (!decodeSections (&file, &igHeader, &pLayerSections[0], &pSelectionSections[0]))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "decodeSections failed");

	IGLibrary::IGLayer *pLayer = GetLayer (nLayerPos);
	if (!pLayer)
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "GetLayer failed");
	_ASSERTE ((int)pLayer->GetId() == nLayerIdx && "CxImageIG::EncodeLayer FAILED");
	bool bIsSubLayerOwner = false;
	int nLayerSectionIndex = findLayerSectionIndex (&igHeader, pLayerSections, nLayerIdx, bIsSubLayerOwner);
	if (nLayerSectionIndex < 0)
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "findLayerSectionIndex failed");
	if ((nLayerSectionIndex > igHeader.nNbLayers) || (nLayerSectionIndex >= CXIMAGEIG_MAX_NBLAYERS))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "findLayerSectionIndex failed");
	CxImage cxSubLayer;
	CxImage *pEncodingLayer = pLayer;
	int nSubLayerWidth = 0;
	int nSubLayerHeight = 0;
	if (p_rcSubLayer)
	{
		// Encode sub-layer
		nSubLayerWidth = p_rcSubLayer->right - p_rcSubLayer->left + 1;
		nSubLayerHeight = p_rcSubLayer->bottom - p_rcSubLayer->top + 1;
		cxSubLayer.Create (nSubLayerWidth, nSubLayerHeight, 24);
		cxSubLayer.AlphaCreate (255);
		BYTE *pLayerBits = NULL;
		BYTE *pSubLayerBits = NULL;
		for (int i = 0; i < nSubLayerHeight; i++)
		{
			pSubLayerBits = cxSubLayer.GetBits (i);
			pLayerBits = pLayer->GetBits (p_rcSubLayer->top + i) + 3 * p_rcSubLayer->left;
			::memcpy (pSubLayerBits, pLayerBits, nSubLayerWidth * 3);
		}
		BYTE *pLayerAlpha = NULL;
		BYTE *pSubLayerAlpha = NULL;
		for (int i = 0; i < nSubLayerHeight; i++)
		{
			pLayerAlpha = pLayer->AlphaGetPointer (p_rcSubLayer->left, p_rcSubLayer->top + i);
			pSubLayerAlpha = cxSubLayer.AlphaGetPointer (0, i);		
			::memcpy (pSubLayerAlpha, pLayerAlpha, nSubLayerWidth);
		}
		pEncodingLayer = &cxSubLayer;
		int nSubLayerSectionIndex = findLayerSectionIndex (&igHeader, pLayerSections, nSubLayerOwnerId, bIsSubLayerOwner);
		if (nSubLayerSectionIndex < 0)
			throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "findLayerSectionIndex failed");
		pLayerSections [nSubLayerSectionIndex].pnSubLayers [pLayerSections [nSubLayerSectionIndex].nSubLayers++] = nLayerSectionIndex;
	}
	ProgressSetRange (pLayer->GetHeight(), 0);
	ProgressSetMessage (L"Encoding layer...");	
	// fill layer offset and size
	pLayerSections [nLayerSectionIndex].nSubLayers = 0;
	pLayerSections [nLayerSectionIndex].ptOffset.x = p_rcSubLayer ? p_rcSubLayer->left : pLayer->info.xOffset;
	pLayerSections [nLayerSectionIndex].ptOffset.y = p_rcSubLayer ? p_rcSubLayer->top : pLayer->info.yOffset;
	pLayerSections [nLayerSectionIndex].ptSize.x = p_rcSubLayer ? p_rcSubLayer->right - p_rcSubLayer->left + 1 : pLayer->GetWidth();
	pLayerSections [nLayerSectionIndex].ptSize.y = p_rcSubLayer ? p_rcSubLayer->bottom - p_rcSubLayer->top + 1 : pLayer->GetHeight();
	if (nLayerSectionIndex == igHeader.nNbLayers)
		pLayerSections [nLayerSectionIndex].commonHeader.nSectionId = (BYTE)igHeader.nNbSections;
	pLayerSections [nLayerSectionIndex].commonHeader.nId = nLayerIdx;
	pLayerSections [nLayerSectionIndex].commonHeader.eSectionType = IGSECTION_LAYER;
	// set byte offset
	if (igHeader.nNbSections == 0)
		pLayerSections [nLayerSectionIndex].commonHeader.nFirstByteOffset = sizeof (IGHEADER) + sizeof (IGSECTIONHEADER_LAYER) * CXIMAGEIG_MAX_NBLAYERS + sizeof (IGSECTIONHEADER_SELECTION) * CXIMAGEIG_MAX_NBSELECTIONS;
	else
		pLayerSections [nLayerSectionIndex].commonHeader.nFirstByteOffset = findSectionFirstByteOffset (&igHeader, pLayerSections, pSelectionSections, pLayerSections [nLayerSectionIndex].commonHeader.nSectionId);

	igHeader.nNbLayers = nLayerSectionIndex + 1;
	if (igHeader.nNbSelections == 0)
	{
		igHeader.nNbSections = pLayerSections [nLayerSectionIndex].commonHeader.nSectionId + 1;
		igHeader.nNbSelections = igHeader.nNbSections - igHeader.nNbLayers;
	}
	else
	{
		if (pSelectionSections [igHeader.nNbSelections - 1].commonHeader.nSectionId == pLayerSections [nLayerSectionIndex].commonHeader.nSectionId + 1)
			igHeader.nNbSections = igHeader.nNbSelections + igHeader.nNbLayers;
		else
		{
			igHeader.nNbSections = pLayerSections [nLayerSectionIndex].commonHeader.nSectionId + 1;
			igHeader.nNbSelections = igHeader.nNbSections - igHeader.nNbLayers;
		}
	}

	// write layer pixels
	if (!file.Seek (pLayerSections [nLayerSectionIndex].commonHeader.nFirstByteOffset, SEEK_SET))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "file.Seek failed");

	// set max JPEG quality
	float fCurQuality = pEncodingLayer->GetJpegQualityF();
	pEncodingLayer->SetJpegQualityF (100.0f);
	// JPEG encoding
	BYTE *pBuf = new BYTE [CXIMAGEIG_INIT_LAYERSIZE];
	CxMemFile memFile (pBuf, CXIMAGEIG_INIT_LAYERSIZE);
	if (!pEncodingLayer->Encode (&memFile, CXIMAGEIG_LAYERFORMAT))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "pEncodingLayer->Encode failed");
	BYTE *pBufImg = memFile.GetBuffer();
	long nSizeBufImg = memFile.Tell();
	// reset JPEG quality
	pEncodingLayer->SetJpegQualityF (fCurQuality);
	file.Write (pBufImg, nSizeBufImg, 1);
	delete [] pBufImg;
	pLayerSections [nLayerSectionIndex].commonHeader.nSizeBuf = nSizeBufImg;
	// write layer alpha
	if (!pEncodingLayer->pAlpha)
		pEncodingLayer->AlphaCreate(255);
	int nNbPixels = pEncodingLayer->GetWidth() * pEncodingLayer->GetHeight();
	file.Write (pEncodingLayer->pAlpha, nNbPixels, 1);
	pLayerSections [nLayerSectionIndex].commonHeader.nEndByteOffset = pLayerSections [nLayerSectionIndex].commonHeader.nFirstByteOffset + nSizeBufImg + nNbPixels;

	// write new headers
	if (!encodeHeader (&file, &igHeader))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "encodeHeader failed");
	if (!encodeSections (&file, &igHeader, pLayerSections, pSelectionSections))
		throw IGEXCEPTION (CxImageIGException, "EncodeLayer", "encodeSections failed");
	delete [] pLayerSections;
	delete [] pSelectionSections;
	return true;
}
예제 #6
0
BOOL CSonicImage::Rotate(int nAngle, POINT * pScout /* = NULL */)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}
	nAngle = abs(nAngle) % 360;
	int nBitX = nAngle <= 180 ? 1 : 0;
	int nBitY = nAngle > 90 && nAngle <= 270 ? 1 : 0;
	int nSrcW = m_nWidth;
	int nSrcH = m_nHeight;
	const int nBytePixel = 4;
	BYTE * pSrc = m_Dib.GetBits();
	int nNewX = (nSrcW - nBitX) >> 1;
	int nNewY = (nSrcH - nBitY) >> 1;

	double m1 = -nSrcW / 2.0f;
	double m2 = nSrcW / 2.0f;
	double n1 = nSrcH / 2.0f;
	double n2 = -nSrcH / 2.0f;

	POINT pt1 = {(int)(m1 * COS(nAngle) + n1 * SIN(nAngle)) >> 10, (int)(-m1 * SIN(nAngle) + n1 * COS(nAngle)) >> 10};
	POINT pt2 = {(int)(m2 * COS(nAngle) + n1 * SIN(nAngle)) >> 10, (int)(-m2 * SIN(nAngle) + n1 * COS(nAngle)) >> 10};
	POINT pt3 = {(int)(m2 * COS(nAngle) + n2 * SIN(nAngle)) >> 10, (int)(-m2 * SIN(nAngle) + n2 * COS(nAngle)) >> 10};
	POINT pt4 = {(int)(m1 * COS(nAngle) + n2 * SIN(nAngle)) >> 10, (int)(-m1 * SIN(nAngle) + n2 * COS(nAngle)) >> 10};

	int i, j, x1, y1, x11, y11;
	i = abs(pt3.x - pt1.x);
	j = abs(pt4.x - pt2.x);
	int nDestW = max(i, j);
	i = abs(pt3.y - pt1.y);
	j = abs(pt4.y - pt2.y);
	int nDestH = max(i, j);

	m_nWidth = nDestW;
	m_nHeight = nDestH;
	HBITMAP hBmp = NULL;
	m_Dib.Resize(m_nWidth, m_nHeight, &hBmp);
	BYTE * pDest = m_Dib.GetBits();
	
	int temp;
	int nOriginX = nDestW >> 1;
	int nOriginY = nDestH >> 1;

	for(i = 0; i < nDestH; i++)
	{
		for(j = 0; j < nDestW; j++)
		{
			x1 = j - nOriginX;
			y1 = nOriginY - i;

			temp = (x1 * COS(nAngle) + y1 * SIN(nAngle)) >> 10;
			x11 = temp + nNewX;
			temp = (-x1 * SIN(nAngle) + y1 * COS(nAngle)) >> 10;
			y11 = nNewY - temp;
			if(x11 >= 0 && x11 < nSrcW && y11 >= 0 && y11 < nSrcH)
			{
				COLORREF color = *(DWORD *)(pSrc + (nSrcW * nBytePixel * y11) + x11 * nBytePixel);
				*(DWORD *)(pDest + i * nBytePixel * nDestW + j * nBytePixel) = color;
			}
		}
	}
	if(hBmp)
	{
		DeleteObject(hBmp);
	}
	if(pScout)
	{
		x1 = pScout->x - nNewX;
		y1 = nNewY - pScout->y;
        nAngle = 360 - nAngle;
		x11 = (x1 * COS(nAngle) + y1 * SIN(nAngle)) >> 10;
		x11 = x11 + nOriginX;
		y11 = (-x1 * SIN(nAngle) + y1 * COS(nAngle)) >> 10;
		y11 = nOriginY - y11;
		pScout->x = x11;
		pScout->y = y11;
	}
	EnableAlphaChannel(FALSE);
	return TRUE;
}

BOOL CSonicImage::SaveAsFile(LPCTSTR lpszFileName, enImageType imgType, int nQuality /* = 0 */)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}
	CxImage img;

	if(img.CreateFromHBITMAP(m_Dib.GetHBitmap()) == FALSE)
	{
		return FALSE;
	}
	if(IsAlphaChannelValid()
		&& (imgType == IMAGE_TYPE_BMP
		|| imgType == IMAGE_TYPE_PNG
		|| imgType == IMAGE_TYPE_TGA
		|| imgType == IMAGE_TYPE_ICO))
	{
		img.AlphaCreate();
		for(int i = 0; i < m_nHeight; i++)
		{
			for(int j = 0; j < m_nWidth; j++)
			{
				BYTE bAlpha = *(m_Dib.GetBits() + i * m_nWidth * 4 + j * 4 + 3);
				img.AlphaSet(j, i, bAlpha);
			}
		}
	}
	DWORD dwType = 0;
	switch (imgType)
	{
	case IMAGE_TYPE_BMP:
		dwType = CXIMAGE_FORMAT_BMP;
		break;
	case IMAGE_TYPE_JPEG:
		dwType = CXIMAGE_FORMAT_JPG;
		nQuality = nQuality ? nQuality : DEFAULT_JPEG_QULITY;
		img.SetJpegQuality(nQuality);
		break;
	case IMAGE_TYPE_TGA:
		dwType = CXIMAGE_FORMAT_TGA;
		break;
	case IMAGE_TYPE_PNG:
		dwType = CXIMAGE_FORMAT_PNG;
		break;
	case IMAGE_TYPE_ICO:
		dwType = CXIMAGE_FORMAT_ICO;
		break;
	}
	CString strPath = lpszFileName;
	int nFind1 = strPath.ReverseFind(_T('\\'));
	int nFind2 = strPath.ReverseFind(_T('/'));
	int nFind = max(nFind1, nFind2);
	if(nFind != -1)
	{
		strPath = strPath.Left(nFind);
		if(PathFileExists(strPath) == FALSE)
		{
			SHCreateDirectoryEx(NULL, strPath, NULL);
		}
	}
#ifdef _UNICODE
    USES_CONVERSION;	
	if(img.Save(W2A(lpszFileName), dwType) == FALSE)
	{
		return FALSE;
	}
#else
	if(img.Save(lpszFileName, dwType) == FALSE)
	{
		return FALSE;
	}
#endif	
	img.Clear();
	return TRUE;
}

BOOL CSonicImage::Gray()
{
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}
	int nSrcSize = m_nWidth * m_nHeight * 4;
	CSSE::DoGray(m_Dib.GetBits(), nSrcSize);
	return TRUE;
}

HRGN CSonicImage::CreateRgn(DWORD dwColorKey /* = DEFAULT_COLOR_KEY */, int x /* = 0 */, int y /* = 0 */, RECT * pRtSrc /* = NULL */, BOOL bReverse /* = FALSE */)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}

	int nBytePixel = 4;
	BYTE * pSrc = m_Dib.GetBits();

	CRect rtSrc(0, 0, m_nWidth, m_nHeight);
	if(pRtSrc)
	{
		rtSrc = *pRtSrc;
	}

	int nLeftx = -1;
	HRGN hAll = CreateRectRgn(x, y, x + rtSrc.Width(), y + rtSrc.Height());

	for(int i = rtSrc.top; i < rtSrc.bottom; i++)
	{
		for(int j = rtSrc.left; j < rtSrc.right; j++)
		{
			DWORD dwColor = *(DWORD *)(pSrc + (i * m_nWidth * nBytePixel) + j * nBytePixel);
			if(!bReverse)
			{
				if(EQUAL_24COLOR(dwColor, dwColorKey) && nLeftx < 0)
				{
					nLeftx = j;
				}
				if(nLeftx >= 0 && (!EQUAL_24COLOR(dwColor, dwColorKey) || j + 1 == rtSrc.right))
				{
					if(EQUAL_24COLOR(dwColor, dwColorKey) && j + 1 == rtSrc.right)j++;
					HRGN hTemp = CreateRectRgn(x + nLeftx - rtSrc.left, y + i - rtSrc.top, x + j - rtSrc.left, y + i + 1 - rtSrc.top);
					CombineRgn(hAll, hAll, hTemp, RGN_XOR);
					DeleteObject(hTemp);
					nLeftx = -1;
				}
			}
			else
			{
				if(!EQUAL_24COLOR(dwColor, dwColorKey) && nLeftx < 0)
				{
					nLeftx = j;
				}
				if(nLeftx >= 0 && (EQUAL_24COLOR(dwColor, dwColorKey) || j + 1 == rtSrc.right))
				{
					if(!EQUAL_24COLOR(dwColor, dwColorKey) && j + 1 == rtSrc.right)j++;
					HRGN hTemp = CreateRectRgn(x + nLeftx - rtSrc.left, y + i - rtSrc.top, x + j - rtSrc.left, y + i + 1 - rtSrc.top);
					CombineRgn(hAll, hAll, hTemp, RGN_XOR);
					DeleteObject(hTemp);
					nLeftx = -1;
				}
			}
		}
	}
	return hAll;
}

BOOL CSonicImage::IsAlphaChannelValid()
{
	return m_bAlphaChannel;
}

BOOL CSonicImage::EnableAlphaChannel(BOOL bModifyRgb /* = TRUE */)
{
	if(m_bAlphaChannel)
	{
		return FALSE;
	}
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}
	m_bAlphaChannel = TRUE;
	if(bModifyRgb)
	{
		int nSrc = m_nWidth * m_nHeight;
		DWORD * pSrc = (DWORD *)m_Dib.GetBits();
		for(int i = 0; i < nSrc; i++)
		{
			CSSE::AdjustAlpha(*pSrc);
			pSrc++;
		}
	}
	return TRUE;
}

DWORD CSonicImage::GetPixel(int x, int y)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return 0;
	}
	if(y < 0 || y >= m_nHeight)
	{
		return 0;
	}
	if(x < 0 || x >= m_nWidth)
	{
		return 0;
	}
	return *(DWORD *)(m_Dib.GetBits() + (m_nHeight - y - 1) * m_nWidth * 4 + x * 4);
}

BOOL CSonicImage::SetPixel(int x, int y, DWORD dwColor)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return 0;
	}
	if(IsAlphaChannelValid())
	{
		CSSE::AdjustAlpha(dwColor);
	}
	else
	{
		dwColor |= 0xff000000;
	}
	if(y < 0 || y >= m_nHeight)
	{
		return 0;
	}
	if(x < 0 || x >= m_nWidth)
	{
		return 0;
	}
	*(DWORD *)(m_Dib.GetBits() + (m_nHeight - y - 1) * m_nWidth * 4 + x * 4) = dwColor;
	return TRUE;
}

BYTE * CSonicImage::GetBits()
{
	return m_Dib.GetBits();
}

BOOL CSonicImage::Init()
{
	double radiant;
	for(int i = 0; i < 361; i++)
	{
		radiant = (i * PAI) / 180;
		double temp = sin(radiant) * 1024;
		Trigonometry[i][0] = ROUND(temp);
		temp = cos(radiant) * 1024;
		Trigonometry[i][1] = ROUND(temp);
	}
	return TRUE;
}

BOOL CSonicImage::SetBitsToDevice(HDC hdc, int x /* = 0 */, int y /* = 0 */)
{
	return SetDIBitsToDevice(hdc, x, y, m_nWidth, m_nHeight, 0, 0, 0, m_nHeight, m_Dib.GetBits(), m_Dib.GetBitmapInfo(), DIB_RGB_COLORS) != 0;
}

RECT CSonicImage::CalculateRectByDrawParam(int x, int y, const DRAW_PARAM * pDp, RECT * pSrc /* = NULL */)
{
	CRect rtSrc, rtDest;
	int cx = m_nWidth;
	int cy = m_nHeight;

	if(pDp && (pDp->dwMask & DP_SRC_CLIP))
	{
		rtSrc = pDp->rtSrc;
	}
	else
	{
		rtSrc.SetRect(0, 0, m_nWidth, m_nHeight);
	}
	cx = rtSrc.Width();
	cy = rtSrc.Height();
	if(pDp)
	{
		if(pDp->dwMask & DP_SCALE)
		{
			cx = (int)(rtSrc.Width() * pDp->fScaleX);
			cy = (int)(rtSrc.Height() * pDp->fScaleY);
		}
		if(pDp->dwMask & DP_DEST_LIMIT)
		{
			cx = pDp->cx;
			cy = pDp->cy;
		}
		if(pDp->dwMask & DP_TILE)
		{
			cx = pDp->nTileLength;
		}
		if(pDp->dwMask & DP_VER_TILE)
		{
			cy = pDp->nTileLength;
		}
	}
	rtDest.SetRect(x, y, x + cx, y + cy);
	if(pSrc)
	{
		*pSrc = rtSrc;
	}
	return rtDest;
}

BOOL CSonicImage::SetColorKey(DWORD dwColor)
{
	if(IsAlphaChannelValid())
	{
		return FALSE;
	}
	CSSE::SetColorKey(m_Dib.GetBits(), m_Dib.GetSize(), dwColor);
	EnableAlphaChannel(FALSE);
	return TRUE;
}

BOOL CSonicImage::Load(HDC hdc, int x, int y, int cx, int cy, BOOL bAlphaChannel /* = FALSE */)
{
	Clear();
	BITMAP bmp;
	GetObject((HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP), sizeof(bmp), &bmp);
	if(bmp.bmType != 0 || bmp.bmPlanes != 1)
	{
		return FALSE;
	}
	if(bmp.bmBitsPixel != 32)
	{
		return FALSE;
	}

	if(PrepareMemDC(cx, cy) == FALSE)
	{
		return FALSE;
	}
	BitBlt(m_Dib.GetSafeHdc(), 0, 0, cx, cy, hdc, x, y, SRCCOPY);
	if(bAlphaChannel)
	{
		EnableAlphaChannel(FALSE);
		CSSE::DoOr(0xff000000, m_Dib.GetBits(), m_Dib.GetSize());
	}
	return TRUE;
}

BOOL CSonicImage::Create(int cx, int cy, DWORD dwColor /* = 0 */, BOOL bWithAlpha /* = FALSE */)
{
	if(PrepareMemDC(cx, cy) == FALSE)
	{
		return FALSE;
	}
	if(bWithAlpha)
	{
		CSSE::AdjustAlpha(dwColor);
		EnableAlphaChannel(FALSE);
	}
	if(dwColor)
	{
		Flush(dwColor);
	}
	return TRUE;
}

BOOL CSonicImage::Flush(DWORD dwColor)
{
	if(m_Dib.IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::MemSetDWord(m_Dib.GetBits(), dwColor, m_Dib.GetSize());
	return TRUE;
}

BOOL CSonicImage::SetHsl(int h /* = -1 */, int s /* = -1 */, int l /* = -1 */)
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::SetHSL(m_Dib.GetBits(), m_Dib.GetSize(), h, s, l);
	return TRUE;
}

BOOL CSonicImage::MirrorX()
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::MirrorX(m_Dib.GetBits(), m_nWidth, m_nHeight);
	return TRUE;
}

BOOL CSonicImage::MirrorY()
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::MirrorY(m_Dib.GetBits(), m_nWidth, m_nHeight);
	return TRUE;
}

BOOL CSonicImage::Stretch(int cx, int cy)
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	if(cx == m_nWidth && cy == m_nHeight)
	{
		return TRUE;
	}
	CSonicImage * pImg = (CSonicImage *)g_UI.CreateImage();
	pImg->CloneFrom(this);
	PrepareMemDC(cx, cy);
	CSSE::Stretch(pImg->m_Dib.GetBits(), pImg->GetWidth(), pImg->GetHeight(), m_Dib.GetBits(), cx, cy);
	g_UI.DestroyObject(pImg);
	return TRUE;
}

BOOL CSonicImage::Extend(int cx /* = 0 */, int cy /* = 0 */)
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	cx = (cx == 0 ? m_nWidth : cx);
	cy = (cy == 0 ? m_nHeight : cy);
	CSonicImage * pImg = (CSonicImage *)g_UI.CreateImage();
	pImg->CloneFrom(this);

	PrepareMemDC(cx, cy);
	for(int i = 0; i < cy; i += pImg->GetHeight())
	{
		for(int j = 0; j < cx; j += pImg->GetWidth())
		{
			pImg->SetBitsToDevice(m_Dib.GetSafeHdc(), j, i);
		}
	}
	g_UI.DestroyObject(pImg);
	return TRUE;
}

HDC CSonicImage::GetDC()
{
	if(IsValid() == FALSE)
	{
		return NULL;
	}
	return m_Dib.GetSafeHdc();
}

BOOL CSonicImage::DestroyAlphaChannel()
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::DoAnd(0xffffff, (char *)m_Dib.GetBits(), m_Dib.GetSize());
	return TRUE;
}

BOOL CSonicImage::SetAlphaChannel(BYTE bAlpha)
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}
	CSSE::DoOr((bAlpha << 24), (char *)m_Dib.GetBits(), m_Dib.GetSize());
	EnableAlphaChannel(FALSE);
	return TRUE;
}

BOOL CSonicImage::Blur(int nType /* = 0 */)
{
	if(IsValid() == FALSE)
	{
		return FALSE;
	}

	char * pTemp = new char[m_Dib.GetSize()];
	CSSE::MemCopy(pTemp, m_Dib.GetBits(), m_Dib.GetSize());
	int i, j;
	DWORD * pSrc = (DWORD *)m_Dib.GetBits();
	DWORD * pDest = (DWORD *)pTemp;
	for(i = 1; i < m_Dib.GetHeight() - 1; i++)
	{
		for(j = 1; j < m_Dib.GetWidth() - 1; j++)
		{
			DWORD dw1 = *(pDest + i * m_Dib.GetWidth() + j);
			DWORD dw2 = *(pDest + i * m_Dib.GetWidth() + j - 1);
			DWORD dw3 = *(pDest + i * m_Dib.GetWidth() + j + 1);
			DWORD dw4 = *(pDest + (i - 1) * m_Dib.GetWidth() + j);
			DWORD dw5 = *(pDest + (i + 1) * m_Dib.GetWidth() + j);
			DWORD dw6 = *(pDest + (i - 1) * m_Dib.GetWidth() + j - 1);
			DWORD dw7 = *(pDest + (i - 1) * m_Dib.GetWidth() + j + 1);
			DWORD dw8 = *(pDest + (i + 1) * m_Dib.GetWidth() + j - 1);
			DWORD dw9 = *(pDest + (i + 1) * m_Dib.GetWidth() + j + 1);
			char r, g, b;
			r = g = b = 0;
			switch (nType)
			{
			case 0:
				{
					// gauss blur
					r = ((GetRValue(dw1) << 2) +
						((GetRValue(dw2) +
						GetRValue(dw3) +
						GetRValue(dw4) +
						GetRValue(dw5)) << 1) + 
						GetRValue(dw6) +
						GetRValue(dw7) +
						GetRValue(dw8) +
						GetRValue(dw9)) >> 4;
					g = ((GetGValue(dw1) << 2) +
						((GetGValue(dw2) +
						GetGValue(dw3) +
						GetGValue(dw4) +
						GetGValue(dw5)) << 1) + 
						GetGValue(dw6) +
						GetGValue(dw7) +
						GetGValue(dw8) +
						GetGValue(dw9)) >> 4;
					b = ((GetBValue(dw1) << 2) +
						((GetBValue(dw2) +
						GetBValue(dw3) +
						GetBValue(dw4) +
						GetBValue(dw5)) << 1) + 
						GetBValue(dw6) +
						GetBValue(dw7) +
						GetBValue(dw8) +
						GetBValue(dw9)) >> 4;
				}
				break;
			case 1:
				{
					// even blur
					r = (GetRValue(dw1) +
						GetRValue(dw2) +
						GetRValue(dw3) +
						GetRValue(dw4) +
						GetRValue(dw5) + 
						GetRValue(dw6) +
						GetRValue(dw7) +
						GetRValue(dw8) +
						GetRValue(dw9)) / 9;
					g = (GetGValue(dw1) +
						GetGValue(dw2) +
						GetGValue(dw3) +
						GetGValue(dw4) +
						GetGValue(dw5) + 
						GetGValue(dw6) +
						GetGValue(dw7) +
						GetGValue(dw8) +
						GetGValue(dw9)) / 9;
					b = (GetBValue(dw1) +
						GetBValue(dw2) +
						GetBValue(dw3) +
						GetBValue(dw4) +
						GetBValue(dw5) + 
						GetBValue(dw6) +
						GetBValue(dw7) +
						GetBValue(dw8) +
						GetBValue(dw9)) / 9;
				}
				break;
			}
			
			*(pSrc + i * m_Dib.GetWidth() + j) = (0xff000000 | RGB(r, g, b));
		}
	}

	delete []pTemp;
	return TRUE;
}