PageRenderTime 34ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/BotE Game/branch/Alpha7/Source/include/ImageStone/include/imagefile/imagehandle_gdiplus.h

#
C++ Header | 360 lines | 286 code | 29 blank | 45 comment | 71 complexity | 08b78ed457a09d8424ba09665aa65917 MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.0
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2004-6-18
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybitwps@hotmail.com
  8. * History :
  9. */
  10. #ifndef __FOO_IMAGE_HANDLE_GDIPLUS__2004_06_18__H__
  11. #define __FOO_IMAGE_HANDLE_GDIPLUS__2004_06_18__H__
  12. #include "../FWin32.h"
  13. //class FCImageHandle ;
  14. class FCImageHandle_Gdiplus ;
  15. //=============================================================================
  16. /**
  17. * Auto load GDI+ module.
  18. * load GDI+ module at constructor and unload at destructor.
  19. */
  20. class FCAutoInitGDIPlus
  21. {
  22. ULONG_PTR m_GdiplusToken ;
  23. public:
  24. /// Constructor (load GDI+ module).
  25. FCAutoInitGDIPlus()
  26. {
  27. Gdiplus::GdiplusStartupInput gpSI ;
  28. Gdiplus::GdiplusStartup (&m_GdiplusToken, &gpSI, NULL) ;
  29. }
  30. /// Destructor (unload GDI+ module).
  31. virtual ~FCAutoInitGDIPlus()
  32. {
  33. Gdiplus::GdiplusShutdown (m_GdiplusToken) ;
  34. }
  35. /// Get bmp/jpeg/gif/tiff/png image's CLSID.
  36. static bool GetImageEncoderClsid (IMAGE_TYPE imgType, CLSID* pClsid)
  37. {
  38. bstr_t strType ;
  39. switch (imgType)
  40. {
  41. case IMG_BMP : strType = "image/bmp" ; break;
  42. case IMG_JPG : strType = "image/jpeg" ; break;
  43. case IMG_GIF : strType = "image/gif" ; break;
  44. case IMG_TIF : strType = "image/tiff" ; break;
  45. case IMG_PNG : strType = "image/png" ; break;
  46. default : return false ;
  47. }
  48. UINT nNum=0, nSize=0 ;
  49. Gdiplus::GetImageEncodersSize (&nNum, &nSize) ;
  50. if (nSize <= 0)
  51. return false ;
  52. PCL_array<Gdiplus::ImageCodecInfo> pICI (new BYTE[nSize]) ;
  53. Gdiplus::GetImageEncoders (nNum, nSize, pICI.get()) ;
  54. for (UINT i=0 ; i < nNum; i++)
  55. {
  56. if (bstr_t(pICI[i].MimeType) == strType)
  57. {
  58. *pClsid = pICI[i].Clsid ;
  59. return true ;
  60. }
  61. }
  62. return false ;
  63. }
  64. };
  65. //=============================================================================
  66. /**
  67. * Read/Write image via Gdi+.
  68. * if you load a gif image with transparent color, you will get a 32bpp image object, transparent color be converted to alpha=0 pixel
  69. */
  70. class FCImageHandle_Gdiplus : public FCImageHandleBase,
  71. public FCAutoInitGDIPlus
  72. {
  73. // create image property object base on Bitmap, must delete returned object
  74. static FCImageProperty* CreatePropertyFromBitmap (Gdiplus::Bitmap& gp_Bmp)
  75. {
  76. // get all property
  77. UINT nBytes, nNum ;
  78. gp_Bmp.GetPropertySize (&nBytes, &nNum) ;
  79. PCL_array<Gdiplus::PropertyItem> gp_Item (new BYTE[nBytes]) ;
  80. gp_Bmp.GetAllPropertyItems (nBytes, nNum, gp_Item.get()) ;
  81. // fill tag
  82. FCImageProperty * pProp = new FCImageProperty ;
  83. for (UINT i=0 ; i < nNum ; i++)
  84. {
  85. Gdiplus::PropertyItem & rItem = gp_Item[i] ;
  86. FIMAGE_TAG nTag = (FIMAGE_TAG)rItem.id ;
  87. // convert all type to string
  88. if (rItem.type == PropertyTagTypeASCII)
  89. {
  90. std::string s ((char*)rItem.value, rItem.length) ;
  91. pProp->SetPropertyValue (nTag, s.c_str()) ;
  92. }
  93. else if (rItem.type == PropertyTagTypeRational)
  94. {
  95. if (rItem.length == 8)
  96. {
  97. std::string s = FCOXOHelper::X2A (*(unsigned long*)rItem.value) ;
  98. s += "/" ;
  99. s += FCOXOHelper::X2A (((unsigned long*)rItem.value)[1]) ;
  100. pProp->SetPropertyValue (nTag, s.c_str()) ;
  101. }
  102. }
  103. else if (rItem.type == PropertyTagTypeSRational)
  104. {
  105. if (rItem.length == 8)
  106. {
  107. std::string s = FCOXOHelper::X2A (*(long*)rItem.value) ;
  108. s += "/" ;
  109. s += FCOXOHelper::X2A (((long*)rItem.value)[1]) ;
  110. pProp->SetPropertyValue (nTag, s.c_str()) ;
  111. }
  112. }
  113. else if (rItem.type == PropertyTagTypeShort)
  114. {
  115. if (rItem.length == 2)
  116. {
  117. std::string s = FCOXOHelper::X2A (*(unsigned short*)rItem.value) ;
  118. pProp->SetPropertyValue (nTag, s.c_str()) ;
  119. }
  120. }
  121. else if (rItem.type == PropertyTagTypeLong)
  122. {
  123. if (rItem.id == PropertyTagFrameDelay)
  124. {
  125. assert (rItem.length % 4 == 0) ;
  126. for (ULONG i=0 ; i < rItem.length/4 ; i++)
  127. {
  128. unsigned long lv = ((unsigned long*)rItem.value)[i] ;
  129. pProp->PutFrameDelay ((int)lv * 10) ;
  130. }
  131. }
  132. else
  133. {
  134. if (rItem.length == 4)
  135. {
  136. std::string s = FCOXOHelper::X2A (*(unsigned long*)rItem.value) ;
  137. pProp->SetPropertyValue (nTag, s.c_str()) ;
  138. }
  139. }
  140. }
  141. }
  142. return pProp ;
  143. }
  144. // property tag <==> type
  145. static void GetGdiplusPropertyTypeTab (PCL_TT_Convertor<PROPID, WORD>& aTab)
  146. {
  147. aTab.Clear() ;
  148. aTab.AddElement (PropertyTagEquipMake, PropertyTagTypeASCII) ;
  149. aTab.AddElement (PropertyTagEquipModel, PropertyTagTypeASCII) ;
  150. aTab.AddElement (PropertyTagExifDTOrig, PropertyTagTypeASCII) ;
  151. aTab.AddElement (PropertyTagExifExposureTime, PropertyTagTypeRational) ;
  152. aTab.AddElement (PropertyTagExifFNumber, PropertyTagTypeRational) ;
  153. aTab.AddElement (PropertyTagExifFocalLength, PropertyTagTypeRational) ;
  154. aTab.AddElement (PropertyTagExifISOSpeed, PropertyTagTypeShort) ;
  155. aTab.AddElement (PropertyTagExifExposureBias, PropertyTagTypeSRational) ;
  156. aTab.AddElement (PropertyTagExifMaxAperture, PropertyTagTypeRational) ;
  157. aTab.AddElement (PropertyTagExifFlash, PropertyTagTypeShort) ;
  158. aTab.AddElement (PropertyTagExifMeteringMode, PropertyTagTypeShort) ;
  159. aTab.AddElement (PropertyTagExifExposureProg, PropertyTagTypeShort) ;
  160. }
  161. // Add property into bitmap object.
  162. static void AddPropertyInBitmap (const FCImageProperty& rImageProp, Gdiplus::Bitmap& gpBmp)
  163. {
  164. PCL_TT_Convertor<PROPID, WORD> tabType ;
  165. GetGdiplusPropertyTypeTab (tabType) ;
  166. // put image's property
  167. for (int i=0 ; i < rImageProp.GetElementCount() ; i++)
  168. {
  169. Gdiplus::PropertyItem aItem ;
  170. aItem.id = rImageProp.GetT1(i) ;
  171. aItem.type = tabType.First_to_Second (aItem.id, PropertyTagTypeUndefined) ;
  172. if (aItem.type == PropertyTagTypeUndefined)
  173. continue ;
  174. const std::string & s = rImageProp.GetT2(i) ;
  175. if (aItem.type == PropertyTagTypeASCII)
  176. {
  177. PCL_array<char> pBuf (s.length() + 1) ;
  178. ZeroMemory (pBuf.get(), s.length() + 1) ;
  179. CopyMemory (pBuf.get(), s.c_str(), s.length()) ;
  180. aItem.length = s.length() + 1 ;
  181. aItem.value = pBuf.get() ;
  182. gpBmp.SetPropertyItem (&aItem) ;
  183. }
  184. else if (aItem.type == PropertyTagTypeRational)
  185. {
  186. size_t nPos = s.find ("/") ;
  187. if (nPos != std::string::npos)
  188. {
  189. unsigned long p[2] ;
  190. FCOXOHelper::A2X (s.substr(0,nPos), p[0]) ;
  191. FCOXOHelper::A2X (s.substr(nPos+1), p[1]) ;
  192. aItem.length = 8 ;
  193. aItem.value = p ;
  194. gpBmp.SetPropertyItem (&aItem) ;
  195. }
  196. }
  197. else if (aItem.type == PropertyTagTypeSRational)
  198. {
  199. size_t nPos = s.find ("/") ;
  200. if (nPos != std::string::npos)
  201. {
  202. long p[2] ;
  203. FCOXOHelper::A2X (s.substr(0,nPos), p[0]) ;
  204. FCOXOHelper::A2X (s.substr(nPos+1), p[1]) ;
  205. aItem.length = 8 ;
  206. aItem.value = p ;
  207. gpBmp.SetPropertyItem (&aItem) ;
  208. }
  209. }
  210. else if (aItem.type == PropertyTagTypeShort)
  211. {
  212. unsigned short n ;
  213. FCOXOHelper::A2X (s, n) ;
  214. aItem.length = 2 ;
  215. aItem.value = &n ;
  216. gpBmp.SetPropertyItem (&aItem) ;
  217. }
  218. else if (aItem.type == PropertyTagTypeLong)
  219. {
  220. unsigned long n ;
  221. FCOXOHelper::A2X (s, n) ;
  222. aItem.length = 4 ;
  223. aItem.value = &n ;
  224. gpBmp.SetPropertyItem (&aItem) ;
  225. }
  226. }
  227. }
  228. // Load image file via GDIPlus.
  229. virtual bool LoadImageFile (const char* szFileName,
  230. PCL_Interface_Composite<FCObjImage>& rImageList,
  231. std::auto_ptr<FCImageProperty>& rImageProp)
  232. {
  233. // load image file
  234. Gdiplus::Bitmap gpBmp (bstr_t(szFileName), FALSE) ;
  235. return StoreMultiFrame (gpBmp, rImageList, rImageProp) ;
  236. }
  237. // Load image memory via GDIPlus.
  238. virtual bool LoadImageMemory (const BYTE* pStart, int nMemSize,
  239. PCL_Interface_Composite<FCObjImage>& rImageList,
  240. std::auto_ptr<FCImageProperty>& rImageProp)
  241. {
  242. if (!pStart || (nMemSize <= 0))
  243. return false ;
  244. // copy to HGLOBAL then load
  245. HGLOBAL hBuffer = ::GlobalAlloc (GMEM_MOVEABLE, nMemSize) ;
  246. ::CopyMemory (::GlobalLock(hBuffer), pStart, nMemSize) ;
  247. ::GlobalUnlock (hBuffer) ;
  248. bool bRet = false ;
  249. IStream * pStream = NULL ;
  250. if (::CreateStreamOnHGlobal (hBuffer, TRUE, &pStream) == S_OK)
  251. {
  252. Gdiplus::Bitmap gpBmp (pStream, FALSE) ;
  253. bRet = StoreMultiFrame (gpBmp, rImageList, rImageProp) ;
  254. }
  255. if (pStream)
  256. pStream->Release() ;
  257. return bRet ;
  258. }
  259. // Get all frames in gp_Bmp, add into rImageList.
  260. static bool StoreMultiFrame (Gdiplus::Bitmap& gp_Bmp,
  261. PCL_Interface_Composite<FCObjImage>& rImageList,
  262. std::auto_ptr<FCImageProperty>& rImageProp)
  263. {
  264. if (gp_Bmp.GetLastStatus() != Gdiplus::Ok)
  265. {
  266. /*assert(false);*/ return false;
  267. }
  268. // get frame dimensions
  269. const UINT nDim = gp_Bmp.GetFrameDimensionsCount() ;
  270. PCL_array<GUID> listID (nDim) ;
  271. gp_Bmp.GetFrameDimensionsList (listID.get(), nDim) ;
  272. // get frame and store
  273. for (UINT i=0 ; i < nDim ; i++)
  274. {
  275. UINT nFrame = gp_Bmp.GetFrameCount (&listID[i]) ;
  276. for (UINT j=0 ; j < nFrame ; j++)
  277. {
  278. gp_Bmp.SelectActiveFrame (&listID[i], j) ;
  279. FCObjImage * pImg = new FCObjImage ;
  280. FCWin32::GDIPlus_LoadBitmap (gp_Bmp, *pImg) ;
  281. if (pImg->IsValidImage())
  282. {
  283. rImageList.PCL_PushObject(pImg) ;
  284. }
  285. else
  286. {
  287. delete pImg ; assert(false);
  288. }
  289. }
  290. }
  291. // store image property
  292. rImageProp = std::auto_ptr<FCImageProperty>(CreatePropertyFromBitmap(gp_Bmp)) ;
  293. return (rImageList.PCL_GetObjectCount() != 0) ;
  294. }
  295. // Save image to file via GDI+.
  296. virtual bool SaveImageFile (const char* szFileName,
  297. const std::deque<const FCObjImage*>& rImageList,
  298. const FCImageProperty& rImageProp)
  299. {
  300. if (rImageList.empty() || !rImageList[0]->IsValidImage())
  301. return false ;
  302. const FCObjImage &img = *rImageList[0] ;
  303. // get encoder's CLSID
  304. CLSID clsID ;
  305. IMAGE_TYPE imgType = FCObjImage::GetImageHandleFactory()->QueryImageFileType(szFileName) ;
  306. if (!GetImageEncoderClsid (imgType, &clsID))
  307. return false ;
  308. // if image is jpeg format, set save quality
  309. std::auto_ptr<Gdiplus::EncoderParameters> pEnParas ;
  310. ULONG nQuality = JpegSaveQuality(rImageProp) ;
  311. if (imgType == IMG_JPG)
  312. {
  313. pEnParas = std::auto_ptr<Gdiplus::EncoderParameters>(new Gdiplus::EncoderParameters) ;
  314. pEnParas->Count = 1 ;
  315. pEnParas->Parameter[0].Guid = Gdiplus::EncoderQuality ;
  316. pEnParas->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong ;
  317. pEnParas->Parameter[0].NumberOfValues = 1 ;
  318. pEnParas->Parameter[0].Value = &nQuality ;
  319. }
  320. // create a GDI+ bitmap and put property
  321. std::auto_ptr<Gdiplus::Bitmap> pBmp (FCWin32::GDIPlus_CreateBitmap(img)) ;
  322. if (!pBmp.get())
  323. return false ;
  324. AddPropertyInBitmap (rImageProp, *pBmp) ;
  325. return (pBmp->Save (bstr_t(szFileName), &clsID, pEnParas.get()) == Gdiplus::Ok) ;
  326. }
  327. };
  328. //=============================================================================
  329. // inline Implement
  330. //=============================================================================
  331. #endif