Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
18 KiB

  1. //
  2. // saveimag.cpp
  3. //
  4. // implementation of saving a file to disk via an installed graphic filter
  5. //
  6. #include "stdafx.h"
  7. #include "pbrush.h"
  8. #include "pbrusdoc.h"
  9. #include "bmobject.h"
  10. #include "imgwnd.h"
  11. #include "imgsuprt.h"
  12. #include "loadimag.h"
  13. #include "saveimag.h"
  14. #include "bmpstrm.h"
  15. #include "imaging.h"
  16. #include <atlbase.h>
  17. #ifdef _X86_
  18. #define _USE_IFL_API
  19. #endif
  20. extern BOOL GetHandlerForFile(BOOL bImport,LPCSTR szFile,
  21. LPSTR szHandler,
  22. UINT cb); // defined in loadimag.cpp
  23. inline RGBTRIPLE GetPalEntry(LPVOID lpPal3, BYTE index)
  24. {
  25. RGBTRIPLE rgb;
  26. rgb.rgbtRed = ((RGBTRIPLE *)lpPal3 + index)->rgbtRed;
  27. rgb.rgbtGreen = ((RGBTRIPLE *)lpPal3 + index)->rgbtGreen;
  28. rgb.rgbtBlue = ((RGBTRIPLE *)lpPal3 + index)->rgbtBlue;
  29. return rgb;
  30. }
  31. inline void ConvertPalette(int bitCount, LPBYTE lpBuf, int width)
  32. {
  33. int j;
  34. switch (bitCount)
  35. {
  36. case 4:
  37. for (j=0; j<width; j++)
  38. {
  39. *(lpBuf+(width-1-j)*2+1) = (*(lpBuf+width-1-j) & 0x0f);
  40. *(lpBuf+(width-1-j)*2) = (*(lpBuf+width-1-j) & 0xf0) >> 4;
  41. }
  42. break;
  43. case 1:
  44. for (j=0; j<width; j++)
  45. {
  46. *(lpBuf+(width-1-j)*8+7) = (*(lpBuf+width-1-j) & 0x1);
  47. *(lpBuf+(width-1-j)*8+6) = (*(lpBuf+width-1-j) & 0x2) >> 1;
  48. *(lpBuf+(width-1-j)*8+5) = (*(lpBuf+width-1-j) & 0x4) >> 2;
  49. *(lpBuf+(width-1-j)*8+4) = (*(lpBuf+width-1-j) & 0x8) >> 3;
  50. *(lpBuf+(width-1-j)*8+3) = (*(lpBuf+width-1-j) & 0x10) >> 4;
  51. *(lpBuf+(width-1-j)*8+2) = (*(lpBuf+width-1-j) & 0x20) >> 5;
  52. *(lpBuf+(width-1-j)*8+1) = (*(lpBuf+width-1-j) & 0x40) >> 6;
  53. *(lpBuf+(width-1-j)*8) = (*(lpBuf+width-1-j) & 0x80) >> 7;
  54. }
  55. break;
  56. default:
  57. // impossible!!!
  58. break;
  59. }
  60. }
  61. inline BYTE SearchPalette(COLORREF crColor, LPVOID lpPal3)
  62. {
  63. BYTE byRed = GetRValue( crTrans );
  64. BYTE byGreen = GetGValue( crTrans );
  65. BYTE byBlue = GetBValue( crTrans );
  66. for (int i = 0; i < MAX_PALETTE_COLORS; i++)
  67. {
  68. // note that we have to switch the colors back before
  69. // attempting to compare them!!
  70. if (byRed == ((RGBTRIPLE *)lpPal3 + i)->rgbtBlue &&
  71. byGreen == ((RGBTRIPLE *)lpPal3 + i)->rgbtGreen &&
  72. byBlue == ((RGBTRIPLE *)lpPal3 + i)->rgbtRed)
  73. return (BYTE)i;
  74. }
  75. // shouldn't reach here!!
  76. // (the color being searched must be in the palette)
  77. return 0;
  78. }
  79. BOOL SaveDIBToFileA( LPCSTR szFileName,
  80. REFGUID guidFormatID,
  81. CBitmapObj* pBitmap )
  82. {
  83. IFLTYPE iflType;
  84. if (guidFormatID == WiaImgFmt_GIF)
  85. {
  86. iflType = IFLT_GIF;
  87. }
  88. else if (guidFormatID == WiaImgFmt_BMP)
  89. {
  90. iflType = IFLT_BMP;
  91. }
  92. else if (guidFormatID == WiaImgFmt_JPEG)
  93. {
  94. iflType = IFLT_JPEG;
  95. }
  96. else if (guidFormatID == WiaImgFmt_TIFF)
  97. {
  98. iflType = IFLT_TIFF;
  99. }
  100. else if (guidFormatID == WiaImgFmt_PNG)
  101. {
  102. iflType = IFLT_PNG;
  103. }
  104. else if (guidFormatID == WiaImgFmt_PHOTOCD)
  105. {
  106. iflType = IFLT_PCD;
  107. }
  108. else
  109. {
  110. return FALSE;
  111. }
  112. #ifdef _USE_IFL_API
  113. LPBITMAPINFOHEADER lpDib = (LPBITMAPINFOHEADER) GlobalLock(pBitmap->m_hThing);
  114. IFLCLASS iflClass = (lpDib->biBitCount == 24) ? IFLCL_RGB : IFLCL_PALETTE;
  115. int iBPS = 8; // bits per sample
  116. if (iflType == IFLT_JPEG)
  117. // force it to be RGB type, otherwise the JPEG filter won't take it
  118. iflClass = IFLCL_RGB;
  119. if (iflType == IFLT_GIF && iflClass == IFLCL_RGB)
  120. {
  121. GlobalUnlock(pBitmap->m_hThing);
  122. // force it to be PALETTE type, otherwise the GIF filter won't take it
  123. iflClass = IFLCL_PALETTE;
  124. // Now convert the image from RGB to palette-based. Note that
  125. // the call to DibFromBitmap() will allocate new memory!!
  126. DWORD dwSize;
  127. lpDib = (LPBITMAPINFOHEADER) DibFromBitmap(
  128. pBitmap->m_pImg->hBitmap, BI_RGB, (WORD) iBPS,
  129. pBitmap->m_pImg->m_pPalette, NULL, dwSize,
  130. pBitmap->m_pImg->cXPelsPerMeter, pBitmap->m_pImg->cYPelsPerMeter);
  131. if (lpDib == NULL)
  132. return FALSE; // memory allocation failed
  133. // now replace the original
  134. pBitmap->Free();
  135. pBitmap->m_hThing = lpDib;
  136. pBitmap->m_lMemSize = dwSize;
  137. lpDib = (LPBITMAPINFOHEADER) GlobalLock(pBitmap->m_hThing);
  138. }
  139. IFLCOMPRESSION iflCompression = IFLCOMP_DEFAULT; // or IFLCOMP_NONE ???
  140. IFLHANDLE iflHandle = iflCreateWriteHandle(lpDib->biWidth, lpDib->biHeight,
  141. iflClass, iBPS, iflCompression, iflType);
  142. if (iflHandle == NULL)
  143. {
  144. GlobalUnlock(pBitmap->m_hThing);
  145. return FALSE;
  146. }
  147. IFLERROR iflErr = iflOpen(iflHandle, (LPSTR)szFileName, IFLM_WRITE);
  148. if (iflErr != IFLERR_NONE)
  149. {
  150. iflFreeHandle(iflHandle);
  151. GlobalUnlock(pBitmap->m_hThing);
  152. return FALSE;
  153. }
  154. LPBITMAPINFOHEADER lpHdr = lpDib;
  155. DWORD dwHdrLen = lpHdr->biSize + PaletteSize((LPSTR)lpHdr);
  156. LPBYTE hp = ((LPBYTE)lpDib) + dwHdrLen;
  157. int iOutWidth = (lpDib->biBitCount == 24) ?
  158. lpDib->biWidth*3 :
  159. lpDib->biWidth*24/lpDib->biBitCount;
  160. LPBYTE lpBuf = new BYTE[iOutWidth];
  161. int i, j, k;
  162. BYTE byTemp;
  163. BOOL fFound;
  164. // convert from pixels to bytes after rounding it up first
  165. DWORD dwWidthInBytes = ((lpDib->biWidth * lpDib->biBitCount + 31) &~31) /8;
  166. if (iflClass == IFLCL_RGB)
  167. {
  168. // set the transparent color on demand and only if it's been set
  169. if (g_bUseTrans && crTrans != TRANS_COLOR_NONE) // not default
  170. {
  171. IFLCOLOR iflTransColor;
  172. iflTransColor.wRed = GetRValue( crTrans );
  173. iflTransColor.wGreen = GetGValue( crTrans );
  174. iflTransColor.wBlue = GetBValue( crTrans );
  175. // ignore any error return (if a format doesn't support
  176. // transparent color, so be it)
  177. iflControl(iflHandle, IFLCMD_TRANS_RGB, 0, 0, &iflTransColor);
  178. }
  179. if (lpDib->biBitCount == 24)
  180. {
  181. // we already have a RGB image, so just copy it out
  182. LPBYTE lpBMP = hp + lpDib->biSizeImage - dwWidthInBytes;
  183. for (i = 0;
  184. i < abs(lpDib->biHeight);
  185. lpBMP-=dwWidthInBytes, i++)
  186. {
  187. memcpy(lpBuf, lpBMP, iOutWidth);
  188. // need to swap RED with BLUE for export
  189. for (j = 0; j < iOutWidth; j+=3)
  190. {
  191. byTemp = *(lpBuf+j);
  192. *(lpBuf+j) = *(lpBuf+j+2);
  193. *(lpBuf+j+2) = byTemp;
  194. }
  195. // write out one line at a time
  196. iflWrite(iflHandle, lpBuf, 1);
  197. }
  198. }
  199. else
  200. {
  201. // need to convert from palatte color
  202. RGBTRIPLE Pal3[MAX_PALETTE_COLORS];
  203. memset(Pal3, 255, MAX_PALETTE_COLORS*sizeof(RGBTRIPLE));
  204. LPRGBQUAD lpPal4 = (LPRGBQUAD)((LPBYTE)lpDib + lpDib->biSize);
  205. for (i = 0; i < MAX_PALETTE_COLORS; i++)
  206. {
  207. Pal3[i].rgbtRed = (lpPal4+i)->rgbBlue;
  208. Pal3[i].rgbtGreen = (lpPal4+i)->rgbGreen;
  209. Pal3[i].rgbtBlue = (lpPal4+i)->rgbRed;
  210. }
  211. LPBYTE lpBMP = hp + lpDib->biSizeImage - dwWidthInBytes;
  212. for (i = 0;
  213. i < abs(lpDib->biHeight);
  214. lpBMP-=dwWidthInBytes, i++)
  215. {
  216. memcpy(lpBuf, lpBMP, lpDib->biWidth);
  217. if (lpDib->biBitCount != 8)
  218. ConvertPalette(lpDib->biBitCount, lpBuf, lpDib->biWidth);
  219. for (j = 0; j < lpDib->biWidth; j++)
  220. {
  221. ((RGBTRIPLE *)(lpBuf+(lpDib->biWidth-j-1)*3))->rgbtRed =
  222. GetPalEntry(&Pal3, *(lpBuf+lpDib->biWidth-j-1)).rgbtRed;
  223. ((RGBTRIPLE *)(lpBuf+(lpDib->biWidth-j-1)*3))->rgbtGreen =
  224. GetPalEntry(&Pal3, *(lpBuf+lpDib->biWidth-j-1)).rgbtGreen;
  225. ((RGBTRIPLE *)(lpBuf+(lpDib->biWidth-j-1)*3))->rgbtBlue =
  226. GetPalEntry(&Pal3, *(lpBuf+lpDib->biWidth-j-1)).rgbtBlue;
  227. }
  228. // write out one line at a time
  229. iflWrite(iflHandle, lpBuf, 1);
  230. }
  231. }
  232. }
  233. else if (iflClass == IFLCL_PALETTE)
  234. {
  235. // first, get the color palette straight...
  236. RGBTRIPLE Pal3[MAX_PALETTE_COLORS];
  237. memset(Pal3, 255, MAX_PALETTE_COLORS*sizeof(RGBTRIPLE));
  238. if (PaletteSize((LPSTR)lpDib) != 0)
  239. {
  240. // we have one available, so just copy it out...
  241. // but not before we swap the RGB values first
  242. LPRGBQUAD lpPal4 = (LPRGBQUAD)((LPBYTE)lpDib + lpDib->biSize);
  243. for (i = 0; i < MAX_PALETTE_COLORS; i++)
  244. {
  245. Pal3[i].rgbtRed = (lpPal4+i)->rgbBlue;
  246. Pal3[i].rgbtGreen = (lpPal4+i)->rgbGreen;
  247. Pal3[i].rgbtBlue = (lpPal4+i)->rgbRed;
  248. }
  249. iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &Pal3);
  250. if (g_bUseTrans)
  251. {
  252. BYTE byTransIdx = SearchPalette(crTrans, &Pal3);
  253. iflControl(iflHandle, IFLCMD_TRANS_IDX, 0, 0, &byTransIdx);
  254. }
  255. LPBYTE lpBMP = hp + lpDib->biSizeImage - dwWidthInBytes;
  256. for (i = 0;
  257. i < abs(lpDib->biHeight);
  258. lpBMP-=dwWidthInBytes, i++)
  259. {
  260. memcpy(lpBuf, lpBMP, lpDib->biWidth);
  261. if (lpDib->biBitCount != 8)
  262. ConvertPalette(lpDib->biBitCount, lpBuf, lpDib->biWidth);
  263. // write out one line at a time
  264. iflWrite(iflHandle, lpBuf, 1);
  265. }
  266. }
  267. else
  268. {
  269. // we have to create our own palette...
  270. for (i = 0, k = 0; i < (int)lpDib->biSizeImage; i+=3)
  271. {
  272. fFound = FALSE;
  273. for (j = 0; j < MAX_PALETTE_COLORS; j++)
  274. if (Pal3[j].rgbtRed == ((RGBTRIPLE *)(hp+i))->rgbtRed &&
  275. Pal3[j].rgbtGreen == ((RGBTRIPLE *)(hp+i))->rgbtGreen &&
  276. Pal3[j].rgbtBlue == ((RGBTRIPLE *)(hp+i))->rgbtBlue)
  277. {
  278. fFound = TRUE;
  279. break;
  280. }
  281. if (!fFound && k < MAX_PALETTE_COLORS)
  282. {
  283. Pal3[k].rgbtRed = ((RGBTRIPLE *)(hp+i))->rgbtRed;
  284. Pal3[k].rgbtGreen = ((RGBTRIPLE *)(hp+i))->rgbtGreen;
  285. Pal3[k].rgbtBlue = ((RGBTRIPLE *)(hp+i))->rgbtBlue;
  286. k++;
  287. }
  288. if (k >= MAX_PALETTE_COLORS)
  289. // we have already filled every palette entry
  290. break;
  291. }
  292. iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &Pal3);
  293. LPBYTE lpBMP = hp + lpDib->biSizeImage - dwWidthInBytes;
  294. for (i = 0;
  295. i < abs(lpDib->biHeight);
  296. lpBMP-=dwWidthInBytes, i++)
  297. {
  298. memcpy(lpBuf, lpBMP, lpDib->biWidth);
  299. for (j = 0; j < lpDib->biWidth; j+=3)
  300. {
  301. fFound = FALSE;
  302. for (k = 0; k < MAX_PALETTE_COLORS; k++)
  303. {
  304. if (*(lpBuf+j) == Pal3[k].rgbtRed &&
  305. *(lpBuf+j+1) == Pal3[k].rgbtGreen &&
  306. *(lpBuf+j+2) == Pal3[k].rgbtBlue)
  307. {
  308. fFound = TRUE;
  309. *(lpBuf+j/3) = (BYTE) k;
  310. break;
  311. }
  312. }
  313. // if (!fFound)
  314. // *(lpBuf+j/3) = 255;
  315. }
  316. // write out one line at a time
  317. iflWrite(iflHandle, lpBuf, 1);
  318. }
  319. }
  320. }
  321. else
  322. ; // currently not supported
  323. delete [] lpBuf;
  324. iflClose(iflHandle);
  325. iflFreeHandle(iflHandle);
  326. GlobalUnlock(pBitmap->m_hThing);
  327. // now update the image by loading the file just exported
  328. USES_CONVERSION;
  329. HGLOBAL hNewDib = LoadDIBFromFile(A2CT(szFileName), &theApp.m_guidFltTypeUsed);
  330. pBitmap->ReadResource(hNewDib);
  331. theApp.m_sCurFile = szFileName;
  332. return TRUE;
  333. #endif // _USE_IFL_API
  334. return FALSE;
  335. }
  336. BOOL SaveDIBGdiplus(LPCTSTR szFileName, REFGUID guidFormatID, CBitmapObj* pBitmap)
  337. {
  338. // find a suitable export filter
  339. CLSID ClsidEncoder;
  340. if (GetClsidOfEncoder(guidFormatID, &ClsidEncoder))
  341. {
  342. // create a stream that emulates a bmp file
  343. CComPtr<CBmpStream> pStream;
  344. if (CBmpStream::Create(&pStream) == S_OK)
  345. {
  346. pStream->SetBuffer(pBitmap->m_hThing, pBitmap->m_lMemSize, pBitmap->m_dwOffBits);
  347. // create the GDI+ object
  348. Gdiplus::Bitmap image(pStream);
  349. if (image.GetLastStatus() == Gdiplus::Ok)
  350. {
  351. // let GDI+ export the file
  352. USES_CONVERSION;
  353. if (image.Save(T2CW(szFileName), &ClsidEncoder, 0) == Gdiplus::Ok)
  354. {
  355. // now update the image by loading the file just exported
  356. HGLOBAL hNewDib = LoadDIBFromFile(szFileName, &theApp.m_guidFltTypeUsed);
  357. pBitmap->ReadResource(hNewDib);
  358. theApp.m_sCurFile = szFileName;
  359. return TRUE;
  360. }
  361. }
  362. }
  363. }
  364. return FALSE;
  365. }
  366. BOOL SaveDIBToFile(LPCTSTR szFileName, REFGUID guidFormatID, CBitmapObj* pBitmap)
  367. {
  368. // Try GDI+ filters first. If it fails to convert the image or
  369. // if it's not available, try the old method
  370. BOOL bResult = FALSE;
  371. if (theApp.GdiplusInit.StartupStatus == Gdiplus::Ok)
  372. {
  373. __try
  374. {
  375. bResult = SaveDIBGdiplus(szFileName, guidFormatID, pBitmap);
  376. }
  377. __except(EXCEPTION_EXECUTE_HANDLER)
  378. {
  379. }
  380. }
  381. if (!bResult)
  382. {
  383. USES_CONVERSION;
  384. bResult = SaveDIBToFileA(T2CA(szFileName), guidFormatID, pBitmap);
  385. }
  386. return bResult;
  387. }