1. 程式人生 > >C++ GDI+ 多張圖片合併生成GIF動畫格式圖片

C++ GDI+ 多張圖片合併生成GIF動畫格式圖片

CGifEncoder::CGifEncoder()
{
	m_started	= false;
	m_width		= 320;
	m_height	= 240;
	m_delayTime = 100;
	m_repeatNum = 0;
	m_haveFrame = false;
	m_pStrSavePath = NULL;
	m_pImage	   = NULL;
}

CGifEncoder::~CGifEncoder()
{
	if (NULL != m_pStrSavePath)
	{
		delete m_pStrSavePath;
	}
	
	if (NULL != m_pImage)
	{
		delete m_pImage;
	}	

	size_t size = m_pBitMapVec.size();
	for (size_t ix=0; ix<size; ix++)
	{
		delete m_pBitMapVec[ix];
		m_pBitMapVec[ix] = NULL;
	}
}

bool CGifEncoder::StartEncoder( wstring &saveFilePath )
{
	bool flag = true;

	if ( NULL != m_pStrSavePath)
	{
		delete m_pStrSavePath;
		m_pStrSavePath = NULL;
	}

	m_pStrSavePath = new wstring(saveFilePath);
	m_started = true;

	return(flag);
}

bool CGifEncoder::AddFrame( Gdiplus::Image *pImage )
{
	if (!m_started || NULL == pImage)
	{
		return(false);
	}

	bool flag = true;
	if (!m_haveFrame)
	{
		m_pImage = new Gdiplus::Bitmap(m_width, m_height);
		Gdiplus::Graphics g(m_pImage);
		g.DrawImage(pImage, 0, 0, m_width, m_height);

		m_haveFrame = true;
		return(true);
	}

	Gdiplus::Bitmap *pBitMap = new Gdiplus::Bitmap(m_width, m_height);
	Gdiplus::Graphics g(pBitMap);
	g.DrawImage(pImage, 0, 0, m_width, m_height);
	m_pBitMapVec.push_back(pBitMap);
	
	return(flag);
}

bool CGifEncoder::AddFrame( wstring &framePath )
{
	if (!m_started)
	{
		return(false);
	}

	bool flag = true;
	Gdiplus::Status statue;
	if (!m_haveFrame)
	{
		m_pImage = new Gdiplus::Bitmap(m_width, m_height);
		Gdiplus::Graphics g(m_pImage);

		Gdiplus::Bitmap bitmap(framePath.c_str());
		g.DrawImage(&bitmap, 0, 0, m_width, m_height);

		m_haveFrame = true;
		return(true);
	}	

	Gdiplus::Bitmap		*pBitMap = new Gdiplus::Bitmap(m_width, m_height);
	Gdiplus::Graphics	g(pBitMap);

	Gdiplus::Bitmap bitmap(framePath.c_str());
	statue = g.DrawImage(&bitmap, 0, 0, m_width, m_height);

	m_pBitMapVec.push_back(pBitMap);

	return(flag);
}

bool CGifEncoder::FinishEncoder()
{
	if (!m_started || !m_haveFrame)
	{
		return(false);
	}

	bool	flag = true;
	Gdiplus::Status statue;

	//1.0 設定影象的屬性
	SetImagePropertyItem();

	//2.0 儲存第一副影象
	GUID						gifGUID;
	Gdiplus::EncoderParameters	encoderParams;  
	GetEncoderClsid(L"image/gif", &gifGUID);
	
	encoderParams.Count = 1;
	encoderParams.Parameter[0].Guid			= Gdiplus::EncoderSaveFlag;
	encoderParams.Parameter[0].NumberOfValues = 1;
	encoderParams.Parameter[0].Type			=  Gdiplus::EncoderParameterValueTypeLong;//第一幀需要設定為MultiFrame

	long firstValue						= Gdiplus::EncoderValueMultiFrame;
	encoderParams.Parameter[0].Value	=  &firstValue;	
	
	m_pImage->Save(m_pStrSavePath->c_str(), &gifGUID, &encoderParams);

	//3.0 儲存剩餘的影象
	size_t size = m_pBitMapVec.size();
	firstValue						= Gdiplus::EncoderValueFrameDimensionTime;
	encoderParams.Parameter[0].Value=  &firstValue;	
	for (size_t ix = 0; ix <size; ix++)
	{
		statue = m_pImage->SaveAdd(m_pBitMapVec[ix], &encoderParams);
	}

	m_started = false;
	m_haveFrame = false;
	return(flag);
}

void CGifEncoder::SetDelayTime( int ms )
{
	if (ms > 0)
	{
		m_delayTime = ms / 10.0f;
	}	
}

void CGifEncoder::SetRepeatNum( int num )
{
	if (num >= 0) 
	{
		m_repeatNum = num;
	}
}

void CGifEncoder::SetFrameRate( float fps )
{
	if (fps > 0) 
	{
		m_delayTime = 100.0f / fps;
	}
}

void CGifEncoder::SetFrameSize( int width, int height )
{
	if (!m_haveFrame) 
	{
		m_width  = width;
		m_height = height;

		if (m_width < 1) 
			m_width = 320;

		if (m_height < 1) 
			height = 240;
	}	
}

void CGifEncoder::SetImagePropertyItem()
{
	if (!m_started || NULL == m_pImage)
	{
		return;
	}

	Gdiplus::PropertyItem propertyItem;

	//1.0 設定動畫迴圈的次數	
	short sValue		= m_repeatNum; //0 -- 不限次數
	propertyItem.id		= PropertyTagLoopCount; 
	propertyItem.length = 2; //位元組數
	propertyItem.type	= PropertyTagTypeShort;
	propertyItem.value	= &sValue; 
	m_pImage->SetPropertyItem(&propertyItem);

	//2.0 設定每副影象延遲的時間,從第一副開始
	long lImageNum = 1 + m_pBitMapVec.size();
	long *plValue = new long[lImageNum];
	for (int ix=0; ix<lImageNum; ix++)
	{
		plValue[ix] = m_delayTime; //可以設定不一樣
	}
	propertyItem.id		= PropertyTagFrameDelay; 
	propertyItem.length = 4 * lImageNum;//位元組數
	propertyItem.type	= PropertyTagTypeLong;
	propertyItem.value	= plValue; //不限次數
	m_pImage->SetPropertyItem(&propertyItem);

	delete []plValue;
	plValue = NULL;
}

bool CGifEncoder::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	UINT num = 0, size = 0;

	Gdiplus::GetImageEncodersSize(&num, &size);
	if(size == 0)
		return false;  // Failure

	Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));

	Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
	bool found = false;
	for (UINT ix = 0; !found && ix < num; ++ix) 
	{
		if (_wcsicmp(pImageCodecInfo[ix].MimeType, format) == 0) 
		{
			*pClsid = pImageCodecInfo[ix].Clsid;
			found = true;
			break;
		}
	}

	free(pImageCodecInfo);
	return found;
}

【4】測試程式碼