VC GDI+ 生成简单验证码图片

先看效果图:

参考了另一篇C#的文章:https://blog.csdn.net/shenqiankk/article/details/99636425,本文将其大致翻译到VC

1 项目肯定要包含gdi+头文件

#include <GdiPlus.h>

#pragma comment(lib, "gdiplus.lib")

2 初始化gdi+

ULONG_PTR m_gdiplusToken;
Gdiplus::GdiplusStartupInput StartupInput;  
GdiplusStartup(&m_gdiplusToken,&StartupInput,NULL);

3 相关代码

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

	Gdiplus::GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // 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;
}

int RangedRand(int range_min, int range_max)
{
	int u = (double)rand() / (RAND_MAX + 1) * (range_max - range_min)
		+ range_min;

	return u;
}

DWORD GetMsInterval(DWORD dwNow, DWORD dwLast)
{
	if( dwNow < dwLast )
		return 0xFFFFFFFF - dwLast + dwNow;
	else
		return dwNow - dwLast;
}

//生成的代码
void GenerateCode()
{
	DWORD dwBegin = GetTickCount();
	using namespace Gdiplus;
	wchar_t toDrawText[64] = {0};
	swprintf_s(toDrawText, 63, L"%d", RangedRand(1000, 9999));
	Gdiplus::Bitmap bmp(120, 40, PixelFormat32bppARGB);
	Graphics g(&bmp);

	for (int i = 0; i < bmp.GetWidth(); i++)
	{
		for (int j = 0; j < bmp.GetHeight(); j++){
			bmp.SetPixel(i, j, Color::Transparent);
		}
	}

	std::vector<std::wstring> fonts;
	fonts.push_back(L"微软雅黑");
	fonts.push_back(L"宋体");
	fonts.push_back(L"楷体");
	fonts.push_back(L"仿宋");

	std::vector<DWORD> colors;
	colors.push_back(Color::Yellow);
	colors.push_back(Color::Blue);
	colors.push_back(Color::Red);
	colors.push_back(Color::Green);
	colors.push_back(Color::Purple);

	int len = wcslen(toDrawText);
	for (int i = 0; i < len; i++)
	{
		Gdiplus::PointF p(i * 20, 0);

		Color clr;
		clr.SetFromCOLORREF(colors[rand() % colors.size()]);

		g.DrawString(toDrawText + i, 
			1, 
			&Gdiplus::Font(&FontFamily(fonts[rand() % fonts.size()].c_str()), 25, Gdiplus::FontStyleBold, Gdiplus::Unit::UnitPoint), 
			p, 
			&SolidBrush(clr));
	}

	// 干扰线
	Color lineColor(colors[rand() % colors.size()]);  //随机颜色
	for (int i = 0; i < 3; i++){
		PointF p1(RangedRand(0, bmp.GetWidth()), RangedRand(0, bmp.GetHeight()));
		PointF p2(RangedRand(0, bmp.GetWidth()), RangedRand(0, bmp.GetHeight()));

		g.DrawLine(&Gdiplus::Pen(lineColor), p1, p2);
	}

	Color lineColor2(colors[rand() % colors.size()]);
	for (int i = 0; i < 3; i++){
		PointF p1(RangedRand(0, bmp.GetWidth()), RangedRand(0, bmp.GetHeight()));
		PointF p2(RangedRand(0, bmp.GetWidth()), RangedRand(0, bmp.GetHeight()));

		g.DrawLine(&Gdiplus::Pen(lineColor2), p1, p2);
	}

	// 干扰点
	for (int i = 0; i < 500; i++)
	{
		PointF p(RangedRand(0, bmp.GetWidth()), RangedRand(0, bmp.GetHeight()));
		bmp.SetPixel(p.X, p.Y, Color::Black);
	}

	IStream* pIStream = NULL;
	CreateStreamOnHGlobal(NULL, TRUE, &pIStream);

	std::vector<BYTE> data;
	CLSID   clsID			 = GUID_NULL;
	wchar_t ext[_MAX_EXT]    = {0};
	wchar_t format[_MAX_EXT] = {L"image/"};
	std::wstring strPicPath = L"E:\\my2.png";
	_wsplitpath_s(strPicPath.c_str(), NULL, 0, NULL, 0, NULL, 0, ext, _MAX_EXT);
	wcscat_s(format, _MAX_EXT, ext + 1);
	if (GetEncoderClsid2(format, &clsID))
	{
		 Gdiplus::Status status = bmp.Save(pIStream, &clsID);
		 if (status != Gdiplus::Status::Ok)
			 return;

		 HGLOBAL hg = NULL;
		 GetHGlobalFromStream(pIStream, &hg);

		 int bufSize = GlobalSize(hg);
		 data.resize(bufSize);

		 LPVOID pImage = GlobalLock(hg);
		 memcpy(&data[0], pImage, bufSize);
		 GlobalUnlock(hg);

		 pIStream->Release();
		//printf("success\n");
		//bmp.Save(strPicPath.c_str(), &clsID, NULL);
	}
	else{
		printf("failed\n");
	}
}

代码里,显示绘制数字,核心函数Graphics::DrawText,然后是绘制干扰线和干扰点,后面是测试保存到本地或字节流。

缺少啥头文件酌情添加。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值