ImageCompress.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include "stdafx.h"
  2. #include "ImageCompress.h"
  3. ULONG_PTR ImageCompress::m_gdiplusToken = NULL;
  4. ImageCompress::ImageCompress(void)
  5. {
  6. }
  7. ImageCompress::~ImageCompress(void)
  8. {
  9. }
  10. // 图片压缩格式;
  11. //image/bmp
  12. //image/jpeg
  13. //image/gif
  14. //image/tiff
  15. //image/png
  16. int ImageCompress::GetEncoderClsid(IN const WCHAR* format, OUT CLSID* pClsid)
  17. {
  18. UINT nNumberOfImageEncoders = 0; // number of image encoders
  19. UINT nSizeOfImageEndcoderArray = 0; // size of the image encoder array in bytes
  20. ImageCodecInfo* pImageCodecInfo = NULL;
  21. GetImageEncodersSize(&nNumberOfImageEncoders, &nSizeOfImageEndcoderArray);
  22. if (nSizeOfImageEndcoderArray == 0)
  23. return -1; // Failure
  24. pImageCodecInfo = (ImageCodecInfo*)(malloc(nSizeOfImageEndcoderArray));
  25. if (pImageCodecInfo == NULL)
  26. return -1; // Failure
  27. GetImageEncoders(nNumberOfImageEncoders, nSizeOfImageEndcoderArray, pImageCodecInfo);
  28. for (UINT i = 0; i < nNumberOfImageEncoders; ++i)
  29. {
  30. if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
  31. {
  32. *pClsid = pImageCodecInfo[i].Clsid;
  33. free(pImageCodecInfo);
  34. return i; // Success
  35. }
  36. }
  37. free(pImageCodecInfo);
  38. return -1; // FailureFailure
  39. }
  40. //Scale 比例;
  41. //Zoom 缩放;
  42. // 给定最小(最大)宽度,按比例(原图宽/指定宽)缩放图片大小,获取完整缩放尺寸;
  43. //-----------------------------------------------------------------------------------------------------------------------
  44. //
  45. // 函数:ScaleZoombySpecificWidth
  46. // 描述:以指定高来缩放矩形;
  47. // 参数:
  48. // nWidth : 指定的压缩宽;
  49. // nHeight : 指定的压缩高;
  50. // rc : 压缩存放的区域;
  51. //
  52. // 返回:#;
  53. //
  54. // 注意:;
  55. //
  56. //-----------------------------------------------------------------------------------------------------------------------
  57. void ImageCompress::ScaleZoombySpecificHeight(IN const int &nWidth, IN const int &nHeight, IN OUT CRect &rc)
  58. {
  59. try
  60. {
  61. if (nWidth == 0 || nHeight == 0)return;
  62. // 图片长宽比例;
  63. float fscale = (float)nWidth / (float)nHeight;
  64. // 设备长宽比例;
  65. float rcscale = ((float)rc.Width()) / ((float)rc.Height());
  66. int rcwid = rc.Width();
  67. int rchei = rc.Height();
  68. int dt = 0;
  69. // Jeff.如果设备长宽比例 < 图片长宽比例;(即相同长度下,高越大比例值越小,所以此时图片尺寸 与 显示设备的尺寸相比,要显得更长)
  70. if (rcscale < fscale)
  71. {
  72. // Jeff.remarks
  73. // 调整显示设备的大小,以使之能容纳图片尺寸;(即长宽比例上,要大于或等于图片的长宽比例)
  74. // 所以有两种方法使得 rcscale >= fscale 表达式成立:
  75. // -----------------------------------------------
  76. // 方法1:显示设备宽加x值,计算出下面表达式x的值即可
  77. // (rc.Width()+x) / rc.Height() >= width/height;
  78. // 方法2:显示设备高减x值,计算出下面表达式x的值即可
  79. // (rc.Width()) / (rc.Height()-x) >= width/height;
  80. //------------------------------------------------
  81. // 两种方法的最后表达式为:
  82. // x >= rc.Height() - rcWidth()*(height/width);
  83. // 即 x >= rc.Height() - rcWidth()/fscale;
  84. //------------------------------------------------
  85. dt = (rchei - rcwid / fscale) / 2;
  86. rc.top += dt;
  87. rc.bottom -= dt;
  88. }
  89. else
  90. {
  91. dt = (rcwid - rchei*fscale) / 2;
  92. rc.left += dt;
  93. rc.right -= dt;
  94. }
  95. }
  96. catch (...)
  97. {
  98. }
  99. }
  100. //-----------------------------------------------------------------------------------------------------------------------
  101. //
  102. // 函数:ScaleZoombySpecificWidth
  103. // 描述:以指定宽来缩放矩形;
  104. // 参数:
  105. // nWidth : 指定的压缩宽;
  106. // nHeight : 指定的压缩高;
  107. // rc : 压缩存放的区域;
  108. //
  109. // 返回:#;
  110. //
  111. // 注意:;
  112. //
  113. //-----------------------------------------------------------------------------------------------------------------------
  114. void ImageCompress::ScaleZoombySpecificWidth(IN const int &nWidth, IN const int &nHeight, IN OUT CRect &rc)
  115. {
  116. try
  117. {
  118. if (nWidth == 0 || nHeight == 0)return;
  119. // 图片长宽比例;
  120. float fscale = (float)nWidth / (float)nHeight;
  121. // 设备长宽比例;
  122. float rcscale = ((float)rc.Width()) / ((float)rc.Height());
  123. int rcwid = rc.Width();
  124. int rchei = rc.Height();
  125. int dt = 0;
  126. // Jeff.如果设备长宽比例 < 图片长宽比例;(即相同长度下,高越大比例值越小,所以此时图片尺寸 与 显示设备的尺寸相比,要显得更长)
  127. if (rcscale < fscale)
  128. {
  129. // Jeff.remarks
  130. // 调整显示设备的大小,以使之能容纳图片尺寸;(即长宽比例上,要大于或等于图片的长宽比例)
  131. // 所以有两种方法使得 rcscale >= fscale 表达式成立:
  132. // -----------------------------------------------
  133. // 方法1:显示设备宽加x值,计算出下面表达式x的值即可
  134. // (rc.Width()+x) / rc.Height() >= width/height;
  135. // 方法2:显示设备高减x值,计算出下面表达式x的值即可
  136. // (rc.Width()) / (rc.Height()-x) >= width/height;
  137. //------------------------------------------------
  138. // 两种方法的最后表达式为:
  139. // x >= rc.Height() - rcWidth()*(height/width);
  140. // 即 x >= rc.Height() - rcWidth()/fscale;
  141. //------------------------------------------------
  142. dt = (rcwid - rchei*fscale) / 2;
  143. rc.left += dt;
  144. rc.right -= dt;
  145. }
  146. else
  147. {
  148. dt = (rchei - rcwid / fscale) / 2;
  149. rc.top += dt;
  150. rc.bottom -= dt;
  151. }
  152. }
  153. catch (...)
  154. {
  155. }
  156. }
  157. //-----------------------------------------------------------------------------------------------------------------------
  158. //
  159. // 函数:SaveImageToFile
  160. // 描述:压缩指定目录的相片到指定目录;
  161. // 参数:
  162. // img : Image对象;
  163. // path : 压缩后相片保存路径;
  164. // quality : 压缩的质量值;
  165. //
  166. // 返回:#;
  167. //
  168. // 注意:;
  169. //
  170. //-----------------------------------------------------------------------------------------------------------------------
  171. void ImageCompress::SaveImageToFile(IN Image *img, IN CString &path, IN ULONG quality)
  172. {
  173. try
  174. {
  175. if (img == NULL)return;
  176. CLSID encoderClsid;
  177. BSTR bstr = path.AllocSysString();
  178. path.MakeLower();
  179. if (path.Right(3) == _T("bmp"))
  180. {
  181. GetEncoderClsid(L"image/bmp", &encoderClsid);
  182. img->Save(bstr, &encoderClsid, NULL);
  183. }
  184. else if (path.Right(3) == _T("png"))
  185. {
  186. GetEncoderClsid(L"image/png", &encoderClsid);
  187. img->Save(bstr, &encoderClsid, NULL);
  188. }
  189. else// if(path.Right (3)== _T("jpg"))
  190. {
  191. GetEncoderClsid(L"image/jpeg", &encoderClsid);
  192. EncoderParameters encoderParameters;
  193. encoderParameters.Count = 1;
  194. encoderParameters.Parameter[0].Guid = EncoderQuality;
  195. encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
  196. encoderParameters.Parameter[0].NumberOfValues = 1;
  197. // Save the image as a JPEG with quality level 100.
  198. encoderParameters.Parameter[0].Value = &quality;
  199. img->Save(bstr, &encoderClsid, &encoderParameters);
  200. }
  201. SysFreeString(bstr);
  202. }
  203. catch (...)
  204. {
  205. }
  206. }
  207. //-----------------------------------------------------------------------------------------------------------------------
  208. //
  209. // 函数:ToCompressImage
  210. // 描述:压缩指定目录的相片到指定目录;
  211. // 参数:
  212. // pImageSource : 原相片完整路径;
  213. // pImageDest : 压缩后相片保存路径;
  214. // nXPiexel : 压缩的像素宽;
  215. // nYPiexel : 压缩的像素高;
  216. //
  217. // 返回:#;
  218. //
  219. // 注意:;
  220. //
  221. //-----------------------------------------------------------------------------------------------------------------------
  222. BOOL ImageCompress::ToCompressImage(IN const TCHAR *pImageSource, IN const TCHAR *pImageDest, IN const int &nXPiexel, IN const int &nYPiexel)
  223. {
  224. Image *pImage = NULL;
  225. ::DeleteFile(pImageDest);
  226. // 1.从文件中以读的方式加载图片到Image中;
  227. CFile cf;
  228. if (cf.Open(pImageSource, CFile::modeRead))
  229. {
  230. DWORD dwLength = cf.GetLength();
  231. BYTE *pData = new BYTE[dwLength];
  232. if (pData == NULL)// 创建内存失败;
  233. return FALSE;
  234. cf.Read(pData, dwLength);
  235. cf.Close();
  236. // 1.1.将文件数据加载到内存数据中;
  237. HGLOBAL taghMem = GlobalAlloc(GMEM_MOVEABLE, dwLength);
  238. if (taghMem == NULL) // 创建内存失败;
  239. return FALSE;
  240. BYTE *pMem = (BYTE*)GlobalLock(taghMem);
  241. memcpy(pMem, pData, dwLength);
  242. // 1.2.创建二进制流对象;
  243. IStream *pStream;
  244. CreateStreamOnHGlobal(taghMem, TRUE, &pStream);
  245. pImage = Gdiplus::Image::FromStream(pStream);
  246. GlobalUnlock(taghMem);
  247. pStream->Release();
  248. delete[]pData;
  249. }
  250. // 2.加载后……
  251. if (pImage == NULL) // 加载失败;
  252. return FALSE;
  253. // 2.1.当图片的像素大于要设定的像素时,进行处理;
  254. if (pImage->GetWidth() > nXPiexel || pImage->GetHeight() > nYPiexel)
  255. {
  256. CRect tagRect(0, 0, nXPiexel, nYPiexel);
  257. ScaleZoombySpecificWidth(pImage->GetWidth(), pImage->GetHeight(), tagRect);
  258. Bitmap bp(tagRect.Width(), tagRect.Height());
  259. Graphics *graphic = Graphics::FromImage(&bp);
  260. graphic->Clear(Color(255, 255, 255, 255));
  261. graphic->SetInterpolationMode(InterpolationModeHighQualityBicubic);
  262. graphic->SetSmoothingMode(SmoothingModeHighQuality);//SmoothingModeHighSpeed
  263. graphic->SetPixelOffsetMode(PixelOffsetModeHighQuality);
  264. graphic->SetCompositingMode(CompositingModeSourceOver);
  265. graphic->SetCompositingQuality(CompositingQualityHighQuality);
  266. graphic->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
  267. graphic->DrawImage(pImage, RectF(0, 0, tagRect.Width(), tagRect.Height()), 0, 0, pImage->GetWidth(), pImage->GetHeight(), UnitPixel);
  268. delete pImage;
  269. try
  270. {
  271. CString path(pImageDest);
  272. CLSID encoderClsid;
  273. BSTR bstr = path.AllocSysString();
  274. path.MakeLower();
  275. if (path.Right(3) == _T("bmp"))
  276. {
  277. GetEncoderClsid(L"image/bmp", &encoderClsid);
  278. bp.Save(bstr, &encoderClsid, NULL);
  279. }
  280. else if (path.Right(3) == _T("png"))
  281. {
  282. GetEncoderClsid(L"image/png", &encoderClsid);
  283. bp.Save(bstr, &encoderClsid, NULL);
  284. }
  285. else// if(path.Right (3)=="jpg")
  286. {
  287. ULONG quality = 95;
  288. GetEncoderClsid(L"image/jpeg", &encoderClsid);
  289. EncoderParameters encoderParameters;
  290. encoderParameters.Count = 1;
  291. encoderParameters.Parameter[0].Guid = EncoderQuality;
  292. encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
  293. encoderParameters.Parameter[0].NumberOfValues = 1;
  294. // Save the image as a JPEG with quality level 100.
  295. encoderParameters.Parameter[0].Value = &quality;
  296. bp.Save(bstr, &encoderClsid, &encoderParameters);
  297. }
  298. SysFreeString(bstr);
  299. }
  300. catch (...)
  301. {
  302. return FALSE;
  303. }
  304. }
  305. return TRUE;
  306. }