#include "stdafx.h" #include "ImageCompress.h" ULONG_PTR ImageCompress::m_gdiplusToken = NULL; ImageCompress::ImageCompress(void) { } ImageCompress::~ImageCompress(void) { } // 图片压缩格式; //image/bmp //image/jpeg //image/gif //image/tiff //image/png int ImageCompress::GetEncoderClsid(IN const WCHAR* format, OUT CLSID* pClsid) { UINT nNumberOfImageEncoders = 0; // number of image encoders UINT nSizeOfImageEndcoderArray = 0; // size of the image encoder array in bytes ImageCodecInfo* pImageCodecInfo = NULL; GetImageEncodersSize(&nNumberOfImageEncoders, &nSizeOfImageEndcoderArray); if (nSizeOfImageEndcoderArray == 0) return -1; // Failure pImageCodecInfo = (ImageCodecInfo*)(malloc(nSizeOfImageEndcoderArray)); if (pImageCodecInfo == NULL) return -1; // Failure GetImageEncoders(nNumberOfImageEncoders, nSizeOfImageEndcoderArray, pImageCodecInfo); for (UINT i = 0; i < nNumberOfImageEncoders; ++i) { if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) { *pClsid = pImageCodecInfo[i].Clsid; free(pImageCodecInfo); return i; // Success } } free(pImageCodecInfo); return -1; // FailureFailure } //Scale 比例; //Zoom 缩放; // 给定最小(最大)宽度,按比例(原图宽/指定宽)缩放图片大小,获取完整缩放尺寸; //----------------------------------------------------------------------------------------------------------------------- // // 函数:ScaleZoombySpecificWidth // 描述:以指定高来缩放矩形; // 参数: // nWidth : 指定的压缩宽; // nHeight : 指定的压缩高; // rc : 压缩存放的区域; // // 返回:#; // // 注意:; // //----------------------------------------------------------------------------------------------------------------------- void ImageCompress::ScaleZoombySpecificHeight(IN const int &nWidth, IN const int &nHeight, IN OUT CRect &rc) { try { if (nWidth == 0 || nHeight == 0)return; // 图片长宽比例; float fscale = (float)nWidth / (float)nHeight; // 设备长宽比例; float rcscale = ((float)rc.Width()) / ((float)rc.Height()); int rcwid = rc.Width(); int rchei = rc.Height(); int dt = 0; // Jeff.如果设备长宽比例 < 图片长宽比例;(即相同长度下,高越大比例值越小,所以此时图片尺寸 与 显示设备的尺寸相比,要显得更长) if (rcscale < fscale) { // Jeff.remarks // 调整显示设备的大小,以使之能容纳图片尺寸;(即长宽比例上,要大于或等于图片的长宽比例) // 所以有两种方法使得 rcscale >= fscale 表达式成立: // ----------------------------------------------- // 方法1:显示设备宽加x值,计算出下面表达式x的值即可 // (rc.Width()+x) / rc.Height() >= width/height; // 方法2:显示设备高减x值,计算出下面表达式x的值即可 // (rc.Width()) / (rc.Height()-x) >= width/height; //------------------------------------------------ // 两种方法的最后表达式为: // x >= rc.Height() - rcWidth()*(height/width); // 即 x >= rc.Height() - rcWidth()/fscale; //------------------------------------------------ dt = (rchei - rcwid / fscale) / 2; rc.top += dt; rc.bottom -= dt; } else { dt = (rcwid - rchei*fscale) / 2; rc.left += dt; rc.right -= dt; } } catch (...) { } } //----------------------------------------------------------------------------------------------------------------------- // // 函数:ScaleZoombySpecificWidth // 描述:以指定宽来缩放矩形; // 参数: // nWidth : 指定的压缩宽; // nHeight : 指定的压缩高; // rc : 压缩存放的区域; // // 返回:#; // // 注意:; // //----------------------------------------------------------------------------------------------------------------------- void ImageCompress::ScaleZoombySpecificWidth(IN const int &nWidth, IN const int &nHeight, IN OUT CRect &rc) { try { if (nWidth == 0 || nHeight == 0)return; // 图片长宽比例; float fscale = (float)nWidth / (float)nHeight; // 设备长宽比例; float rcscale = ((float)rc.Width()) / ((float)rc.Height()); int rcwid = rc.Width(); int rchei = rc.Height(); int dt = 0; // Jeff.如果设备长宽比例 < 图片长宽比例;(即相同长度下,高越大比例值越小,所以此时图片尺寸 与 显示设备的尺寸相比,要显得更长) if (rcscale < fscale) { // Jeff.remarks // 调整显示设备的大小,以使之能容纳图片尺寸;(即长宽比例上,要大于或等于图片的长宽比例) // 所以有两种方法使得 rcscale >= fscale 表达式成立: // ----------------------------------------------- // 方法1:显示设备宽加x值,计算出下面表达式x的值即可 // (rc.Width()+x) / rc.Height() >= width/height; // 方法2:显示设备高减x值,计算出下面表达式x的值即可 // (rc.Width()) / (rc.Height()-x) >= width/height; //------------------------------------------------ // 两种方法的最后表达式为: // x >= rc.Height() - rcWidth()*(height/width); // 即 x >= rc.Height() - rcWidth()/fscale; //------------------------------------------------ dt = (rcwid - rchei*fscale) / 2; rc.left += dt; rc.right -= dt; } else { dt = (rchei - rcwid / fscale) / 2; rc.top += dt; rc.bottom -= dt; } } catch (...) { } } //----------------------------------------------------------------------------------------------------------------------- // // 函数:SaveImageToFile // 描述:压缩指定目录的相片到指定目录; // 参数: // img : Image对象; // path : 压缩后相片保存路径; // quality : 压缩的质量值; // // 返回:#; // // 注意:; // //----------------------------------------------------------------------------------------------------------------------- void ImageCompress::SaveImageToFile(IN Image *img, IN CString &path, IN ULONG quality) { try { if (img == NULL)return; CLSID encoderClsid; BSTR bstr = path.AllocSysString(); path.MakeLower(); if (path.Right(3) == _T("bmp")) { GetEncoderClsid(L"image/bmp", &encoderClsid); img->Save(bstr, &encoderClsid, NULL); } else if (path.Right(3) == _T("png")) { GetEncoderClsid(L"image/png", &encoderClsid); img->Save(bstr, &encoderClsid, NULL); } else// if(path.Right (3)== _T("jpg")) { GetEncoderClsid(L"image/jpeg", &encoderClsid); EncoderParameters encoderParameters; encoderParameters.Count = 1; encoderParameters.Parameter[0].Guid = EncoderQuality; encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; encoderParameters.Parameter[0].NumberOfValues = 1; // Save the image as a JPEG with quality level 100. encoderParameters.Parameter[0].Value = &quality; img->Save(bstr, &encoderClsid, &encoderParameters); } SysFreeString(bstr); } catch (...) { } } //----------------------------------------------------------------------------------------------------------------------- // // 函数:ToCompressImage // 描述:压缩指定目录的相片到指定目录; // 参数: // pImageSource : 原相片完整路径; // pImageDest : 压缩后相片保存路径; // nXPiexel : 压缩的像素宽; // nYPiexel : 压缩的像素高; // // 返回:#; // // 注意:; // //----------------------------------------------------------------------------------------------------------------------- BOOL ImageCompress::ToCompressImage(IN const TCHAR *pImageSource, IN const TCHAR *pImageDest, IN const int &nXPiexel, IN const int &nYPiexel) { Image *pImage = NULL; ::DeleteFile(pImageDest); // 1.从文件中以读的方式加载图片到Image中; CFile cf; if (cf.Open(pImageSource, CFile::modeRead)) { DWORD dwLength = cf.GetLength(); BYTE *pData = new BYTE[dwLength]; if (pData == NULL)// 创建内存失败; return FALSE; cf.Read(pData, dwLength); cf.Close(); // 1.1.将文件数据加载到内存数据中; HGLOBAL taghMem = GlobalAlloc(GMEM_MOVEABLE, dwLength); if (taghMem == NULL) // 创建内存失败; return FALSE; BYTE *pMem = (BYTE*)GlobalLock(taghMem); memcpy(pMem, pData, dwLength); // 1.2.创建二进制流对象; IStream *pStream; CreateStreamOnHGlobal(taghMem, TRUE, &pStream); pImage = Gdiplus::Image::FromStream(pStream); GlobalUnlock(taghMem); pStream->Release(); delete[]pData; } // 2.加载后…… if (pImage == NULL) // 加载失败; return FALSE; // 2.1.当图片的像素大于要设定的像素时,进行处理; if (pImage->GetWidth() > nXPiexel || pImage->GetHeight() > nYPiexel) { CRect tagRect(0, 0, nXPiexel, nYPiexel); ScaleZoombySpecificWidth(pImage->GetWidth(), pImage->GetHeight(), tagRect); Bitmap bp(tagRect.Width(), tagRect.Height()); Graphics *graphic = Graphics::FromImage(&bp); graphic->Clear(Color(255, 255, 255, 255)); graphic->SetInterpolationMode(InterpolationModeHighQualityBicubic); graphic->SetSmoothingMode(SmoothingModeHighQuality);//SmoothingModeHighSpeed graphic->SetPixelOffsetMode(PixelOffsetModeHighQuality); graphic->SetCompositingMode(CompositingModeSourceOver); graphic->SetCompositingQuality(CompositingQualityHighQuality); graphic->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit); graphic->DrawImage(pImage, RectF(0, 0, tagRect.Width(), tagRect.Height()), 0, 0, pImage->GetWidth(), pImage->GetHeight(), UnitPixel); delete pImage; try { CString path(pImageDest); CLSID encoderClsid; BSTR bstr = path.AllocSysString(); path.MakeLower(); if (path.Right(3) == _T("bmp")) { GetEncoderClsid(L"image/bmp", &encoderClsid); bp.Save(bstr, &encoderClsid, NULL); } else if (path.Right(3) == _T("png")) { GetEncoderClsid(L"image/png", &encoderClsid); bp.Save(bstr, &encoderClsid, NULL); } else// if(path.Right (3)=="jpg") { ULONG quality = 95; GetEncoderClsid(L"image/jpeg", &encoderClsid); EncoderParameters encoderParameters; encoderParameters.Count = 1; encoderParameters.Parameter[0].Guid = EncoderQuality; encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; encoderParameters.Parameter[0].NumberOfValues = 1; // Save the image as a JPEG with quality level 100. encoderParameters.Parameter[0].Value = &quality; bp.Save(bstr, &encoderClsid, &encoderParameters); } SysFreeString(bstr); } catch (...) { return FALSE; } } return TRUE; }