这几天遇到个需求,要求缩放图片,但是不能改变图片的dpi,用 opencv 不行,于是在网上找,但是找了很久没有找到相关的信息,只有一篇帖子说使用 Gdiplus 可以满足这个需求,遂研究了一下 Gdiplus 的接口,终于找到了 Gdiplus::Bitmap::SetResolution
这个方法,新技能 Get!
完整的代码如下:
#pragma comment(lib, "")
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
/*
* 该方法获取相应图片的 class id
*/
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
Gdiplus::GetImageEncodersSize(&num, &size);
if (size == 0)
{
return -1;
}
pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL)
{
return -1;
}
Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
for (UINT j = 0; j < num; ++j)
{
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
bool GdiplusUtils::resizeImage(const std::string &sourceImagePath,
const std::string &targetImagePath,
int targetImageWidth,
int targetImageHeight,
const std::string &targetImageEncoder,
Gdiplus::PixelFormat targetImagePixelFormat,
bool remainResolution)
{
/*
* Load source image and get information
*/
Gdiplus::Bitmap sourceImage(StringUtils::MB2WC(sourceImagePath).c_str(), FALSE);
/*
* Rescale and set resolution
*/
// rescale
Gdiplus::Bitmap targetImage(targetImageWidth, targetImageHeight, targetImagePixelFormat);
Gdiplus::Graphics graphics(&targetImage);
(&sourceImage, 0, 0, targetImageWidth, targetImageHeight);
// set resolution
if (remainResolution)
{
auto hResolution = ();
auto vResolution = ();
(hResolution, vResolution);
}
/*
* Save Image
*/
CLSID clsid;
GetEncoderClsid(StringUtils::MB2WC(targetImageEncoder).c_str(), &clsid);
(StringUtils::MB2WC(targetImagePath).c_str(), &clsid);
return true;
}
需要注意的是必须引入 ,并且需要通过 Gdiplus::GdiplusStartup
与 Gdiplus::GdiplusShutdown
来初始化和反初始化 Gdiplus。这些内容没有体现在上面的代码中,读者需要在合适的位置自行添加。
最后,代码中的 StringUtils::MB2WC
是一个将多字节字符转换为宽字节字符的辅助函数,代码如下:
std::wstring StringUtils::MB2WC(const std::string &mb)
{
int lenWC = ::MultiByteToWideChar(CP_ACP, 0, mb.c_str(), (), NULL, 0);
std::unique_ptr<wchar_t> wc(new wchar_t[lenWC]());
::MultiByteToWideChar(CP_ACP, 0, mb.c_str(), (), (), lenWC);
return std::wstring((), lenWC);
}