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.

9955 lines
277 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Implemenation of GpBitmap class
  8. *
  9. * Revision History:
  10. *
  11. * 06/28/1998 davidx
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. #include "..\imaging\api\comutils.hpp"
  17. #include "..\imaging\api\decodedimg.hpp"
  18. #include "..\imaging\api\icmdll.hpp"
  19. #include "..\imaging\api\memstream.hpp"
  20. #include "..\imaging\api\imgutils.hpp"
  21. #include "..\imaging\api\imgfactory.hpp"
  22. #include "..\render\scanoperationinternal.hpp"
  23. #include "..\render\FormatConverter.hpp"
  24. #include "CopyOnWriteBitmap.hpp"
  25. #define GDIP_TRANSPARENT_COLOR_KEY 0x000D0B0C
  26. static const CLSID InternalJpegClsID =
  27. {
  28. 0x557cf401,
  29. 0x1a04,
  30. 0x11d3,
  31. {0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e}
  32. };
  33. //!!! TO DO: need to go through all the routines to
  34. // map image error codes to gdi+ error codes
  35. GpStatus
  36. MapHRESULTToGpStatus(HRESULT hr)
  37. {
  38. GpStatus status;
  39. switch(hr)
  40. {
  41. case S_OK:
  42. status = Ok;
  43. break;
  44. case E_INVALIDARG:
  45. status = InvalidParameter;
  46. break;
  47. case E_OUTOFMEMORY:
  48. status = OutOfMemory;
  49. break;
  50. case IMGERR_OBJECTBUSY:
  51. status = ObjectBusy;
  52. break;
  53. case E_NOTIMPL:
  54. status = NotImplemented;
  55. break;
  56. case IMGERR_ABORT:
  57. status = Aborted;
  58. break;
  59. case IMGERR_CODECNOTFOUND:
  60. case IMGERR_FAILLOADCODEC:
  61. status = FileNotFound;
  62. break;
  63. case IMGERR_PROPERTYNOTFOUND:
  64. status = PropertyNotFound;
  65. break;
  66. case IMGERR_PROPERTYNOTSUPPORTED:
  67. status = PropertyNotSupported;
  68. break;
  69. default:
  70. status = Win32Error;
  71. }
  72. return status;
  73. }
  74. /**************************************************************************\
  75. *
  76. * Function Description:
  77. * ICM conversion from the embedded profile - if any - to SRGB
  78. *
  79. * Arguments:
  80. * dstBitmap - pass in pointer to destination buffer or NULL to do conversion
  81. * in place.
  82. *
  83. * Return Value:
  84. *
  85. * The image is cloned and the operations performed on the clone.
  86. * The result is returned in dst.
  87. * NULL indicates that the operation didn't happen
  88. *
  89. \**************************************************************************/
  90. GpStatus CopyOnWriteBitmap::ICMFrontEnd(
  91. CopyOnWriteBitmap **dstBitmap,
  92. DrawImageAbort callback,
  93. VOID *callbackData,
  94. GpRect *rect
  95. )
  96. {
  97. // check to see if we're doing a conversion.
  98. if(!ICMConvert || Globals::NoICM)
  99. {
  100. return Ok;
  101. }
  102. GpStatus status = Ok;
  103. UINT size;
  104. CopyOnWriteBitmap *dst = NULL;
  105. status = GetPropertyItemSize(TAG_ICC_PROFILE, &size);
  106. if(status==Ok)
  107. {
  108. PropertyItem *pi = (PropertyItem *)GpMalloc(size);
  109. if(pi)
  110. {
  111. status = GetPropertyItem(TAG_ICC_PROFILE, size, pi);
  112. }
  113. else
  114. {
  115. status = OutOfMemory;
  116. }
  117. if(status == Ok)
  118. {
  119. HRESULT hr = LoadICMDll();
  120. if(SUCCEEDED(hr))
  121. {
  122. // Get Embedded profile
  123. PROFILE p;
  124. p.dwType = PROFILE_MEMBUFFER;
  125. p.pProfileData = pi->value;
  126. p.cbDataSize = size-sizeof(PropertyItem);
  127. // destination profile for our internal space.
  128. char profilename[40] = "sRGB Color Space Profile.icm";
  129. PROFILE srgb;
  130. srgb.dwType = PROFILE_FILENAME;
  131. srgb.pProfileData = profilename;
  132. srgb.cbDataSize = 40;
  133. HPROFILE profiles[2];
  134. profiles[0] = (*pfnOpenColorProfile)(&p,
  135. PROFILE_READ,
  136. FILE_SHARE_READ,
  137. OPEN_EXISTING);
  138. profiles[1] = (*pfnOpenColorProfile)(&srgb,
  139. PROFILE_READ,
  140. FILE_SHARE_READ,
  141. OPEN_EXISTING);
  142. if ( profiles[0] && profiles[1] )
  143. {
  144. HTRANSFORM trans;
  145. DWORD intent[2] = {INTENT_PERCEPTUAL, INTENT_PERCEPTUAL};
  146. trans = (*pfnCreateMultiProfileTransform)(
  147. profiles, 2, intent, 2,
  148. BEST_MODE | USE_RELATIVE_COLORIMETRIC,
  149. 0
  150. );
  151. if(trans)
  152. {
  153. // Translate bitmap bits at bit depth.
  154. PixelFormatID pixFmt = PixelFormat32bppARGB;
  155. if (IsIndexedPixelFormat(PixelFormatInMem))
  156. {
  157. pixFmt = PixelFormatInMem;
  158. }
  159. if(dstBitmap)
  160. {
  161. *dstBitmap = Clone(rect, pixFmt);
  162. dst = *dstBitmap;
  163. }
  164. else
  165. {
  166. dst = this;
  167. if (pixFmt != PixelFormatInMem)
  168. {
  169. ConvertFormat(pixFmt, callback, callbackData);
  170. }
  171. }
  172. // Up to this point, PixelFormatInMem is preserved if
  173. // indexed palette is available, otherwise we set to
  174. // PIXFMT_32BPP_ARGB.
  175. if(dst)
  176. {
  177. ASSERT(dst->Bmp != NULL);
  178. ASSERT(dst->State == CopyOnWriteBitmap::MemBitmap);
  179. BOOL result = FALSE;
  180. if (IsIndexedPixelFormat(pixFmt))
  181. {
  182. // Translate the palette on bitmap
  183. const ColorPalette *srcPalette;
  184. srcPalette = dst->Bmp->GetCurrentPalette();
  185. if (srcPalette != NULL)
  186. {
  187. ColorPalette *dstPalette;
  188. dstPalette = CloneColorPalette(srcPalette, FALSE);
  189. if (dstPalette != NULL)
  190. {
  191. // Do ICM
  192. result = (*pfnTranslateBitmapBits)(
  193. trans,
  194. (PVOID)&(srcPalette->Entries[0]),
  195. BM_xRGBQUADS,
  196. 1,
  197. srcPalette->Count,
  198. sizeof(ARGB),
  199. (PVOID)&(dstPalette->Entries[0]),
  200. BM_xRGBQUADS,
  201. sizeof(ARGB),
  202. NULL,
  203. NULL
  204. );
  205. if (result)
  206. {
  207. // Set transformed palette into
  208. // the destination MemoryBitmap
  209. hr = dst->Bmp->SetPalette(dstPalette);
  210. if (FAILED(hr))
  211. {
  212. result = FALSE;
  213. }
  214. }
  215. else
  216. {
  217. DWORD err = GetLastError();
  218. status = Win32Error;
  219. WARNING(("TranslateBitmapBits failed %d", err));
  220. }
  221. GpFree(dstPalette);
  222. }
  223. }
  224. }// Indexed format conversion
  225. else
  226. {
  227. // Make a new Bmp structure.
  228. GpMemoryBitmap *icmBmp = new GpMemoryBitmap();
  229. if(icmBmp)
  230. {
  231. icmBmp->InitNewBitmap(
  232. dst->Bmp->Width,
  233. dst->Bmp->Height,
  234. pixFmt
  235. );
  236. // Do ICM
  237. BMFORMAT ulSrcColorMode = BM_xRGBQUADS;
  238. BMFORMAT ulDstColorMode = BM_xRGBQUADS;
  239. if ( dst->SrcImageInfo.Flags
  240. & IMGFLAG_COLORSPACE_CMYK )
  241. {
  242. // Source image is in CMYK color space
  243. ulSrcColorMode = BM_CMYKQUADS;
  244. }
  245. result = (*pfnTranslateBitmapBits)(
  246. trans,
  247. dst->Bmp->Scan0,
  248. ulSrcColorMode,
  249. dst->Bmp->Width,
  250. dst->Bmp->Height,
  251. dst->Bmp->Stride,
  252. icmBmp->Scan0,
  253. ulDstColorMode,
  254. icmBmp->Stride,
  255. NULL,
  256. NULL
  257. );
  258. if (result)
  259. {
  260. // switch in the corrected bmp.
  261. GpMemoryBitmap *tmp = dst->Bmp;
  262. dst->Bmp = icmBmp;
  263. icmBmp = tmp;
  264. }
  265. else
  266. {
  267. DWORD err = GetLastError();
  268. status = Win32Error;
  269. WARNING(("TranslateBitmapBits failed %d", err));
  270. }
  271. // delete the appropriate one - based on success or failure
  272. // of the TranslateBitmapBits
  273. delete icmBmp;
  274. // Convert from RGB to 32 ARGB
  275. // Note: ICC doesn't support alpha. If we fall into
  276. // this piece of code, we are sure we are in
  277. // 32BPP_RGB mode. So we can just set the image as
  278. // opaque.
  279. ASSERT(dst->PixelFormatInMem==PixelFormat32bppARGB);
  280. BYTE* pBits = (BYTE*)dst->Bmp->Scan0;
  281. for ( int i = 0; i < (int)dst->Bmp->Height; ++i )
  282. {
  283. BYTE* pTemp = pBits;
  284. for ( int j = 0; j < (int)dst->Bmp->Width; ++j )
  285. {
  286. pTemp[3] = 0xff;
  287. pTemp += 4;
  288. }
  289. pBits += dst->Bmp->Stride;
  290. }
  291. // If we have hacked the color format in
  292. // LoadIntomemory() to avoid the color format
  293. // conversion, then we need to restore it back
  294. // here
  295. if ( HasChangedRequiredPixelFormat == TRUE )
  296. {
  297. PixelFormatInMem = PixelFormat32bppPARGB;
  298. HasChangedRequiredPixelFormat = FALSE;
  299. }
  300. }
  301. else //if icmBmp
  302. {
  303. status = OutOfMemory;
  304. }
  305. }
  306. }
  307. else
  308. {
  309. status = Win32Error;
  310. WARNING(("Failed to clone bitmap\n"));
  311. }
  312. (*pfnDeleteColorTransform)(trans);
  313. }// if ( trans )
  314. else
  315. {
  316. status = Win32Error;
  317. WARNING(("CreateMultiProfileTransform failed"));
  318. }
  319. }// if ( profiles[0] && profiles[1] )
  320. else
  321. {
  322. status = Win32Error;
  323. WARNING(("OpenColorProfile failed"));
  324. }
  325. if(profiles[0])
  326. {
  327. (*pfnCloseColorProfile)(profiles[0]);
  328. }
  329. if(profiles[1])
  330. {
  331. (*pfnCloseColorProfile)(profiles[1]);
  332. }
  333. }
  334. else
  335. {
  336. status = Win32Error;
  337. WARNING(("Failed to load ICM dll\n"));
  338. }
  339. }
  340. else
  341. {
  342. WARNING(("Failed to get the ICC property"));
  343. }
  344. GpFree(pi);
  345. }
  346. else
  347. {
  348. // Try do gamma and chromaticity.
  349. PropertyItem *piGamma= NULL;
  350. status = GetPropertyItemSize(TAG_GAMMA, &size);
  351. if(status==Ok)
  352. {
  353. piGamma = (PropertyItem *)GpMalloc(size);
  354. status = GetPropertyItem(TAG_GAMMA, size, piGamma);
  355. }
  356. else
  357. {
  358. status = Ok;
  359. }
  360. PropertyItem *piWhitePoint= NULL;
  361. PropertyItem *piRGBPoint= NULL;
  362. status = GetPropertyItemSize(TAG_WHITE_POINT, &size);
  363. if(status==Ok)
  364. {
  365. piWhitePoint = (PropertyItem *)GpMalloc(size);
  366. status = GetPropertyItem(TAG_WHITE_POINT, size, piWhitePoint);
  367. }
  368. status = GetPropertyItemSize(TAG_PRIMAY_CHROMATICS, &size);
  369. if(status==Ok)
  370. {
  371. piRGBPoint = (PropertyItem *)GpMalloc(size);
  372. status = GetPropertyItem(TAG_PRIMAY_CHROMATICS, size,
  373. piRGBPoint);
  374. }
  375. else
  376. {
  377. status = Ok;
  378. }
  379. GpImageAttributes imageAttributes;
  380. if(piGamma)
  381. {
  382. REAL gamma;
  383. ASSERT((piGamma->type == TAG_TYPE_RATIONAL));
  384. // get 1.0/gamma from the (source) gamma chunk
  385. // formula is dstgamma/srcgamma
  386. // we have to invert the gamma to account to how it is stored
  387. // in the file format
  388. gamma = (REAL)*((long *)piGamma->value)/ *((long *)piGamma->value+1);
  389. gamma = gamma * 0.4545f; // our destination gamma is 1/2.2
  390. // don't do any work if gamma is 1.0
  391. // !!! need to work out what the best value for the tolerance is.
  392. if(REALABS(gamma-1.0f) >= REAL_EPSILON)
  393. {
  394. imageAttributes.SetGamma(
  395. ColorAdjustTypeBitmap, TRUE, gamma
  396. );
  397. }
  398. }
  399. using namespace VectorMath;
  400. if(piWhitePoint && piRGBPoint)
  401. {
  402. Matrix R;
  403. // Please refer to gdiplus\Specs\pngchrm.xls for all the formula
  404. // and calculations below
  405. LONG* llTemp = (long*)(piWhitePoint->value);
  406. REAL Rx, Ry, Gx, Gy, Bx, By, Wx, Wy;
  407. Wx = (REAL)llTemp[0] / llTemp[1];
  408. Wy = (REAL)llTemp[2] / llTemp[3];
  409. llTemp = (long*)(piRGBPoint->value);
  410. Rx = (REAL)llTemp[0] / llTemp[1];
  411. Ry = (REAL)llTemp[2] / llTemp[3];
  412. Gx = (REAL)llTemp[4] / llTemp[5];
  413. Gy = (REAL)llTemp[6] / llTemp[7];
  414. Bx = (REAL)llTemp[8] / llTemp[9];
  415. By = (REAL)llTemp[10] / llTemp[11];
  416. // White point
  417. Vector Wp(Wx, Wy, 1.0f-(Wx+Wy));
  418. // Within some obscurely small amount
  419. // !!! We need to work out what the actual tolerance should be.
  420. BOOL accelerate =
  421. (REALABS(Wx-0.3127f) < REAL_EPSILON) &&
  422. (REALABS(Wy-0.3290f) < REAL_EPSILON);
  423. Wp = Wp * (1.0f/Wy);
  424. // Transpose of the input matrix.
  425. Matrix I(
  426. Rx, Gx, Bx,
  427. Ry, Gy, By,
  428. 1.0f-(Rx+Ry), 1.0f-(Gx+Gy), 1.0f-(Bx+By)
  429. );
  430. Matrix II = I.Inverse();
  431. Vector IIW = II*Wp;
  432. Matrix DIIW(IIW); // Diagonalize vector IIW
  433. Matrix Q = I*DIIW;
  434. Matrix sRGB(
  435. 3.2406f, -1.5372f, -0.4986f,
  436. -0.9689f, 1.8758f, 0.0415f,
  437. 0.0557f, -0.2040f, 1.0570f
  438. );
  439. if(accelerate)
  440. {
  441. R = sRGB*Q;
  442. }
  443. else
  444. {
  445. Matrix B(
  446. 0.40024f, 0.70760f, -0.08081f,
  447. -0.22630f, 1.16532f, 0.04570f,
  448. 0.00000f, 0.00000f, 0.91822f
  449. );
  450. Matrix BI(
  451. 1.859936387f, -1.129381619f, 0.21989741f,
  452. 0.361191436f, 0.638812463f,-6.3706E-06f,
  453. 0.000000000f, 0.000000000f, 1.089063623f
  454. );
  455. Vector LMS = B * Wp;
  456. // Get Diag( LMS^(-1) ), cell F50 in the XLS file
  457. if ( LMS.data[0] != 0 )
  458. {
  459. LMS.data[0] = 1.0f / LMS.data[0];
  460. }
  461. if ( LMS.data[1] != 0 )
  462. {
  463. LMS.data[1] = 1.0f / LMS.data[1];
  464. }
  465. if ( LMS.data[2] != 0 )
  466. {
  467. LMS.data[2] = 1.0f / LMS.data[2];
  468. }
  469. Matrix L(LMS); // Diagonalize vector LMS
  470. Matrix T = BI * L * B;
  471. R = sRGB * T * Q;
  472. }
  473. // Make a 5x5 Color matrix for the recolor pipeline.
  474. ColorMatrix ChM = {
  475. R.data[0][0], R.data[1][0], R.data[2][0], 0, 0,
  476. R.data[0][1], R.data[1][1], R.data[2][1], 0, 0,
  477. R.data[0][2], R.data[1][2], R.data[2][2], 0, 0,
  478. 0, 0, 0, 1, 0,
  479. 0, 0, 0, 0, 1
  480. };
  481. imageAttributes.SetColorMatrix(
  482. ColorAdjustTypeBitmap, TRUE, &ChM, NULL, ColorMatrixFlagsDefault
  483. );
  484. }
  485. // If we initialized the imageAttributes to anything other than
  486. // no-op then do the recoloring.
  487. if(piGamma || (piWhitePoint && piRGBPoint))
  488. {
  489. // Note under certain conditions, the imageAttributes could still
  490. // be no-op at this point. For instance if the gamma was really
  491. // close to 1 and we had no chromaticities.
  492. // Fortunately the recolor pipeline knows how to optimize the
  493. // no-op case.
  494. // Apply the Chromaticities and Gamma if they have been set.
  495. status = Recolor(
  496. imageAttributes.recolor,
  497. dstBitmap, NULL, NULL, rect
  498. );
  499. // Recolor() will set Dirty flag on this image. Actually it is not
  500. // dirty since we just apply the color correction on the image to
  501. // display it. So we should reverse it back to not dirty.
  502. // Note: this is a real issue for digital images from some cameras
  503. // like Fuji. It always have White balance in it. If we don't do
  504. // the reverse below, we can't do lossless transform on these
  505. // images.
  506. // Note: Unfortunately this kind of "dirty flag restore" breaks this
  507. // scenario: (windows bug #583962)
  508. // Source image is a 48 BPP PNG with embedded gamma. Without
  509. // restoring the dirty flag here, if the caller asks for save(), we
  510. // will save PNG using the bits in memory. If we set it to not dirty
  511. // the save code path will let the PNG decoder talk to the encoder
  512. // which will have 48 to 32 and to 48 conversion. This is a known
  513. // GDI+ issue that this kind of conversion will produce wrong data.
  514. // In order to avoid the PNG problem, we only restore the dirty flag
  515. // here if the source is a JPEG image.
  516. if (SrcImageInfo.RawDataFormat == IMGFMT_JPEG)
  517. {
  518. SetDirtyFlag(FALSE);
  519. }
  520. }
  521. GpFree(piGamma);
  522. GpFree(piWhitePoint);
  523. GpFree(piRGBPoint);
  524. }
  525. return status;
  526. }
  527. /**************************************************************************\
  528. *
  529. * Function Description:
  530. * Performs recoloring
  531. *
  532. * Arguments:
  533. *
  534. * recolor contains the recolor object.
  535. * dstBitmap is the destination bitmap - set to NULL to recolor in place
  536. *
  537. * Return Value:
  538. *
  539. * The image is cloned and the operations performed on the clone.
  540. * The result is returned in dst.
  541. * NULL indicates that the operation didn't happen
  542. *
  543. \**************************************************************************/
  544. GpStatus
  545. CopyOnWriteBitmap::Recolor(
  546. GpRecolor *recolor,
  547. CopyOnWriteBitmap **dstBitmap,
  548. DrawImageAbort callback,
  549. VOID *callbackData,
  550. GpRect *rect
  551. )
  552. {
  553. GpStatus status = Ok;
  554. CopyOnWriteBitmap *dst = NULL;
  555. // If recolor exists, do color adjustment in a temporary bitmap.
  556. if (recolor)
  557. {
  558. PixelFormatID pixfmt;
  559. if (State >= MemBitmap)
  560. {
  561. // Bitmap has been decoded already
  562. pixfmt = PixelFormatInMem;
  563. }
  564. else
  565. {
  566. // Bitmap hasn't been decoded yet. Let's make sure we
  567. // decode it in a good format to avoid an expensive format
  568. // conversion step later.
  569. pixfmt = SrcImageInfo.PixelFormat;
  570. }
  571. // If indexed, color adjust natively; otherwise,
  572. // convert to 32bpp ARGB and then do color adjust.
  573. if (!IsIndexedPixelFormat(pixfmt))
  574. {
  575. pixfmt = PIXFMT_32BPP_ARGB;
  576. }
  577. if (dstBitmap)
  578. {
  579. *dstBitmap = Clone(rect, pixfmt);
  580. dst = *dstBitmap;
  581. }
  582. else
  583. {
  584. dst = this;
  585. ConvertFormat(pixfmt, callback, callbackData);
  586. }
  587. if (dst)
  588. {
  589. if (callback && ((*callback)(callbackData)))
  590. {
  591. status = Aborted;
  592. }
  593. if (status == Ok)
  594. {
  595. status = dst->ColorAdjust(recolor, pixfmt,
  596. callback, callbackData);
  597. }
  598. }
  599. else
  600. {
  601. status = OutOfMemory;
  602. }
  603. }
  604. return status;
  605. }// Recolor()
  606. /**************************************************************************\
  607. *
  608. * Function Description:
  609. *
  610. * ICM corrects from an embedded profile - if any - to SRGB and then
  611. * performs Recoloring.
  612. *
  613. * Arguments:
  614. *
  615. * ImageAttributes contains the recolor object and the ICM on/off flag.
  616. *
  617. * Return Value:
  618. *
  619. * The image is cloned and the operations performed on the clone.
  620. * The result is returned in dst.
  621. * NULL indicates that the operation didn't happen
  622. *
  623. \**************************************************************************/
  624. /*GpStatus CopyOnWriteBitmap::RecolorAndICM(
  625. GpImageAttributes *imageAttributes,
  626. CopyOnWriteBitmap **dstBitmap,
  627. DrawImageAbort callback,
  628. VOID *callbackData,
  629. GpRect *rect
  630. )
  631. {
  632. GpStatus status = Ok;
  633. if(imageAttributes)
  634. {
  635. *dstBitmap = NULL;
  636. if(imageAttributes->DeviceImageAttributes.ICMMode)
  637. {
  638. status = ICMFrontEnd(
  639. dstBitmap, callback, callbackData, rect
  640. );
  641. if( (status == Ok) && (imageAttributes->recolor != NULL) )
  642. {
  643. status = (*dstBitmap)->ColorAdjust(
  644. imageAttributes->recolor,
  645. callback, callbackData
  646. );
  647. }
  648. }
  649. if(*dstBitmap == NULL)
  650. {
  651. status = Recolor(
  652. imageAttributes->recolor,
  653. dstBitmap, callback, callbackData, rect
  654. );
  655. }
  656. }
  657. return status;
  658. }
  659. */
  660. /**************************************************************************\
  661. *
  662. * Function Description:
  663. *
  664. * Load an image from a file
  665. *
  666. * Arguments:
  667. *
  668. * filename - Specifies the name of the image file
  669. *
  670. * Return Value:
  671. *
  672. * Pointer to the newly loaded image object
  673. * NULL if there is an error
  674. *
  675. \**************************************************************************/
  676. GpImage*
  677. GpImage::LoadImage(
  678. const WCHAR* filename
  679. )
  680. {
  681. // Try to create a metafile.
  682. // If we do, and the metafile is valid then return it
  683. // if the metafile isn't valid then create a bitmap
  684. GpMetafile* metafile = new GpMetafile(filename);
  685. if (metafile != NULL && !metafile->IsValid())
  686. {
  687. if (metafile->IsCorrupted())
  688. {
  689. metafile->Dispose();
  690. return NULL;
  691. }
  692. // Dispose of the bad metafile and try a Bitmap
  693. metafile->Dispose();
  694. GpImage* bitmap = new GpBitmap(filename);
  695. if (bitmap != NULL && !bitmap->IsValid())
  696. {
  697. bitmap->Dispose();
  698. return NULL;
  699. }
  700. else
  701. {
  702. return bitmap;
  703. }
  704. }
  705. else
  706. {
  707. return metafile;
  708. }
  709. }
  710. /**************************************************************************\
  711. *
  712. * Function Description:
  713. *
  714. * Load an image from an input data stream
  715. *
  716. * Arguments:
  717. *
  718. * stream - Specifies the input data stream
  719. *
  720. * Return Value:
  721. *
  722. * Pointer to the newly loaded image object
  723. * NULL if there is an error
  724. *
  725. \**************************************************************************/
  726. GpImage*
  727. GpImage::LoadImage(
  728. IStream* stream
  729. )
  730. {
  731. // See if the stream is a metafile
  732. GpMetafile* metafile = new GpMetafile(stream);
  733. if (metafile != NULL)
  734. {
  735. if (metafile->IsValid())
  736. return metafile;
  737. else
  738. {
  739. BOOL isCorrupted = metafile->IsCorrupted();
  740. metafile->Dispose();
  741. if (isCorrupted)
  742. {
  743. return NULL;
  744. }
  745. }
  746. }
  747. // it's not a valid metafile -- it must be a bitmap
  748. GpBitmap* bitmap = new GpBitmap(stream);
  749. return bitmap;
  750. }
  751. /**************************************************************************\
  752. *
  753. * Function Description:
  754. *
  755. * Construct a bitmap image object from a file
  756. *
  757. * Arguments:
  758. *
  759. * filename - Specifies the name of the bitmap image file
  760. *
  761. * Return Value:
  762. *
  763. * NONE
  764. *
  765. \**************************************************************************/
  766. CopyOnWriteBitmap::CopyOnWriteBitmap(
  767. const WCHAR* filename
  768. )
  769. {
  770. InitDefaults();
  771. Filename = UnicodeStringDuplicate(filename);
  772. if ( Filename != NULL )
  773. {
  774. State = ImageRef;
  775. }
  776. if ( DereferenceStream() == Ok )
  777. {
  778. ASSERT(Img != NULL);
  779. // Get source image info
  780. if ( Img->GetImageInfo(&SrcImageInfo) == S_OK )
  781. {
  782. return;
  783. }
  784. // If we can't do a GetImageInfo(), there must be something wrong
  785. // with this image. So we should release the DecodedImage object
  786. // and set the State to Invalid
  787. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(filename)---GetImageInfo() failed"));
  788. Img->Release();
  789. Img = NULL;
  790. }
  791. GpFree(Filename);
  792. Filename = NULL;
  793. State = Invalid;
  794. }
  795. /**************************************************************************\
  796. *
  797. * Function Description:
  798. *
  799. * Construct a bitmap image object from a stream
  800. *
  801. * Arguments:
  802. *
  803. * stream - Specifies the input data stream
  804. *
  805. * Return Value:
  806. *
  807. * NONE
  808. *
  809. \**************************************************************************/
  810. CopyOnWriteBitmap::CopyOnWriteBitmap(
  811. IStream* stream
  812. )
  813. {
  814. InitDefaults();
  815. Stream = stream;
  816. Stream->AddRef();
  817. State = ExtStream;
  818. if ( DereferenceStream() == Ok )
  819. {
  820. ASSERT(Img != NULL);
  821. // Get source image info
  822. if ( Img->GetImageInfo(&SrcImageInfo) == S_OK )
  823. {
  824. return;
  825. }
  826. // If we can't do a GetImageInfo(), there must be something wrong
  827. // with this image. So we should release the DecodedImage object
  828. // and set the State to Invalid
  829. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(stream)---GetImageInfo() failed"));
  830. Img->Release();
  831. Img = NULL;
  832. }
  833. Stream->Release();
  834. Stream = NULL;
  835. State = Invalid;
  836. }
  837. /**************************************************************************\
  838. *
  839. * Function Description:
  840. *
  841. * Macro style function to save some common code in some constructors. The
  842. * main purpose of this method is to cache the image info structure
  843. *
  844. * Arguments:
  845. *
  846. * hr - Specifies the return code from previous function call
  847. *
  848. * Return Value:
  849. *
  850. * NONE
  851. *
  852. * Note:
  853. * Not an elegant method. Just for reducing code size
  854. *
  855. \**************************************************************************/
  856. inline VOID
  857. CopyOnWriteBitmap::CacheImageInfo(
  858. HRESULT hr
  859. )
  860. {
  861. if ( SUCCEEDED(hr) )
  862. {
  863. // Fill image info structure
  864. if ( Bmp->GetImageInfo(&SrcImageInfo) == S_OK )
  865. {
  866. State = MemBitmap;
  867. PixelFormatInMem = SrcImageInfo.PixelFormat;
  868. return;
  869. }
  870. // There must be some problems if the basic GetImageInfo() failed.
  871. // So we let it fall through to clean up even though the previous
  872. // function succeed
  873. // Notice: we haven't change the State yet. It is still at Invaliad
  874. }
  875. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap()----failed"));
  876. delete Bmp;
  877. Bmp = NULL;
  878. return;
  879. }// CacheImageInfo()
  880. /**************************************************************************\
  881. *
  882. * Function Description:
  883. *
  884. * INTEROP
  885. *
  886. * Derive a bitmap image from the given direct draw surface
  887. *
  888. * Arguments:
  889. *
  890. * surface - Direct draw surface
  891. *
  892. * Return Value:
  893. *
  894. * NONE
  895. *
  896. \**************************************************************************/
  897. CopyOnWriteBitmap::CopyOnWriteBitmap(
  898. IDirectDrawSurface7 * surface
  899. )
  900. {
  901. InitDefaults();
  902. Bmp = new GpMemoryBitmap();
  903. if (!Bmp)
  904. {
  905. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(IDirectDrawSurface7)----Out of memory"));
  906. return;
  907. }
  908. HRESULT hr = Bmp->InitDirectDrawBitmap(surface);
  909. CacheImageInfo(hr);
  910. }
  911. /**************************************************************************\
  912. *
  913. * Function Description:
  914. *
  915. * Create a bitmap image with the specified dimension and pixel format
  916. *
  917. * Arguments:
  918. *
  919. * width, height - Desired bitmap image dimension
  920. * format - Desired pixel format
  921. *
  922. * Return Value:
  923. *
  924. * NONE
  925. *
  926. \**************************************************************************/
  927. CopyOnWriteBitmap::CopyOnWriteBitmap(
  928. INT width,
  929. INT height,
  930. PixelFormatID format
  931. )
  932. {
  933. InitDefaults();
  934. Bmp = new GpMemoryBitmap();
  935. if (!Bmp)
  936. {
  937. WARNING(("CopyOnWriteBitmap::GpBimap(w, h, p)---Out of memory"));
  938. return;
  939. }
  940. // Initialize the bitmap, clearing it (to opaque black).
  941. HRESULT hr = Bmp->InitNewBitmap(width, height, format, TRUE);
  942. CacheImageInfo(hr);
  943. }
  944. CopyOnWriteBitmap::CopyOnWriteBitmap(
  945. INT width,
  946. INT height,
  947. PixelFormatID format,
  948. GpGraphics * graphics
  949. )
  950. {
  951. InitDefaults();
  952. Bmp = new GpMemoryBitmap();
  953. if (!Bmp)
  954. {
  955. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(w, h, f, g)----Out of memory"));
  956. return;
  957. }
  958. // Initialize the bitmap, clearing it (to opaque black).
  959. HRESULT hr = Bmp->InitNewBitmap(width, height, format, TRUE);
  960. if ( SUCCEEDED(hr) )
  961. {
  962. if ( Bmp->GetImageInfo(&SrcImageInfo) == S_OK )
  963. {
  964. REAL dpiX = graphics->GetDpiX();
  965. REAL dpiY = graphics->GetDpiY();
  966. // Note: SrcImageInfo will be updated for dpi in SetResolution()
  967. if ( this->SetResolution(dpiX, dpiY) == Ok )
  968. {
  969. this->Display = graphics->IsDisplay();
  970. }
  971. State = MemBitmap;
  972. PixelFormatInMem = SrcImageInfo.PixelFormat;
  973. return;
  974. }
  975. // There must be some problems if the basic GetImageInfo() failed. So we
  976. // let it fall through to clean up even though InitNewBitmap() succeed
  977. // Notice: we haven't change the State yet. It is still at Invaliad
  978. }
  979. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(w, h, f, g)---InitNewBitmap() failed"));
  980. delete Bmp;
  981. Bmp = NULL;
  982. return;
  983. }
  984. /**************************************************************************\
  985. *
  986. * Function Description:
  987. *
  988. * Create a bitmap image with the specified dimension and pixel format
  989. *
  990. * Arguments:
  991. *
  992. * width, height - Desired bitmap image dimension
  993. * format - Desired pixel format
  994. *
  995. * Return Value:
  996. *
  997. * NONE
  998. *
  999. \**************************************************************************/
  1000. CopyOnWriteBitmap::CopyOnWriteBitmap(
  1001. INT width,
  1002. INT height,
  1003. INT stride, // negative for bottom-up bitmaps
  1004. PixelFormatID format,
  1005. BYTE * scan0
  1006. )
  1007. {
  1008. this->InitDefaults();
  1009. Bmp = new GpMemoryBitmap();
  1010. if (Bmp != NULL)
  1011. {
  1012. BitmapData bmData;
  1013. bmData.Width = width;
  1014. bmData.Height = height;
  1015. bmData.Stride = stride;
  1016. bmData.PixelFormat = format;
  1017. bmData.Scan0 = scan0;
  1018. bmData.Reserved = NULL;
  1019. HRESULT hr = Bmp->InitMemoryBitmap(&bmData);
  1020. CacheImageInfo(hr);
  1021. }
  1022. else
  1023. {
  1024. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(w, h, s, f, scan)----Out of memory"));
  1025. }
  1026. return;
  1027. }
  1028. /**************************************************************************\
  1029. *
  1030. * Function Description:
  1031. *
  1032. * Create an in-memory bitmap image
  1033. *
  1034. * Arguments:
  1035. *
  1036. * membmp - [IN]Memory bitmap current object is based on
  1037. *
  1038. * Return Value:
  1039. *
  1040. * NONE
  1041. *
  1042. * Note:
  1043. * This is a private constructor
  1044. *
  1045. * [minliu] It would be safer if this constructor did a Bmp->AddRef() and
  1046. * the caller was required to do a Bmp->Release() during its own cleanup.
  1047. * However, since we don't currently call Bmp->AddRef(), the caller MUST
  1048. * be very careful not to delete/release the GpMemoryBitmap passed into
  1049. * this contructor. Fortunately, this this constructor is only
  1050. * used in Clone() and GetThumbnail() and in each case the caller is
  1051. * properly managing the objects.
  1052. *
  1053. * New code which uses this contructor will similarly have to manage
  1054. * the membmp passed in properly.
  1055. *
  1056. \**************************************************************************/
  1057. inline
  1058. CopyOnWriteBitmap::CopyOnWriteBitmap(
  1059. GpMemoryBitmap* membmp
  1060. )
  1061. {
  1062. ASSERT(membmp != NULL);
  1063. InitDefaults();
  1064. Bmp = membmp; // [minliu] Dangerous assignment, see header comments above
  1065. if ( Bmp->GetImageInfo(&SrcImageInfo) == S_OK )
  1066. {
  1067. PixelFormatInMem = SrcImageInfo.PixelFormat;
  1068. State = MemBitmap;
  1069. }
  1070. else
  1071. {
  1072. Bmp = NULL;
  1073. }
  1074. }
  1075. /**************************************************************************\
  1076. *
  1077. * Function Description:
  1078. *
  1079. * INTEROP
  1080. *
  1081. * Decode an RLE_8 bitmap into an 8bpp allocated bitmap. This only works
  1082. * for bitmaps with positive stride because the RLE stream doesn't necessarily
  1083. * respect end of line tags, and we would otherwise need to keep track of it.
  1084. * Caller must fix up in such cases.
  1085. *
  1086. * Arguments:
  1087. *
  1088. * gdiBitmapInfo - Points to a BITMAPINFO, describing bitmap format
  1089. * gdiBitmapData - Points to the bits used to initialize image
  1090. * bitmapData----- Points to the BitmapData we return to the caller
  1091. *
  1092. * Comments:
  1093. *
  1094. * 10/13/2000 ericvan
  1095. *
  1096. * Return Value:
  1097. *
  1098. * NONE
  1099. *
  1100. \**************************************************************************/
  1101. VOID *
  1102. DecodeCompressedRLEBitmap(
  1103. BITMAPINFO * gdiBitmapInfo,
  1104. VOID * gdiBitmapData,
  1105. BitmapData * bitmapData
  1106. )
  1107. {
  1108. ASSERT(gdiBitmapInfo->bmiHeader.biCompression == BI_RLE8);
  1109. ASSERT(gdiBitmapInfo->bmiHeader.biSizeImage>0);
  1110. ASSERT(gdiBitmapData != NULL);
  1111. BYTE* outputBitmap;
  1112. INT stride = bitmapData->Stride;
  1113. if (stride<0)
  1114. {
  1115. stride = -stride;
  1116. }
  1117. outputBitmap = (BYTE*)GpMalloc(stride*gdiBitmapInfo->bmiHeader.biHeight);
  1118. if (outputBitmap != NULL)
  1119. {
  1120. BYTE * srcPtr = (BYTE*)gdiBitmapData;
  1121. BYTE * endStrPtr = srcPtr + gdiBitmapInfo->bmiHeader.biSizeImage;
  1122. BYTE * dstPtr = outputBitmap;
  1123. BYTE * dstRasterPtr = outputBitmap;
  1124. BYTE * endDstPtr = outputBitmap + stride*gdiBitmapInfo->bmiHeader.biHeight;
  1125. while (srcPtr < endStrPtr)
  1126. {
  1127. INT numPixels = *srcPtr++;
  1128. if (numPixels == 0)
  1129. {
  1130. BYTE encode = *srcPtr++;
  1131. switch (encode)
  1132. {
  1133. case 0: // End of line.
  1134. dstRasterPtr += stride;
  1135. dstPtr = dstRasterPtr;
  1136. ASSERT(dstRasterPtr <= endDstPtr);
  1137. if (dstRasterPtr > endDstPtr)
  1138. {
  1139. GpFree(outputBitmap);
  1140. return NULL;
  1141. }
  1142. break;
  1143. case 1: // End of bitmap.
  1144. goto FinishedDecode;
  1145. case 2: // Delta. The 2 bytes following the escape contain
  1146. // unsigned values indicating the horizontal and vertical
  1147. // offsets of the next pixel from the current position.
  1148. {
  1149. BYTE horzOff = *srcPtr++;
  1150. BYTE vertOff = *srcPtr++;
  1151. dstPtr = dstPtr + horzOff + vertOff*stride;
  1152. dstRasterPtr += vertOff*stride;
  1153. ASSERT(dstRasterPtr <= endDstPtr);
  1154. if (dstRasterPtr > endDstPtr)
  1155. {
  1156. GpFree(outputBitmap);
  1157. return NULL;
  1158. }
  1159. break;
  1160. }
  1161. default:
  1162. numPixels = (INT)encode;
  1163. while (numPixels--)
  1164. {
  1165. *dstPtr++ = *srcPtr++;
  1166. }
  1167. // Force word alignment if not WORD aligned
  1168. if (((ULONG_PTR)srcPtr) % 2 == 1) srcPtr++;
  1169. }
  1170. }
  1171. else
  1172. {
  1173. BYTE outPixel = *srcPtr++;
  1174. while (numPixels--)
  1175. {
  1176. *dstPtr++ = outPixel;
  1177. }
  1178. }
  1179. }
  1180. }
  1181. FinishedDecode:
  1182. if (outputBitmap && bitmapData->Stride<0)
  1183. {
  1184. BYTE* flippedBitmap = (BYTE *)GpMalloc(stride*gdiBitmapInfo->bmiHeader.biHeight);
  1185. if (flippedBitmap != NULL)
  1186. {
  1187. BYTE * srcPtr = outputBitmap + stride*(bitmapData->Height-1);
  1188. BYTE * dstPtr = flippedBitmap;
  1189. for (UINT cntY = 0; cntY<bitmapData->Height; cntY++)
  1190. {
  1191. GpMemcpy(dstPtr, srcPtr, stride);
  1192. srcPtr -= stride;
  1193. dstPtr += stride;
  1194. }
  1195. GpFree(outputBitmap);
  1196. outputBitmap = flippedBitmap;
  1197. bitmapData->Stride = stride;
  1198. }
  1199. }
  1200. return outputBitmap;
  1201. }
  1202. /**************************************************************************\
  1203. *
  1204. * Function Description:
  1205. *
  1206. * INTEROP
  1207. *
  1208. * Create a bitmap image from a GDI-style BITMAPINFO and pointer to
  1209. * the bits. Also, fill the ColorPalette info
  1210. *
  1211. * Arguments:
  1212. *
  1213. * gdiBitmapInfo - Points to a BITMAPINFO, describing bitmap format
  1214. * gdiBitmapData - Points to the bits used to initialize image
  1215. * bitmapData----- Points to the BitmapData we return to the caller
  1216. * palette-------- Points to a ColorPalette which will be filled in this method
  1217. *
  1218. * Comments:
  1219. *
  1220. * Does not handle compressed formats. Not identified as a customer need,
  1221. * but could add for completeness...
  1222. *
  1223. * Return Value:
  1224. *
  1225. * NONE
  1226. *
  1227. \**************************************************************************/
  1228. BOOL
  1229. ValidateBitmapInfo(
  1230. BITMAPINFO* gdiBitmapInfo,
  1231. VOID* gdiBitmapData,
  1232. BitmapData* bitmapData,
  1233. ColorPalette* palette
  1234. )
  1235. {
  1236. BOOL status = FALSE;
  1237. ASSERT(gdiBitmapInfo != NULL);
  1238. ASSERT(gdiBitmapData != NULL);
  1239. ASSERT(bitmapData != NULL);
  1240. ASSERT(palette != NULL);
  1241. // Only understand BI_RGB and BI_BITFIELDS.
  1242. //!!!TODO: could handle BI_JPEG and BI_PNG by creating a GpMemoryStream
  1243. //!!! and passing to Bitmap::Bitmap(IStream*)
  1244. //!!!TODO: could handle BI_RLEx by creating a DIB to render into and
  1245. //!!! grabbing the decompressed bits
  1246. if ((gdiBitmapInfo->bmiHeader.biCompression != BI_RGB) &&
  1247. (gdiBitmapInfo->bmiHeader.biCompression != BI_BITFIELDS) &&
  1248. (gdiBitmapInfo->bmiHeader.biCompression != BI_RLE8))
  1249. {
  1250. return status;
  1251. }
  1252. // Scanlines are aligned to 4 byte boundaries.
  1253. INT colorBits = gdiBitmapInfo->bmiHeader.biPlanes *
  1254. gdiBitmapInfo->bmiHeader.biBitCount;
  1255. INT stride = (((gdiBitmapInfo->bmiHeader.biWidth * colorBits) + 31)
  1256. & ~31) / 8;
  1257. // Determine GDI+ Pixelformat. Note that GDI bitmaps do not have alpha.
  1258. PixelFormatID format = PIXFMT_UNDEFINED;
  1259. switch (colorBits)
  1260. {
  1261. case 1:
  1262. format = PIXFMT_1BPP_INDEXED;
  1263. break;
  1264. case 4:
  1265. format = PIXFMT_4BPP_INDEXED;
  1266. break;
  1267. case 8:
  1268. format = PIXFMT_8BPP_INDEXED;
  1269. break;
  1270. case 16:
  1271. if (gdiBitmapInfo->bmiHeader.biCompression == BI_RGB)
  1272. format = PIXFMT_16BPP_RGB555;
  1273. else
  1274. {
  1275. ASSERT(gdiBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS);
  1276. ULONG* colorMasks = reinterpret_cast<ULONG*>
  1277. (&gdiBitmapInfo->bmiColors[0]);
  1278. if ((colorMasks[0] == 0x00007c00) && // red
  1279. (colorMasks[1] == 0x000003e0) && // green
  1280. (colorMasks[2] == 0x0000001f)) // blue
  1281. format = PIXFMT_16BPP_RGB555;
  1282. else if ((colorMasks[0] == 0x0000F800) && // red
  1283. (colorMasks[1] == 0x000007e0) && // green
  1284. (colorMasks[2] == 0x0000001f)) // blue
  1285. format = PIXFMT_16BPP_RGB565;
  1286. //!!!TODO: Win9x does not support any other combination for
  1287. //!!! 16bpp BI_BITFIELDS. WinNT does and we could support
  1288. //!!! via same mechanism as for BI_RLEx, but is it worth it?
  1289. }
  1290. break;
  1291. case 24:
  1292. format = PIXFMT_24BPP_RGB;
  1293. break;
  1294. case 32:
  1295. if (gdiBitmapInfo->bmiHeader.biCompression == BI_RGB)
  1296. format = PIXFMT_32BPP_RGB;
  1297. else
  1298. {
  1299. ASSERT(gdiBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS);
  1300. ULONG* colorMasks = reinterpret_cast<ULONG*>
  1301. (&gdiBitmapInfo->bmiColors[0]);
  1302. if ((colorMasks[0] == 0x00ff0000) && // red
  1303. (colorMasks[1] == 0x0000ff00) && // green
  1304. (colorMasks[2] == 0x000000ff)) // blue
  1305. format = PIXFMT_32BPP_RGB;
  1306. else
  1307. format = PIXFMT_UNDEFINED;
  1308. //!!!TODO: Win9x does not support any other combination for
  1309. //!!! 32bpp BI_BITFIELDS. WinNT does and we could support
  1310. //!!! via same mechanism as for BI_RLEx, but is it worth it?
  1311. }
  1312. break;
  1313. default:
  1314. format = PIXFMT_UNDEFINED;
  1315. break;
  1316. }
  1317. if (format == PIXFMT_UNDEFINED)
  1318. return status;
  1319. // Deal with color table.
  1320. switch(format)
  1321. {
  1322. case PIXFMT_1BPP_INDEXED:
  1323. case PIXFMT_4BPP_INDEXED:
  1324. case PIXFMT_8BPP_INDEXED:
  1325. palette->Count = 1 << colorBits;
  1326. if ((gdiBitmapInfo->bmiHeader.biClrUsed > 0) &&
  1327. (gdiBitmapInfo->bmiHeader.biClrUsed < palette->Count))
  1328. palette->Count = gdiBitmapInfo->bmiHeader.biClrUsed;
  1329. break;
  1330. default:
  1331. palette->Count = 0;
  1332. break;
  1333. }
  1334. ASSERT(palette->Count <= 256);
  1335. if (palette->Count)
  1336. {
  1337. palette->Flags = 0;
  1338. RGBQUAD* rgb = gdiBitmapInfo->bmiColors;
  1339. ARGB* argb = palette->Entries;
  1340. ARGB* argbEnd = argb + palette->Count;
  1341. for (; argb < argbEnd; argb++, rgb++)
  1342. {
  1343. *argb = Color::MakeARGB(255, rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
  1344. }
  1345. }
  1346. // Compute scan0. The stride will allow us to determine top-down or
  1347. // bottom-up.
  1348. VOID* scan0;
  1349. INT height;
  1350. if (gdiBitmapInfo->bmiHeader.biHeight > 0)
  1351. {
  1352. // Bottom-up:
  1353. height = gdiBitmapInfo->bmiHeader.biHeight;
  1354. scan0 = static_cast<VOID*>
  1355. (static_cast<BYTE*>(gdiBitmapData) + (height - 1) * stride);
  1356. stride = -stride;
  1357. }
  1358. else
  1359. {
  1360. // Top-down:
  1361. height = -gdiBitmapInfo->bmiHeader.biHeight;
  1362. scan0 = gdiBitmapData;
  1363. }
  1364. // Setup the BitmapData.
  1365. bitmapData->Width = gdiBitmapInfo->bmiHeader.biWidth;
  1366. bitmapData->Height = height;
  1367. bitmapData->Stride = stride;
  1368. bitmapData->PixelFormat = format;
  1369. bitmapData->Scan0 = scan0;
  1370. bitmapData->Reserved = NULL;
  1371. status = TRUE;
  1372. return status;
  1373. }
  1374. CopyOnWriteBitmap::CopyOnWriteBitmap(
  1375. BITMAPINFO* gdiBitmapInfo,
  1376. VOID* gdiBitmapData,
  1377. BOOL ownBitmapData
  1378. )
  1379. {
  1380. this->InitDefaults();
  1381. if ( ownBitmapData )
  1382. {
  1383. cleanupBitmapData = gdiBitmapData;
  1384. }
  1385. Bmp = new GpMemoryBitmap();
  1386. if ( Bmp != NULL )
  1387. {
  1388. BitmapData bitmapData;
  1389. UINT colorTableSize;
  1390. BYTE paletteBuffer[sizeof(ColorPalette) + 255*sizeof(ARGB)];
  1391. ColorPalette* palette = reinterpret_cast<ColorPalette*>
  1392. (&paletteBuffer[0]);
  1393. // Validate image info
  1394. // Note: "palette" and "bitmapData" structures will be filled after
  1395. // return from ValidateBitmapInfo()
  1396. if ( ValidateBitmapInfo(gdiBitmapInfo, gdiBitmapData,
  1397. &bitmapData, palette) )
  1398. {
  1399. HRESULT hr;
  1400. if (gdiBitmapInfo->bmiHeader.biCompression == BI_RLE8)
  1401. {
  1402. VOID* decodedBitmapBits;
  1403. decodedBitmapBits = DecodeCompressedRLEBitmap(gdiBitmapInfo,
  1404. gdiBitmapData,
  1405. &bitmapData);
  1406. if (decodedBitmapBits == NULL)
  1407. {
  1408. goto CleanupBmp;
  1409. }
  1410. if (ownBitmapData)
  1411. {
  1412. GpFree(gdiBitmapData);
  1413. }
  1414. cleanupBitmapData = decodedBitmapBits;
  1415. ownBitmapData = TRUE;
  1416. bitmapData.Scan0 = cleanupBitmapData;
  1417. }
  1418. hr = Bmp->InitMemoryBitmap(&bitmapData);
  1419. if ( SUCCEEDED(hr) )
  1420. {
  1421. // Set the current state
  1422. State = MemBitmap;
  1423. // If it is indexed mode, set the palette
  1424. if ( palette->Count )
  1425. {
  1426. hr = Bmp->SetPalette(palette);
  1427. }
  1428. if ( SUCCEEDED(hr) )
  1429. {
  1430. // Set proper image flags
  1431. UINT imageFlags;
  1432. BITMAPINFOHEADER *bmih = &gdiBitmapInfo->bmiHeader;
  1433. imageFlags = SinkFlagsTopDown
  1434. | SinkFlagsFullWidth
  1435. | ImageFlagsHasRealPixelSize
  1436. | ImageFlagsColorSpaceRGB;
  1437. // If both XPelsPerMeter and YPelsPerMeter are greater than
  1438. // 0, then we claim that the file has real dpi info in the
  1439. // flags. Otherwise, claim that the dpi's are fake.
  1440. if ( (bmih->biXPelsPerMeter > 0)
  1441. &&(bmih->biYPelsPerMeter > 0) )
  1442. {
  1443. imageFlags |= ImageFlagsHasRealDPI;
  1444. }
  1445. hr = Bmp->SetImageFlags(imageFlags);
  1446. if ( SUCCEEDED(hr) )
  1447. {
  1448. // Get source image info
  1449. hr = Bmp->GetImageInfo(&SrcImageInfo);
  1450. if ( SUCCEEDED(hr) )
  1451. {
  1452. PixelFormatInMem = SrcImageInfo.PixelFormat;
  1453. // Return successfully
  1454. return;
  1455. }
  1456. else
  1457. {
  1458. WARNING(("::CopyOnWriteBitmap(b, d)-GetImageInfo() failed"));
  1459. }
  1460. }
  1461. }
  1462. }// If ( SUCCEEDED() on InitMemoryBitmap() )
  1463. CleanupBmp:
  1464. ;
  1465. }// if ( ValidateBitmapInfo() )
  1466. // If we fall into here, it means something is wrong above if the basic
  1467. // GetImageInfo() or SetImageFlags() failed.
  1468. // So we let it fall through to clean up
  1469. // Notice: we have to reset the State to Invaliad afetr clean up
  1470. WARNING(("CopyOnWriteBitmap::CopyOnWriteBitmap(bmpinfo, data)--InitMemoryBitmap failed"));
  1471. Bmp->Release();
  1472. Bmp = NULL;
  1473. State = Invalid;
  1474. return;
  1475. }// If ( Bmp != NULL )
  1476. WARNING(("Out of memory"));
  1477. return;
  1478. }
  1479. /**************************************************************************\
  1480. *
  1481. * Function Description:
  1482. *
  1483. * INTEROP
  1484. *
  1485. * Create CopyOnWriteBitmap from a GDI HBITMAP. The HBITMAP must not be selected
  1486. * into an HDC. The hpal defines the color table if hbm is a 4bpp or 8bpp
  1487. * DDB.
  1488. *
  1489. * Arguments:
  1490. *
  1491. * hbm -- Initialize CopyOnWriteBitmap with contents of this HBITMAP
  1492. * hpal -- Defines color table if hbm is palettized DDB
  1493. * bitmap -- Return created bitmap via this buffer
  1494. *
  1495. * Return Value:
  1496. *
  1497. * Ok if successful
  1498. *
  1499. \**************************************************************************/
  1500. GpStatus
  1501. CopyOnWriteBitmap::CreateFromHBITMAP(
  1502. HBITMAP hbm,
  1503. HPALETTE hpal,
  1504. CopyOnWriteBitmap** bitmap
  1505. )
  1506. {
  1507. GpStatus status = Win32Error;
  1508. BYTE bufferBitmapInfo[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
  1509. BITMAPINFO *gdiBitmapInfo = (BITMAPINFO *) bufferBitmapInfo;
  1510. memset(bufferBitmapInfo, 0, sizeof(bufferBitmapInfo));
  1511. HDC hdc = CreateCompatibleDC(NULL);
  1512. if (hdc)
  1513. {
  1514. // Select palette (ignored if bitmap is not DDB or not palettized):
  1515. HPALETTE hpalOld = (HPALETTE) SelectObject(hdc, hpal);
  1516. // Call GetDIBits to get info about size, etc. of the GDI bitmap:
  1517. gdiBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1518. if (GetDIBits(hdc, hbm, 0, 0, NULL, gdiBitmapInfo, DIB_RGB_COLORS) &&
  1519. (gdiBitmapInfo->bmiHeader.biSizeImage != 0))
  1520. {
  1521. // Allocate memory for the bitmap bits:
  1522. VOID *gdiBitmapData = GpMalloc(gdiBitmapInfo->bmiHeader.biSizeImage);
  1523. if (gdiBitmapData != NULL)
  1524. {
  1525. // Get the bitmap bits:
  1526. if (GetDIBits(hdc, hbm,
  1527. 0, abs(gdiBitmapInfo->bmiHeader.biHeight),
  1528. gdiBitmapData, gdiBitmapInfo, DIB_RGB_COLORS))
  1529. {
  1530. // Create a GDI+ bitmap from the BITMAPINFO and bits.
  1531. // Let the GDI+ bitmap take ownership of the memory
  1532. // (i.e., Bitmap::Dispose() will delete the bitmap
  1533. // bits buffer):
  1534. *bitmap = new CopyOnWriteBitmap(gdiBitmapInfo, gdiBitmapData, TRUE);
  1535. if (*bitmap != NULL)
  1536. {
  1537. if ((*bitmap)->IsValid())
  1538. status = Ok;
  1539. else
  1540. {
  1541. (*bitmap)->Dispose();
  1542. *bitmap = NULL;
  1543. status = InvalidParameter;
  1544. }
  1545. }
  1546. else
  1547. {
  1548. // Bitmap ctor failed, so we still have responsiblity
  1549. // for cleaning up the bitmap bits buffer:
  1550. GpFree(gdiBitmapData);
  1551. status = OutOfMemory;
  1552. }
  1553. }
  1554. else
  1555. {
  1556. GpFree(gdiBitmapData);
  1557. }
  1558. }
  1559. else
  1560. {
  1561. status = OutOfMemory;
  1562. }
  1563. }
  1564. SelectObject(hdc, hpalOld);
  1565. DeleteDC(hdc);
  1566. }
  1567. return status;
  1568. }
  1569. /**************************************************************************\
  1570. *
  1571. * Function Description:
  1572. *
  1573. * INTEROP
  1574. *
  1575. * Create CopyOnWriteBitmap from a Win32 HICON.
  1576. *
  1577. * Arguments:
  1578. *
  1579. * hicon -- Initialize CopyOnWriteBitmap with contents of this HICON
  1580. * bitmap -- Return created bitmap via this buffer
  1581. *
  1582. * Return Value:
  1583. *
  1584. * Ok if successful
  1585. *
  1586. \**************************************************************************/
  1587. VOID ImportMask32BPP(BitmapData* dst, BitmapData* mask)
  1588. {
  1589. ASSERT(dst->PixelFormat == PIXFMT_32BPP_ARGB);
  1590. ASSERT(mask->PixelFormat == PIXFMT_32BPP_RGB);
  1591. ASSERT(dst->Width == mask->Width);
  1592. ASSERT(dst->Height == mask->Height);
  1593. ASSERT(dst->Scan0 != NULL);
  1594. ASSERT(mask->Scan0 != NULL);
  1595. BYTE* dstScan = static_cast<BYTE*>(dst->Scan0);
  1596. BYTE* maskScan = static_cast<BYTE*>(mask->Scan0);
  1597. for (UINT row = 0; row < dst->Height; row++)
  1598. {
  1599. ARGB *dstPixel = static_cast<ARGB*>(static_cast<VOID*>(dstScan));
  1600. ARGB *maskPixel = static_cast<ARGB*>(static_cast<VOID*>(maskScan));
  1601. for (UINT col = 0; col < dst->Width; col++)
  1602. {
  1603. if (*maskPixel)
  1604. *dstPixel = 0;
  1605. dstPixel++;
  1606. maskPixel++;
  1607. }
  1608. dstScan = dstScan + dst->Stride;
  1609. maskScan = maskScan + mask->Stride;
  1610. }
  1611. }
  1612. GpStatus
  1613. CopyOnWriteBitmap::CreateFromHICON(
  1614. HICON hicon,
  1615. CopyOnWriteBitmap** bitmap
  1616. )
  1617. {
  1618. GpStatus status = Ok;
  1619. // Get icon bitmaps via Win32:
  1620. ICONINFO iconInfo;
  1621. if (GetIconInfo(hicon, &iconInfo))
  1622. {
  1623. if (iconInfo.fIcon && (iconInfo.hbmColor != NULL))
  1624. {
  1625. // Create a Bitmap from the icon's hbmColor:
  1626. status = CreateFromHBITMAP(iconInfo.hbmColor,
  1627. (HPALETTE)GetStockObject(DEFAULT_PALETTE),
  1628. bitmap);
  1629. // Convert Bitmap to 32bpp ARGB (need the alpha channel):
  1630. if (status == Ok && (*bitmap != NULL))
  1631. (*bitmap)->ConvertFormat(PIXFMT_32BPP_ARGB, NULL, NULL);
  1632. // Retrieve the icon mask:
  1633. if ((status == Ok) && (iconInfo.hbmMask != NULL))
  1634. {
  1635. status = Win32Error;
  1636. HDC hdc = GetDC(NULL);
  1637. if (hdc)
  1638. {
  1639. // Get some basic information about the bitmap mask:
  1640. BYTE bufferBitmapInfo[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
  1641. BITMAPINFO *gdiBitmapInfo = (BITMAPINFO *) bufferBitmapInfo;
  1642. memset(bufferBitmapInfo, 0, sizeof(bufferBitmapInfo));
  1643. gdiBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1644. if (GetDIBits(hdc,
  1645. iconInfo.hbmMask,
  1646. 0,
  1647. 0,
  1648. NULL,
  1649. gdiBitmapInfo,
  1650. DIB_RGB_COLORS))
  1651. {
  1652. // Get the bitmap mask as a 32bpp top-down DIB:
  1653. gdiBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1654. gdiBitmapInfo->bmiHeader.biHeight = -abs(gdiBitmapInfo->bmiHeader.biHeight);
  1655. gdiBitmapInfo->bmiHeader.biPlanes = 1;
  1656. gdiBitmapInfo->bmiHeader.biBitCount = 32;
  1657. gdiBitmapInfo->bmiHeader.biCompression = BI_RGB;
  1658. gdiBitmapInfo->bmiHeader.biSizeImage = 0;
  1659. gdiBitmapInfo->bmiHeader.biClrUsed = 0;
  1660. gdiBitmapInfo->bmiHeader.biClrImportant = 0;
  1661. VOID *gdiBitmapData = GpMalloc(gdiBitmapInfo->bmiHeader.biHeight
  1662. * gdiBitmapInfo->bmiHeader.biHeight
  1663. * 4);
  1664. if (gdiBitmapData != NULL)
  1665. {
  1666. if (GetDIBits(hdc,
  1667. iconInfo.hbmMask,
  1668. 0,
  1669. -gdiBitmapInfo->bmiHeader.biHeight,
  1670. gdiBitmapData,
  1671. gdiBitmapInfo,
  1672. DIB_RGB_COLORS))
  1673. {
  1674. // Convert non-zero mask values to alpha = 0:
  1675. BitmapData bmpData;
  1676. status = (*bitmap)->LockBits(NULL,
  1677. IMGLOCK_READ|IMGLOCK_WRITE,
  1678. PIXFMT_32BPP_ARGB,
  1679. &bmpData);
  1680. if (status == Ok)
  1681. {
  1682. BitmapData maskData;
  1683. maskData.Width = gdiBitmapInfo->bmiHeader.biWidth;
  1684. maskData.Height = -gdiBitmapInfo->bmiHeader.biHeight;
  1685. maskData.Stride = gdiBitmapInfo->bmiHeader.biWidth * 4;
  1686. maskData.PixelFormat = PIXFMT_32BPP_RGB;
  1687. maskData.Scan0 = gdiBitmapData;
  1688. maskData.Reserved = 0;
  1689. ImportMask32BPP(&bmpData, &maskData);
  1690. (*bitmap)->UnlockBits(&bmpData);
  1691. }
  1692. }
  1693. else
  1694. {
  1695. WARNING(("GetDIBits failed on icon mask bitmap"));
  1696. }
  1697. GpFree(gdiBitmapData);
  1698. }
  1699. else
  1700. {
  1701. WARNING(("memory allocation failed"));
  1702. status = OutOfMemory;
  1703. }
  1704. }
  1705. else
  1706. {
  1707. WARNING(("GetDIBits failed on icon color bitmap"));
  1708. }
  1709. ReleaseDC(NULL, hdc);
  1710. }
  1711. }
  1712. }
  1713. else
  1714. {
  1715. status = InvalidParameter;
  1716. }
  1717. if (iconInfo.hbmMask != NULL)
  1718. DeleteObject(iconInfo.hbmMask);
  1719. if (iconInfo.hbmColor != NULL)
  1720. DeleteObject(iconInfo.hbmColor);
  1721. }
  1722. else
  1723. {
  1724. status = InvalidParameter;
  1725. }
  1726. return status;
  1727. }
  1728. /**************************************************************************\
  1729. *
  1730. * Function Description:
  1731. *
  1732. * INTEROP
  1733. *
  1734. * Create CopyOnWriteBitmap from a resource.
  1735. *
  1736. * Arguments:
  1737. *
  1738. * hInstance -- Specifies instance that contains resource
  1739. * lpBitmapName -- Specifies resource name or ordinal
  1740. * bitmap -- Return created bitmap via this buffer
  1741. *
  1742. * Return Value:
  1743. *
  1744. * Ok if successful
  1745. *
  1746. \**************************************************************************/
  1747. GpStatus
  1748. CopyOnWriteBitmap::CreateFromResource(
  1749. HINSTANCE hInstance,
  1750. LPWSTR lpBitmapName,
  1751. CopyOnWriteBitmap** bitmap
  1752. )
  1753. {
  1754. GpStatus status = Ok;
  1755. HBITMAP hbm = (HBITMAP) _LoadBitmap(hInstance, lpBitmapName);
  1756. if (hbm)
  1757. {
  1758. status = CreateFromHBITMAP(hbm, (HPALETTE) NULL, bitmap);
  1759. DeleteObject(hbm);
  1760. }
  1761. else
  1762. {
  1763. status = InvalidParameter;
  1764. }
  1765. return status;
  1766. }
  1767. /**************************************************************************\
  1768. *
  1769. * Function Description:
  1770. *
  1771. * CopyOnWriteBitmap object destructor
  1772. *
  1773. * Arguments:
  1774. *
  1775. * NONE
  1776. *
  1777. * Return Value:
  1778. *
  1779. * NONE
  1780. *
  1781. \**************************************************************************/
  1782. CopyOnWriteBitmap::~CopyOnWriteBitmap()
  1783. {
  1784. this->FreeData();
  1785. // Close the encoder object attached to this
  1786. TerminateEncoder();
  1787. }
  1788. VOID
  1789. CopyOnWriteBitmap::FreeData()
  1790. {
  1791. GpFree(Filename);
  1792. if (Stream) Stream->Release();
  1793. if (Img) Img->Release();
  1794. if (Bmp) Bmp->Release();
  1795. if (InteropData.Hdc) DeleteDC(InteropData.Hdc);
  1796. if (InteropData.Hbm) DeleteObject(InteropData.Hbm);
  1797. if (cleanupBitmapData) GpFree(cleanupBitmapData);
  1798. }
  1799. /**************************************************************************\
  1800. *
  1801. * Function Description:
  1802. *
  1803. * Dereferences the stream or filename image into a non-decoded image.
  1804. *
  1805. * Arguments:
  1806. *
  1807. * format - Specifies the preferred pixel format
  1808. *
  1809. * Return Value:
  1810. *
  1811. * Status code
  1812. *
  1813. \**************************************************************************/
  1814. GpStatus
  1815. CopyOnWriteBitmap::DereferenceStream() const
  1816. {
  1817. HRESULT hr;
  1818. if (State < DecodedImg)
  1819. {
  1820. ASSERT(Img == NULL);
  1821. if (State == ExtStream)
  1822. {
  1823. ASSERT(Stream != NULL);
  1824. hr = GpDecodedImage::CreateFromStream(Stream, &Img);
  1825. }
  1826. else
  1827. {
  1828. ASSERT(State == ImageRef && Filename != NULL);
  1829. hr = GpDecodedImage::CreateFromFile(Filename, &Img);
  1830. }
  1831. if (FAILED(hr))
  1832. {
  1833. WARNING(("Failed to create decoded image: %x", hr));
  1834. State = Invalid;
  1835. return (MapHRESULTToGpStatus(hr));
  1836. }
  1837. State = DecodedImg;
  1838. }
  1839. return Ok;
  1840. }
  1841. /**************************************************************************\
  1842. *
  1843. * Function Description:
  1844. *
  1845. * Load the memory image into memory
  1846. *
  1847. * Arguments:
  1848. *
  1849. * format - Specifies the preferred pixel format
  1850. *
  1851. * Return Value:
  1852. *
  1853. * Status code
  1854. *
  1855. \**************************************************************************/
  1856. GpStatus
  1857. CopyOnWriteBitmap::LoadIntoMemory(
  1858. PixelFormatID format,
  1859. DrawImageAbort callback,
  1860. VOID *callbackData,
  1861. INT width,
  1862. INT height
  1863. ) const
  1864. {
  1865. ASSERT(IsValid());
  1866. if (State >= MemBitmap)
  1867. return Ok;
  1868. // Create decoded image object if necessary
  1869. HRESULT hr;
  1870. // Dereference the stream or file pointer and create an encoded image
  1871. // object that can be decoded by the codec.
  1872. // If the bitmap is already greater or equal to DecodedImg state, this
  1873. // is a nop.
  1874. GpStatus status = DereferenceStream();
  1875. if ( status != Ok )
  1876. {
  1877. return status;
  1878. }
  1879. ASSERT(Img != NULL);
  1880. if ( format == PixelFormatUndefined )
  1881. {
  1882. // If the caller doesn't care about the pixel format, then we load it
  1883. // as the source image format
  1884. format = SrcImageInfo.PixelFormat;
  1885. }
  1886. if ( ICMConvert == TRUE )
  1887. {
  1888. // Check if the OS supports ICM. We are doing this by checking if the
  1889. // ICM dlls we need are available on the system or not.
  1890. // Note: NT4 doesn't have ICM2 functionality. So the LoadICMDll() call
  1891. // should fail
  1892. // Note: LoadICMDll() is expensive only for the first time. If it has
  1893. // already beed loaded, then it is a very small cost
  1894. hr = LoadICMDll();
  1895. if(SUCCEEDED(hr))
  1896. {
  1897. // We should let the codec know that we need the native data format
  1898. // and we will do the conversion in ICMFrontEnd()
  1899. BOOL fUseICC = TRUE;
  1900. hr = Img->SetDecoderParam(DECODER_USEICC, 1, &fUseICC);
  1901. // Note: we don't need to check the return code of this call because
  1902. // it just pass the info down to the codec. If the codec doesn't
  1903. // support this. It is still fine
  1904. // If the source is in CMYK color space and we need to do ICM
  1905. // conversion, then we can't load the image in as 32PARGB. The reason
  1906. // is that the lower lever codec will return CMYK in native format,
  1907. // as we require it to. But if we ask
  1908. // GpMemoryBitmap::CreateFromImage() to create a 32PARGB, then it
  1909. // will do a format conversion and treat the C channel as ALPHA.
  1910. // That's completely wrong.
  1911. // So the solution here is to change the caller's requirement from
  1912. // 32PARGB to 32ARGB, remember it. Load the image in as 32ARGB, call
  1913. // ICMFrontEnd() to do the ICM conversion. Then before it is done,
  1914. // change the format back to 32 PARGB
  1915. // A complicated work around. MinLiu (01/25/2001)
  1916. if ( (format == PixelFormat32bppPARGB)
  1917. &&(SrcImageInfo.Flags & IMGFLAG_COLORSPACE_CMYK) )
  1918. {
  1919. HasChangedRequiredPixelFormat = TRUE;
  1920. format = PixelFormat32bppARGB;
  1921. }
  1922. }
  1923. // If the OS doesn't support ICM, then we don't set DECODER_USEICC and
  1924. // the codec will return RGB format to us
  1925. }
  1926. // Now load the image into memory
  1927. ASSERT(Bmp == NULL);
  1928. hr = GpMemoryBitmap::CreateFromImage(
  1929. Img,
  1930. width,
  1931. height,
  1932. format,
  1933. InterpolationHintAveraging,
  1934. &Bmp,
  1935. callback,
  1936. callbackData
  1937. );
  1938. if (FAILED(hr))
  1939. {
  1940. WARNING(("Failed to load image into memory: %x", hr));
  1941. return MapHRESULTToGpStatus(hr);
  1942. }
  1943. // If resolution has been overridden, make sure GpMemoryBitmap is
  1944. // consistent with the set value
  1945. if ( (XDpiOverride > 0.0) && (YDpiOverride > 0.0) )
  1946. {
  1947. // Note: we don't need to check return code here since SetResolution()
  1948. // will not fail if both parameters are > 0
  1949. Bmp->SetResolution(XDpiOverride, YDpiOverride);
  1950. }
  1951. State = MemBitmap;
  1952. // Remember pixel format in the memory
  1953. PixelFormatInMem = format;
  1954. // We must be in MemBitmap state otherwise ICMFrontEnd will call us
  1955. // recursively.
  1956. ASSERT((State == MemBitmap));
  1957. // !!! ack - we have to call a huge chain of non-const stuff here from this
  1958. // const function. This should be fixed by removing the const from this
  1959. // function, but it's a pretty massive change.
  1960. const_cast<CopyOnWriteBitmap *>(this)->ICMFrontEnd(NULL, callback, callbackData, NULL);
  1961. return Ok;
  1962. }
  1963. /**************************************************************************\
  1964. *
  1965. * Function Description:
  1966. *
  1967. * Get the encoder parameter list size from an encoder object specified by
  1968. * input clsid
  1969. *
  1970. * Arguments:
  1971. *
  1972. * clsidEncoder - Specifies the encoder class ID
  1973. * size---------- The size of the encoder parameter list
  1974. *
  1975. * Return Value:
  1976. *
  1977. * Status code
  1978. *
  1979. * Revision History:
  1980. *
  1981. * 03/22/2000 minliu
  1982. * Created it.
  1983. *
  1984. \**************************************************************************/
  1985. GpStatus
  1986. CopyOnWriteBitmap::GetEncoderParameterListSize(
  1987. CLSID* clsidEncoder,
  1988. UINT* size
  1989. )
  1990. {
  1991. ASSERT(IsValid());
  1992. GpStatus status;
  1993. HRESULT hResult;
  1994. // If the image has a source and it is not dirty, we let the decoder
  1995. // directly talk to the encoder
  1996. if ( (Img != NULL) && (IsDirty() == FALSE) )
  1997. {
  1998. hResult = Img->GetEncoderParameterListSize(clsidEncoder, size);
  1999. }
  2000. else
  2001. {
  2002. status = LoadIntoMemory();
  2003. if ( status != Ok )
  2004. {
  2005. return status;
  2006. }
  2007. hResult = Bmp->GetEncoderParameterListSize(clsidEncoder, size);
  2008. }
  2009. return MapHRESULTToGpStatus(hResult);
  2010. }// GetEncoderParameterListSize()
  2011. /**************************************************************************\
  2012. *
  2013. * Function Description:
  2014. *
  2015. * Get the encoder parameter list from an encoder object specified by
  2016. * input clsid
  2017. *
  2018. * Arguments:
  2019. *
  2020. * clsidEncoder --- Specifies the encoder class ID
  2021. * size------------ The size of the encoder parameter list
  2022. * pBuffer--------- Buffer for storing the list
  2023. *
  2024. * Return Value:
  2025. *
  2026. * Status code
  2027. *
  2028. * Revision History:
  2029. *
  2030. * 03/22/2000 minliu
  2031. * Created it.
  2032. *
  2033. \**************************************************************************/
  2034. GpStatus
  2035. CopyOnWriteBitmap::GetEncoderParameterList(
  2036. CLSID* clsidEncoder,
  2037. UINT size,
  2038. EncoderParameters* pBuffer
  2039. )
  2040. {
  2041. ASSERT(IsValid());
  2042. GpStatus status;
  2043. HRESULT hResult;
  2044. // If the image has a source and it is not dirty, we let the decoder
  2045. // directly talk to the encoder
  2046. if ( (Img != NULL) && (IsDirty() == FALSE) )
  2047. {
  2048. hResult = Img->GetEncoderParameterList(clsidEncoder, size, pBuffer);
  2049. }
  2050. else
  2051. {
  2052. status = LoadIntoMemory();
  2053. if ( status != Ok )
  2054. {
  2055. return status;
  2056. }
  2057. hResult = Bmp->GetEncoderParameterList(clsidEncoder, size, pBuffer);
  2058. }
  2059. return MapHRESULTToGpStatus(hResult);
  2060. }// GetEncoderParameterList()
  2061. /**************************************************************************\
  2062. *
  2063. * Function Description:
  2064. *
  2065. * Parse the input encoder parameter
  2066. *
  2067. * Arguments:
  2068. *
  2069. * encoderParams ------ Pointer to a set of encoder parameters
  2070. * pbIsMultiFrameSave--Return flag to tell the caller if this is a multi-frame
  2071. * saving operation or not
  2072. *
  2073. * Return Value:
  2074. *
  2075. * Status code
  2076. *
  2077. * Note:
  2078. * We don't validate input parameter because this is a private function.
  2079. * For performance reason the caller should validate the parameter before it
  2080. * calls this function. For the moment only those saving methods call it
  2081. *
  2082. * Revision History:
  2083. *
  2084. * 07/19/2000 minliu
  2085. * Created it.
  2086. *
  2087. \**************************************************************************/
  2088. GpStatus
  2089. CopyOnWriteBitmap::ParseEncoderParameter(
  2090. const EncoderParameters* encoderParams,
  2091. BOOL* pfIsMultiFrameSave,
  2092. BOOL* pfSpecialJPEG,
  2093. RotateFlipType* rfType
  2094. )
  2095. {
  2096. ASSERT(encoderParams != NULL);
  2097. ASSERT(pfIsMultiFrameSave != NULL);
  2098. ASSERT(pfSpecialJPEG != NULL);
  2099. ASSERT(rfType != NULL);
  2100. *pfIsMultiFrameSave = FALSE;
  2101. *pfSpecialJPEG = FALSE;
  2102. *rfType = RotateNoneFlipNone;
  2103. // Parse the encoder parameter caller set for:
  2104. // 1) Check if the caller has specified this is a multi-frame save OP or not
  2105. // 2) The caller can't set lossless transformation for JPEG if the image is
  2106. // dirty or the image size is not multiple of 16
  2107. for ( UINT i = 0; (i < encoderParams->Count); ++i )
  2108. {
  2109. if ( (encoderParams->Parameter[i].Guid == ENCODER_SAVE_FLAG)
  2110. &&(encoderParams->Parameter[i].Type == EncoderParameterValueTypeLong)
  2111. &&(encoderParams->Parameter[i].NumberOfValues == 1) )
  2112. {
  2113. UINT* pValue = (UINT*)encoderParams->Parameter[i].Value;
  2114. if ( *pValue == EncoderValueMultiFrame )
  2115. {
  2116. *pfIsMultiFrameSave = TRUE;
  2117. }
  2118. }
  2119. else if ( encoderParams->Parameter[i].Guid == ENCODER_TRANSFORMATION )
  2120. {
  2121. // We should check if the image format user wants to save is
  2122. // JPEG or not. But we can't do this since it might possible that
  2123. // other image codec supports "transformation". Also, we don't need
  2124. // to check this now since the codec will return "InvalidParameter"
  2125. // if it doesn't supports it.
  2126. //
  2127. // For transformation, the type has to be "ValueTypeLong" and
  2128. // "NumberOfValue" should be "1" because you can set only one
  2129. // transformation at a time
  2130. // Of course, the image has to be not dirty
  2131. if ( (encoderParams->Parameter[i].Type
  2132. != EncoderParameterValueTypeLong)
  2133. ||(encoderParams->Parameter[i].NumberOfValues != 1)
  2134. ||(encoderParams->Parameter[i].Value == NULL)
  2135. ||(IsDirty() == TRUE) )
  2136. {
  2137. WARNING(("COWBmap::ParseEncoderParameter-invalid input args"));
  2138. return InvalidParameter;
  2139. }
  2140. if (SrcImageInfo.RawDataFormat == IMGFMT_JPEG)
  2141. {
  2142. // If the width or height is not multiple of 16, set it as a
  2143. // special JPEG so that we have to tranform it in memory
  2144. if (((SrcImageInfo.Width & 0x000F) != 0) ||
  2145. ((SrcImageInfo.Height & 0x000F) != 0))
  2146. {
  2147. *pfSpecialJPEG = TRUE;
  2148. }
  2149. // If the source is JPEG, we will return "rfType" according to
  2150. // the encoder parameter
  2151. EncoderValue requiredTransform =
  2152. *((EncoderValue*)encoderParams->Parameter[i].Value);
  2153. switch ( requiredTransform )
  2154. {
  2155. case EncoderValueTransformRotate90:
  2156. *rfType = Rotate90FlipNone;
  2157. break;
  2158. case EncoderValueTransformRotate180:
  2159. *rfType = Rotate180FlipNone;
  2160. break;
  2161. case EncoderValueTransformRotate270:
  2162. *rfType = Rotate270FlipNone;
  2163. break;
  2164. case EncoderValueTransformFlipHorizontal:
  2165. *rfType = RotateNoneFlipX;
  2166. break;
  2167. case EncoderValueTransformFlipVertical:
  2168. *rfType = RotateNoneFlipY;
  2169. break;
  2170. default:
  2171. break;
  2172. }
  2173. }
  2174. }// GUID == ENCODER_TRANSFORMATION
  2175. }// Loop all the settings
  2176. return Ok;
  2177. }// ParseEncoderParameter()
  2178. /**************************************************************************\
  2179. *
  2180. * Function Description:
  2181. *
  2182. * Transform embedded JPEG thumbnail so that it matches the transform applied
  2183. * to the main image.
  2184. *
  2185. * Return Value:
  2186. *
  2187. * Status code
  2188. *
  2189. * Note:
  2190. * This function should be called iff and source image is JPEG and the caller
  2191. * wants to do a lossless transformation during save.
  2192. * Of course, if the source is not JPEG, this function won't do any harm to the
  2193. * result, just waste of time.
  2194. *
  2195. * Revision History:
  2196. *
  2197. * 01/10/2002 minliu
  2198. * Created it.
  2199. *
  2200. \**************************************************************************/
  2201. GpStatus
  2202. CopyOnWriteBitmap::TransformThumbanil(
  2203. IN CLSID* clsidEncoder, // CLSID for Destination format
  2204. IN EncoderParameters* encoderParams, // Encoder parameters
  2205. OUT PropertyItem **ppOriginalItem // Pointer to original thumbnail
  2206. // property item
  2207. )
  2208. {
  2209. if (ppOriginalItem == NULL)
  2210. {
  2211. return InvalidParameter;
  2212. }
  2213. if (NULL == encoderParams)
  2214. {
  2215. // Nothing we need to do
  2216. return Ok;
  2217. }
  2218. *ppOriginalItem = NULL;
  2219. Status status = Ok;
  2220. HRESULT hr = S_OK;
  2221. // The condition to transform the thumbnail are:
  2222. // 1) Source and dest are JPEGs. But we can't check the format here since it
  2223. // might have been transformed in memory due to the non-multiple of 16
  2224. // issue. The caller should control this, as said above.
  2225. // 2) Has a meaningful transform type
  2226. if (*clsidEncoder == InternalJpegClsID)
  2227. {
  2228. // Check if the source has thumbnail
  2229. UINT cSize = 0;
  2230. status = GetPropertyItemSize(PropertyTagThumbnailData, &cSize);
  2231. if (Ok == status)
  2232. {
  2233. // Allocate memory buffer for receiving it
  2234. PropertyItem *pItem = (PropertyItem*)GpMalloc(cSize);
  2235. if (pItem)
  2236. {
  2237. // Get the thumbnail data
  2238. status = GetPropertyItem(PropertyTagThumbnailData, cSize,pItem);
  2239. if (Ok == status)
  2240. {
  2241. GpImagingFactory imgFact;
  2242. GpDecodedImage *pThumbImage = NULL;
  2243. GpReadOnlyMemoryStream *pSrcStream =
  2244. new GpReadOnlyMemoryStream();
  2245. if (pSrcStream)
  2246. {
  2247. pSrcStream->InitBuffer(pItem->value, pItem->length);
  2248. // Create a decoded image object from the stream
  2249. hr = GpDecodedImage::CreateFromStream(
  2250. pSrcStream,
  2251. &pThumbImage
  2252. );
  2253. if (SUCCEEDED(hr))
  2254. {
  2255. // Check the thumbnail size to see if it is multiple
  2256. // of 16 or not
  2257. ImageInfo imgInfo;
  2258. hr = pThumbImage->GetImageInfo(&imgInfo);
  2259. if (SUCCEEDED(hr))
  2260. {
  2261. BOOL fTrimEdge = FALSE;
  2262. // Number of encoder parameters to set
  2263. int cParams = 1;
  2264. if (((imgInfo.Width & 0x000F) != 0) ||
  2265. ((imgInfo.Height & 0x000F) != 0))
  2266. {
  2267. // Do edge trim if it is non-multiple of 16
  2268. fTrimEdge = TRUE;
  2269. cParams++;
  2270. }
  2271. // Parameter index
  2272. int iParam = 0;
  2273. // Make up a transform encoder parameter
  2274. EncoderParameters *pThumbParam =
  2275. (EncoderParameters*)GpMalloc(
  2276. sizeof(EncoderParameters) +
  2277. cParams * sizeof(EncoderParameter));
  2278. UINT uTransformType = 0;
  2279. if (pThumbParam)
  2280. {
  2281. // Get the transform info from the main
  2282. // image's encoder parameter
  2283. for (UINT i = 0; i < (encoderParams->Count);
  2284. ++i)
  2285. {
  2286. if (encoderParams->Parameter[i].Guid ==
  2287. ENCODER_TRANSFORMATION)
  2288. {
  2289. pThumbParam->Parameter[iParam].Guid=
  2290. ENCODER_TRANSFORMATION;
  2291. pThumbParam->Parameter[iParam].NumberOfValues =
  2292. encoderParams->Parameter[i].NumberOfValues;
  2293. pThumbParam->Parameter[iParam].Type=
  2294. encoderParams->Parameter[i].Type;
  2295. uTransformType =
  2296. *((UINT*)encoderParams->Parameter[i].Value);
  2297. pThumbParam->Parameter[iParam].Value =
  2298. &uTransformType;
  2299. iParam++;
  2300. // Only one transform parameter is
  2301. // allowed
  2302. break;
  2303. }
  2304. }
  2305. // Set the trim edge info if necessary
  2306. if (fTrimEdge)
  2307. {
  2308. BOOL trimFlag = TRUE;
  2309. pThumbParam->Parameter[iParam].Guid =
  2310. ENCODER_TRIMEDGE;
  2311. pThumbParam->Parameter[iParam].Type =
  2312. EncoderParameterValueTypeByte;
  2313. pThumbParam->Parameter[iParam].NumberOfValues
  2314. = 1;
  2315. pThumbParam->Parameter[iParam].Value = &trimFlag;
  2316. iParam++;
  2317. }
  2318. pThumbParam->Count = iParam;
  2319. // Create a memory stream for writing JPEG
  2320. GpWriteOnlyMemoryStream *pDestStream =
  2321. new GpWriteOnlyMemoryStream();
  2322. if (pDestStream)
  2323. {
  2324. // Set initiali buffer size to 2 times
  2325. // the source thumbnail image. This
  2326. // should be enough. On the other hand,
  2327. // GpWriteOnlyMemoryStream object will
  2328. // do realloc if necessary
  2329. hr = pDestStream->InitBuffer(
  2330. 2 * pItem->length);
  2331. if (SUCCEEDED(hr))
  2332. {
  2333. // Save thumbnail to memory stream
  2334. IImageEncoder *pDstJpegEncoder =
  2335. NULL;
  2336. hr = pThumbImage->SaveToStream(
  2337. pDestStream,
  2338. clsidEncoder,
  2339. pThumbParam,
  2340. &pDstJpegEncoder
  2341. );
  2342. // Note: SaveToStream might fail.
  2343. // But the encoder might still be
  2344. // allocated before the failure.
  2345. // There are some code path
  2346. // limitations which causes this.
  2347. // Need to be revisited in Avalon.
  2348. // For now, we should release the
  2349. // encoder object if it is not NULL
  2350. if (pDstJpegEncoder)
  2351. {
  2352. pDstJpegEncoder->TerminateEncoder();
  2353. pDstJpegEncoder->Release();
  2354. }
  2355. if (SUCCEEDED(hr))
  2356. {
  2357. // Get the bits from the stream
  2358. // and set the property
  2359. BYTE *pRawBits = NULL;
  2360. UINT nLength = 0;
  2361. hr = pDestStream->GetBitsPtr(
  2362. &pRawBits,
  2363. &nLength
  2364. );
  2365. if (SUCCEEDED(hr))
  2366. {
  2367. PropertyItem dstItem;
  2368. dstItem.id =
  2369. PropertyTagThumbnailData;
  2370. dstItem.length = nLength;
  2371. dstItem.type =
  2372. PropertyTagTypeByte;
  2373. dstItem.value = pRawBits;
  2374. status = SetPropertyItem(
  2375. &dstItem);
  2376. }
  2377. }// SaveToStream succeed
  2378. }// InitBuffer() succeed
  2379. pDestStream->Release();
  2380. }// Create GpWriteOnlyMemoryStream() succeed
  2381. GpFree(pThumbParam);
  2382. }// Allocate a encoder parameter block succeed
  2383. }// GetImageInfo succeed
  2384. pThumbImage->Release();
  2385. }// Create thumbImage succeed
  2386. pSrcStream->Release();
  2387. }// Create source stream
  2388. else
  2389. {
  2390. status = OutOfMemory;
  2391. }
  2392. }// Get thumbnail data
  2393. if ((Ok == status) && SUCCEEDED(hr))
  2394. {
  2395. // Pass the original thumbnail property item to the caller
  2396. // so that it can undo the transformation after the save()
  2397. *ppOriginalItem = pItem;
  2398. }
  2399. else
  2400. {
  2401. GpFree(pItem);
  2402. }
  2403. }// GpMalloc() succeed
  2404. else
  2405. {
  2406. status = OutOfMemory;
  2407. }
  2408. }// GetPropertyItemSize() Ok
  2409. if (PropertyNotFound == status)
  2410. {
  2411. // If we can't find thumbnail in the image, that's OK. We don't need
  2412. // to transform it. So this function should return Ok
  2413. status = Ok;
  2414. }
  2415. }// Condition check
  2416. if ((Ok == status) && FAILED(hr))
  2417. {
  2418. status = MapHRESULTToGpStatus(hr);
  2419. }
  2420. return status;
  2421. }
  2422. /**************************************************************************\
  2423. *
  2424. * Function Description:
  2425. *
  2426. * Validate if the encoder we created can really support multi-frame saving.
  2427. * If not, call TerminateEncoder()
  2428. * This method is called after we saved the image and we are not sure if we
  2429. * need to keep the encoder pointer.
  2430. *
  2431. * Arguments:
  2432. *
  2433. * VOID
  2434. *
  2435. * Return Value:
  2436. *
  2437. * Status code
  2438. *
  2439. * Note:
  2440. * We don't validate input parameter because this is a private function.
  2441. * For performance reason the caller should validate the parameter before it
  2442. * calls this method. For the moment only those saving methods call it
  2443. *
  2444. * Revision History:
  2445. *
  2446. * 07/19/2000 minliu
  2447. * Created it.
  2448. *
  2449. \**************************************************************************/
  2450. GpStatus
  2451. CopyOnWriteBitmap::ValidateMultiFrameSave()
  2452. {
  2453. // Though the user sets the encoder parameter for multi-frame save, we
  2454. // still need to check if the lower level codec supports saving multi-
  2455. // frame or not.
  2456. // The reason we need to do this is that if the user sets this flag, we
  2457. // don't close the image file handle so that it can saving multi-frame.
  2458. // But for images like JPEG, it supports only single frame. If the user
  2459. // calls SaveAdd() subsequently, we will damage the file which has been
  2460. // saved with current Save() call
  2461. ASSERT(EncoderPtr != NULL);
  2462. UINT uiSize;
  2463. HRESULT hResult = EncoderPtr->GetEncoderParameterListSize(&uiSize);
  2464. if ( hResult == S_OK )
  2465. {
  2466. EncoderParameters* pParams = (EncoderParameters*)GpMalloc(uiSize);
  2467. if ( pParams == NULL )
  2468. {
  2469. // Though we are out of memory here. But we succeed in saving
  2470. // the image. So we should keep that result
  2471. WARNING(("CopyOnWriteBitmap::ValidateMultiFrameSave---Out of memory"));
  2472. TerminateEncoder();
  2473. return OutOfMemory;
  2474. }
  2475. hResult = EncoderPtr->GetEncoderParameterList(uiSize, pParams);
  2476. if ( hResult == S_OK )
  2477. {
  2478. // Check if the codec supports multi-frame save or not
  2479. UINT uiTemp;
  2480. for ( uiTemp = 0; (uiTemp < pParams->Count); ++uiTemp )
  2481. {
  2482. if ( (pParams->Parameter[uiTemp].Guid == ENCODER_SAVE_FLAG)
  2483. &&(pParams->Parameter[uiTemp].Type == EncoderParameterValueTypeLong)
  2484. &&(pParams->Parameter[uiTemp].NumberOfValues == 1)
  2485. &&(EncoderValueMultiFrame
  2486. == *((ULONG*)pParams->Parameter[uiTemp].Value) ) )
  2487. {
  2488. break;
  2489. }
  2490. }
  2491. if ( uiTemp == pParams->Count )
  2492. {
  2493. // Not found clue for supporting multi-frame save
  2494. TerminateEncoder();
  2495. }
  2496. }
  2497. GpFree(pParams);
  2498. }
  2499. else
  2500. {
  2501. // This encoder doesn't provide encoder parameter query. It mustn't
  2502. // support multi-frame save
  2503. TerminateEncoder();
  2504. }
  2505. return Ok;
  2506. }// ValidateFrameSave()
  2507. /**************************************************************************\
  2508. *
  2509. * Function Description:
  2510. *
  2511. * Save the image to a stream using the specified encoder
  2512. *
  2513. * Arguments:
  2514. *
  2515. * stream - Specifies the target stream
  2516. * clsidEncoder - Specifies the CLSID of the encoder
  2517. * encoderParams - Parameters passed to the encoder
  2518. *
  2519. * Return Value:
  2520. *
  2521. * Status code
  2522. *
  2523. \**************************************************************************/
  2524. GpStatus
  2525. CopyOnWriteBitmap::SaveToStream(
  2526. IStream* stream,
  2527. CLSID* clsidEncoder,
  2528. EncoderParameters* encoderParams
  2529. )
  2530. {
  2531. return DoSave(stream, NULL, clsidEncoder, encoderParams);
  2532. }// SaveToStream()
  2533. /**************************************************************************\
  2534. *
  2535. * Function Description:
  2536. *
  2537. * Save the image to a file using the specified encoder
  2538. *
  2539. * Arguments:
  2540. *
  2541. * stream - Specifies the filename to save to
  2542. * clsidEncoder - Specifies the CLSID of the encoder
  2543. * encoderParams - Parameters passed to the encoder
  2544. *
  2545. * Return Value:
  2546. *
  2547. * Status code
  2548. *
  2549. \**************************************************************************/
  2550. GpStatus
  2551. CopyOnWriteBitmap::SaveToFile(
  2552. const WCHAR* filename,
  2553. CLSID* clsidEncoder,
  2554. EncoderParameters* encoderParams
  2555. )
  2556. {
  2557. return DoSave(NULL,filename,clsidEncoder,encoderParams);
  2558. }// SaveToFile()
  2559. GpStatus
  2560. CopyOnWriteBitmap::DoSave(
  2561. IStream* stream,
  2562. const WCHAR* filename,
  2563. CLSID* clsidEncoder,
  2564. EncoderParameters* pEncoderParams
  2565. )
  2566. {
  2567. ASSERT(IsValid());
  2568. // We already have an encoder attached to this bitmap. Need to close it
  2569. // first before we open a new one
  2570. TerminateEncoder();
  2571. GpStatus status = Ok;
  2572. HRESULT hr = S_OK;
  2573. BOOL fMultiFrameSave = FALSE;
  2574. BOOL fSpecialJPEG = FALSE;
  2575. RotateFlipType rfType = RotateNoneFlipNone;
  2576. if (pEncoderParams)
  2577. {
  2578. // Validate the encoder parameter caller set
  2579. status = ParseEncoderParameter(
  2580. pEncoderParams,
  2581. &fMultiFrameSave,
  2582. &fSpecialJPEG,
  2583. &rfType
  2584. );
  2585. if (status != Ok)
  2586. {
  2587. WARNING(("CopyOnWriteBitmap::DoSave--ParseEncoderParameter() failed"));
  2588. return status;
  2589. }
  2590. }
  2591. // If the destination file format is JPEG and it needs special JPEG
  2592. // treatment, that is, the size doesn't meet the lossless transformation
  2593. // requirement. But the caller wants to do a lossless transformation. So we
  2594. // rotate or flip it in memory. Then pass this flag down to GpMemoryBitmap
  2595. // which will set the luminance and chrominance table before save. This way
  2596. // we can do our best to preserve the original JPEG image quality
  2597. if ((fSpecialJPEG == TRUE) &&
  2598. (rfType != RotateNoneFlipNone) &&
  2599. (*clsidEncoder == InternalJpegClsID))
  2600. {
  2601. // We are handling special lossless JPEG transform saving request
  2602. SpecialJPEGSave = TRUE;
  2603. // Rotate or flip in memory.
  2604. hr = RotateFlip(rfType);
  2605. if (FAILED(hr))
  2606. {
  2607. WARNING(("CopyOnWriteBitmap::DoSave-RotateFlip() failed"));
  2608. return MapHRESULTToGpStatus(hr);
  2609. }
  2610. }
  2611. // If the image has a source and it is not dirty, we let the decoder
  2612. // directly talk to the encoder
  2613. PropertyItem *pSrcItem = NULL;
  2614. BOOL fNeedToRestoreThumb = FALSE;
  2615. if ((Img != NULL) && (IsDirty() == FALSE))
  2616. {
  2617. // Since we can't save CMYK TIFF for now. So we shouldn't pass CMYK bits
  2618. // to the encoder. JPEG decoder doesn't support this decoder parameter
  2619. // yet. See windows bug#375298 for more details.
  2620. // In V2, after we add CMYK as one of the color format, after we move
  2621. // all the color conversion stuff to an approprite place, we will
  2622. // re-visit the code here.
  2623. BOOL fUseICC = FALSE;
  2624. hr = Img->SetDecoderParam(DECODER_USEICC, 1, &fUseICC);
  2625. // Note: we don't need to check the return code for SetDecoderParam()
  2626. // Most codec not support it. Then it will be a Nop.
  2627. // Handle thumbnail transformation if it is lossless JPEG transformation
  2628. // Note: rfType will be set to a non-RotateNoneFlipNone value iff the
  2629. // source image is JPEG
  2630. if (rfType != RotateNoneFlipNone)
  2631. {
  2632. status = TransformThumbanil(clsidEncoder,pEncoderParams, &pSrcItem);
  2633. }
  2634. if (Ok == status)
  2635. {
  2636. fNeedToRestoreThumb = TRUE;
  2637. if (stream)
  2638. {
  2639. hr = Img->SaveToStream(
  2640. stream,
  2641. clsidEncoder,
  2642. pEncoderParams,
  2643. &EncoderPtr
  2644. );
  2645. }
  2646. else if (filename)
  2647. {
  2648. hr = Img->SaveToFile(
  2649. filename,
  2650. clsidEncoder,
  2651. pEncoderParams,
  2652. &EncoderPtr
  2653. );
  2654. }
  2655. else
  2656. {
  2657. // This should not happen that both stream and filename are NULL
  2658. hr = E_FAIL;
  2659. }
  2660. }
  2661. }
  2662. else
  2663. {
  2664. status = LoadIntoMemory();
  2665. if (status != Ok)
  2666. {
  2667. return status;
  2668. }
  2669. EncoderParameters *pNewParam = pEncoderParams;
  2670. BOOL fFreeExtraParamBlock = FALSE;
  2671. // PAY attention to the scope of "fSuppressAPP0". Its address is used as
  2672. // parameter passed into Save() call below. So this variable can't be
  2673. // destroyed before the save() is called.
  2674. BOOL fSuppressAPP0 = TRUE;
  2675. if (fSpecialJPEG == TRUE)
  2676. {
  2677. // We are in a situation that the caller asks us to do a lossless
  2678. // transformation. Due to the size limitation, we have to
  2679. // transform it in memory.
  2680. // Since it is not correct to save APP0 in a Exif file. So we check
  2681. // if the source is Exif, then we suppress APP0 header
  2682. int cParams = 1;
  2683. pNewParam = (EncoderParameters*)GpMalloc(
  2684. sizeof(EncoderParameters) +
  2685. cParams * sizeof(EncoderParameter));
  2686. if (pNewParam)
  2687. {
  2688. // Set the Suppress APP0 parameter
  2689. pNewParam->Parameter[cParams - 1].Guid = ENCODER_SUPPRESSAPP0;
  2690. pNewParam->Parameter[cParams - 1].NumberOfValues = 1;
  2691. pNewParam->Parameter[cParams - 1].Type = TAG_TYPE_BYTE;
  2692. pNewParam->Parameter[cParams - 1].Value = (VOID*)&fSuppressAPP0;
  2693. pNewParam->Count = cParams;
  2694. // Set the flag to TRUE so that we can free it later
  2695. fFreeExtraParamBlock = TRUE;
  2696. // Handle thumbnail transformation if it is lossless
  2697. // transformation
  2698. if (rfType != RotateNoneFlipNone)
  2699. {
  2700. status = TransformThumbanil(
  2701. clsidEncoder,
  2702. pEncoderParams,
  2703. &pSrcItem
  2704. );
  2705. if (Ok == status)
  2706. {
  2707. fNeedToRestoreThumb = TRUE;
  2708. }
  2709. }
  2710. }
  2711. else
  2712. {
  2713. status = OutOfMemory;
  2714. }
  2715. }// Special JPEG case
  2716. if (SUCCEEDED(hr) && (Ok == status))
  2717. {
  2718. // Determine how should we pass the GpDecodedImage pointer down to
  2719. // the save() call. If we are handling special lossless transform,
  2720. // we know that we have RotateFlip() the image in memory, so we
  2721. // should not pass any GpDecodedImage info down, just pass NULL.
  2722. // Otherwise, pass the pointer to GpDecodedImage down.
  2723. GpDecodedImage *pSrc = Img;
  2724. if (SpecialJPEGSave == TRUE)
  2725. {
  2726. pSrc = NULL;
  2727. }
  2728. if (stream)
  2729. {
  2730. hr = Bmp->SaveToStream(
  2731. stream,
  2732. clsidEncoder,
  2733. pNewParam,
  2734. fSpecialJPEG,
  2735. &EncoderPtr,
  2736. pSrc
  2737. );
  2738. }
  2739. else if (filename)
  2740. {
  2741. hr = Bmp->SaveToFile(
  2742. filename,
  2743. clsidEncoder,
  2744. pNewParam,
  2745. fSpecialJPEG,
  2746. &EncoderPtr,
  2747. pSrc
  2748. );
  2749. }
  2750. else
  2751. {
  2752. // This should not happen that both stream and filename are NULL
  2753. hr = E_FAIL;
  2754. }
  2755. }
  2756. // When we handle the special lossless transform request, we rotate/flip
  2757. // the image in memory. The Img pointer should be released when
  2758. // RotateFlip() is done. But we couldn't do that since Save() function
  2759. // in JPEG encoder needs to get all the private APP headers from the
  2760. // source image. So we delay the release for the Img pointer until the
  2761. // save() is done.
  2762. if (Img && (SpecialJPEGSave == TRUE))
  2763. {
  2764. Img->Release();
  2765. Img = NULL;
  2766. SpecialJPEGSave = FALSE;
  2767. }
  2768. if (fFreeExtraParamBlock && pNewParam)
  2769. {
  2770. GpFree(pNewParam);
  2771. }
  2772. }
  2773. if ((TRUE == fNeedToRestoreThumb) && pSrcItem)
  2774. {
  2775. // If pSrcIetm is not NULL, it means we have transformed the thumbnail
  2776. // of current image. Restore the original thumbnail info
  2777. status = SetPropertyItem(pSrcItem);
  2778. GpFree(pSrcItem);
  2779. }
  2780. if (FAILED(hr))
  2781. {
  2782. // If SaveToFile/Stream() filed, we should terminate the encoder
  2783. // immediately.
  2784. // We don't need to check if it is multi-frame save or not.
  2785. TerminateEncoder();
  2786. return MapHRESULTToGpStatus(hr);
  2787. }
  2788. // If it is a single frame save OP, close the encoder
  2789. if (fMultiFrameSave == FALSE)
  2790. {
  2791. TerminateEncoder();
  2792. }
  2793. else
  2794. {
  2795. // The caller set the multi-frame save flag in encoder parameter. But
  2796. // we still need to check if the encoder really supports it. If not,
  2797. // the encoder will be closed in ValidateMultiFrameSave()
  2798. ValidateMultiFrameSave();
  2799. }
  2800. return status;
  2801. }// DoSave()
  2802. /**************************************************************************\
  2803. *
  2804. * Function Description:
  2805. *
  2806. * Append current frame to current encoder object
  2807. *
  2808. * Arguments:
  2809. *
  2810. * encoderParams - Encoder parameters
  2811. *
  2812. * Return Value:
  2813. *
  2814. * Status code
  2815. *
  2816. * Revision History:
  2817. *
  2818. * 04/21/2000 minliu
  2819. * Created it.
  2820. *
  2821. \**************************************************************************/
  2822. GpStatus
  2823. CopyOnWriteBitmap::SaveAdd(
  2824. const EncoderParameters* encoderParams
  2825. )
  2826. {
  2827. // Caller has to call Save() first to establish the encoder object
  2828. if ( EncoderPtr == NULL )
  2829. {
  2830. WARNING(("CopyOnWriteBitmap::SaveAdd---Caller hasn't call Save() yet"));
  2831. return Win32Error;
  2832. }
  2833. // We don't need to check if encoderParams is NULL or not because it has
  2834. // been checked in flatapi.cpp
  2835. ASSERT(encoderParams != NULL);
  2836. ASSERT(IsValid());
  2837. BOOL bLastFrame = FALSE;
  2838. BOOL bSetFrameDimension = FALSE;
  2839. GUID tempGuid;
  2840. // Check if the caller has specified this is the last frame or a flush OP
  2841. // Also, according to spec, the caller also has to specify the type of
  2842. // dimension for next frame
  2843. for ( UINT i = 0; (i < encoderParams->Count); ++i )
  2844. {
  2845. if ( (encoderParams->Parameter[i].Guid == ENCODER_SAVE_FLAG )
  2846. &&(encoderParams->Parameter[i].Type == EncoderParameterValueTypeLong)
  2847. &&(encoderParams->Parameter[i].NumberOfValues == 1) )
  2848. {
  2849. UINT ulValue = *((UINT*)(encoderParams->Parameter[i].Value));
  2850. if ( ulValue == EncoderValueLastFrame )
  2851. {
  2852. bLastFrame = TRUE;
  2853. }
  2854. else if ( ulValue == EncoderValueFlush )
  2855. {
  2856. // The caller just wants to close the file
  2857. TerminateEncoder();
  2858. return Ok;
  2859. }
  2860. else if ( ulValue == EncoderValueFrameDimensionPage )
  2861. {
  2862. tempGuid = FRAMEDIM_PAGE;
  2863. bSetFrameDimension = TRUE;
  2864. }
  2865. else if ( ulValue == EncoderValueFrameDimensionTime )
  2866. {
  2867. tempGuid = FRAMEDIM_TIME;
  2868. bSetFrameDimension = TRUE;
  2869. }
  2870. else if ( ulValue == EncoderValueFrameDimensionResolution )
  2871. {
  2872. tempGuid = FRAMEDIM_RESOLUTION;
  2873. bSetFrameDimension = TRUE;
  2874. }
  2875. }
  2876. }// Loop all the settings
  2877. HRESULT hResult = S_OK;
  2878. GpStatus status;
  2879. if ( bSetFrameDimension == FALSE )
  2880. {
  2881. WARNING(("CopyOnWriteBitmap::SaveAdd---Caller doesn't set frame dimension"));
  2882. return InvalidParameter;
  2883. }
  2884. else
  2885. {
  2886. hResult = EncoderPtr->SetFrameDimension(&tempGuid);
  2887. if ( FAILED(hResult) )
  2888. {
  2889. return MapHRESULTToGpStatus(hResult);
  2890. }
  2891. }
  2892. // If the image has a source and it is not dirty, we let the decoder
  2893. // directly talk to the encoder
  2894. if ( (Img != NULL) && (IsDirty() == FALSE) )
  2895. {
  2896. hResult = Img->SaveAppend(encoderParams, EncoderPtr);
  2897. }
  2898. else
  2899. {
  2900. status = LoadIntoMemory();
  2901. if ( status != Ok )
  2902. {
  2903. return status;
  2904. }
  2905. hResult = Bmp->SaveAppend(encoderParams, EncoderPtr, Img);
  2906. }
  2907. if ( FAILED(hResult) )
  2908. {
  2909. return MapHRESULTToGpStatus(hResult);
  2910. }
  2911. // If it is the last frame, close the encoder
  2912. if ( bLastFrame == TRUE )
  2913. {
  2914. TerminateEncoder();
  2915. }
  2916. return Ok;
  2917. }// SaveAdd()
  2918. /**************************************************************************\
  2919. *
  2920. * Function Description:
  2921. *
  2922. * Append the bitmap object(newBits) to current encoder object
  2923. *
  2924. * Arguments:
  2925. *
  2926. * newBits-------- Image object to be appended
  2927. * encoderParams - Encoder parameters
  2928. *
  2929. * Return Value:
  2930. *
  2931. * Status code
  2932. *
  2933. * Revision History:
  2934. *
  2935. * 04/21/2000 minliu
  2936. * Created it.
  2937. *
  2938. \**************************************************************************/
  2939. GpStatus
  2940. CopyOnWriteBitmap::SaveAdd(
  2941. CopyOnWriteBitmap* newBits,
  2942. const EncoderParameters* encoderParams
  2943. )
  2944. {
  2945. // Caller has to call Save() first to establish the encoder object
  2946. if ( EncoderPtr == NULL )
  2947. {
  2948. WARNING(("CopyOnWriteBitmap::SaveAdd---Caller hasn't call Save() yet"));
  2949. return Win32Error;
  2950. }
  2951. // Note: we don't need to check if "newBits" is NULL and encoderParams is
  2952. // NULL since it has been checked in flatapi.cpp
  2953. ASSERT(newBits != NULL);
  2954. ASSERT(encoderParams != NULL);
  2955. ASSERT(IsValid());
  2956. BOOL bLastFrame = FALSE;
  2957. BOOL bSetFrameDimension = FALSE;
  2958. GUID tempGuid;
  2959. // Check if the caller has specified this is the last frame
  2960. // Also, according to spec, the caller also has to specify the type of
  2961. // dimension for next frame
  2962. for ( UINT i = 0; (i < encoderParams->Count); ++i )
  2963. {
  2964. if ( (encoderParams->Parameter[i].Guid == ENCODER_SAVE_FLAG)
  2965. &&(encoderParams->Parameter[i].Type == EncoderParameterValueTypeLong)
  2966. &&(encoderParams->Parameter[i].NumberOfValues == 1) )
  2967. {
  2968. UINT ulValue = *((UINT*)(encoderParams->Parameter[i].Value));
  2969. if ( ulValue == EncoderValueLastFrame )
  2970. {
  2971. bLastFrame = TRUE;
  2972. }
  2973. else if ( ulValue == EncoderValueFrameDimensionPage )
  2974. {
  2975. tempGuid = FRAMEDIM_PAGE;
  2976. bSetFrameDimension = TRUE;
  2977. }
  2978. else if ( ulValue == EncoderValueFrameDimensionTime )
  2979. {
  2980. tempGuid = FRAMEDIM_TIME;
  2981. bSetFrameDimension = TRUE;
  2982. }
  2983. else if ( ulValue == EncoderValueFrameDimensionResolution )
  2984. {
  2985. tempGuid = FRAMEDIM_RESOLUTION;
  2986. bSetFrameDimension = TRUE;
  2987. }
  2988. }
  2989. }// Loop all the settings
  2990. HRESULT hResult = S_OK;
  2991. if ( bSetFrameDimension == FALSE )
  2992. {
  2993. WARNING(("CopyOnWriteBitmap::SaveAdd---Caller doesn't set frame dimension"));
  2994. return InvalidParameter;
  2995. }
  2996. else
  2997. {
  2998. hResult = EncoderPtr->SetFrameDimension(&tempGuid);
  2999. if ( FAILED(hResult) )
  3000. {
  3001. return (MapHRESULTToGpStatus(hResult));
  3002. }
  3003. }
  3004. // We just need to call newBits->SaveAppend() and passing the EncoderPtr to
  3005. // it. newBits->SaveAppend() should append all the frames in the object at
  3006. // the end of the stream pointed by EncoderPtr
  3007. CopyOnWriteBitmap* newBitmap = (CopyOnWriteBitmap*)newBits;
  3008. Status rCode = newBitmap->SaveAppend(encoderParams, EncoderPtr);
  3009. // If it is the last frame, close the encoder
  3010. if ( bLastFrame == TRUE )
  3011. {
  3012. TerminateEncoder();
  3013. }
  3014. return rCode;
  3015. }// SaveAdd()
  3016. /**************************************************************************\
  3017. *
  3018. * Function Description:
  3019. *
  3020. * Append current frame to the encoder object caller passed in
  3021. * Note: This function is called from another CopyOnWriteBitmap object which holds the
  3022. * encoder object. It asks current frame to be appended at the end of its
  3023. * encoder object
  3024. *
  3025. * Arguments:
  3026. *
  3027. * encoderParams - Encoder parameters
  3028. * pDestEncoderPtr---Encoder object for saving this frame to
  3029. *
  3030. * Return Value:
  3031. *
  3032. * Status code
  3033. *
  3034. * Revision History:
  3035. *
  3036. * 04/21/2000 minliu
  3037. * Created it.
  3038. *
  3039. \**************************************************************************/
  3040. GpStatus
  3041. CopyOnWriteBitmap::SaveAppend(
  3042. const EncoderParameters* encoderParams,
  3043. IImageEncoder* pDestEncoderPtr
  3044. )
  3045. {
  3046. // We don't need to check if EncoderPtr is NULL since this is not a public
  3047. // function. The caller should check
  3048. ASSERT(pDestEncoderPtr != NULL);
  3049. ASSERT(IsValid());
  3050. HRESULT hResult;
  3051. GpStatus status;
  3052. // If the image has a source and it is not dirty, we let the decoder
  3053. // directly talk to the encoder
  3054. if ( (Img != NULL) && (IsDirty() == FALSE) )
  3055. {
  3056. hResult = Img->SaveAppend(encoderParams, pDestEncoderPtr);
  3057. }
  3058. else
  3059. {
  3060. status = LoadIntoMemory();
  3061. if ( status != Ok )
  3062. {
  3063. return status;
  3064. }
  3065. hResult = Bmp->SaveAppend(encoderParams, pDestEncoderPtr, Img);
  3066. }
  3067. if ( FAILED(hResult) )
  3068. {
  3069. return (MapHRESULTToGpStatus(hResult));
  3070. }
  3071. return Ok;
  3072. }// SaveAppend()
  3073. /**************************************************************************\
  3074. *
  3075. * Function Description:
  3076. *
  3077. * Make a copy of the bitmap image object
  3078. *
  3079. * Arguments:
  3080. *
  3081. * rect - Specifies the area of the bitmap to be copied
  3082. * format - Specifies the desired pixel format
  3083. *
  3084. * Return Value:
  3085. *
  3086. * Pointer to the newly copied bitmap image object
  3087. * NULL if there is an error
  3088. *
  3089. * Revision History:
  3090. *
  3091. * 06/30/2000 minliu
  3092. * Rewrote it.
  3093. *
  3094. \**************************************************************************/
  3095. CopyOnWriteBitmap*
  3096. CopyOnWriteBitmap::Clone(
  3097. const GpRect* rect,
  3098. PixelFormatID format
  3099. ) const
  3100. {
  3101. // At this stage, the state should be >= 3 for a CopyOnWriteBitmap
  3102. ASSERT(State >= 3);
  3103. // Input parameter validate
  3104. if ( (rect != NULL)
  3105. &&( (rect->X < 0)
  3106. ||(rect->Y < 0)
  3107. ||(rect->Width < 0)
  3108. ||(rect->Height < 0) ) )
  3109. {
  3110. // We can't clone negative coordinates or size
  3111. WARNING(("CopyOnWriteBitmap::Clone---invalid input rect"));
  3112. return NULL;
  3113. }
  3114. if ( (rect != NULL)
  3115. &&( ( (rect->X + rect->Width) > (INT)SrcImageInfo.Width)
  3116. ||( (rect->Y + rect->Height) > (INT)SrcImageInfo.Height) ) )
  3117. {
  3118. // We can't clone an area which is bigger than the source image
  3119. WARNING(("CopyOnWriteBitmap::Clone---invalid input rect size"));
  3120. return NULL;
  3121. }
  3122. if ( format == PixelFormatUndefined )
  3123. {
  3124. // If the caller doesn't care about the pixel format, then we clone it
  3125. // as the source image format
  3126. // Note: This is the most frequently used the scenario since we have
  3127. // Image::Clone() which doesn't take any parameters.
  3128. // And we have
  3129. // GpImage* Clone() const
  3130. // {
  3131. // return Clone(NULL, PixelFormatDontCare);
  3132. // }
  3133. format = SrcImageInfo.PixelFormat;
  3134. }
  3135. CopyOnWriteBitmap* pRetBmp = NULL;
  3136. // Flag to indicate if we need to undo the LoadIntoMemory() or not
  3137. // Note: This flag will be set to TRUE iff the current State is "DecodedImg"
  3138. // and this function does a LoadIntoMemory()
  3139. BOOL bNeedToDiscard = FALSE;
  3140. // A non-identical clone will happen if:
  3141. // 1) the caller wants clone only a portion of the source image
  3142. // 2) the dest image has a different pixel format than the current one
  3143. // A non-identical clone means the newly created image doesn't have any
  3144. // connections to the original image in terms of FileName or Stream etc.
  3145. // Note: For a non-identical clone, we don't clone the property items either
  3146. BOOL bIdenticalClone = TRUE;
  3147. if ( (rect != NULL)
  3148. &&( (rect->X != 0)
  3149. || (rect->Y != 0)
  3150. || (rect->Width != (INT)SrcImageInfo.Width)
  3151. || (rect->Height != (INT)SrcImageInfo.Height)
  3152. || (SrcImageInfo.PixelFormat != format) ) )
  3153. {
  3154. bIdenticalClone = FALSE;
  3155. }
  3156. // If the image is:
  3157. // 1) Not dirty
  3158. // 2) We have an source image
  3159. // 3) The image has been loaded into memory
  3160. //
  3161. // Then we need to throw away the memory copy. The reasons are:
  3162. // 1) Avoid the color conversion failure. One example will be: if the
  3163. // source image is 1 bpp indexed and we load it into memory at 32 PARGB
  3164. // for drawing. If we don't throw away the 32PARGB copy in memory, we
  3165. // will fail the clone() because the color conversion will fail
  3166. // 2) Keep property item intact. for example, if the image is 24 bpp with
  3167. // property items in it. But it was loaded into memory for some reason.
  3168. // If we don't throw away the memory copy here, the code below will fall
  3169. // into "else if ( State == MemBitmap )" case. Then it will call
  3170. // Bmp->Clone() to make another copy in memory. Since the source "Bmp"
  3171. // doesn't contain any property info. The cloned one won't have any
  3172. // property info either. See Windows bug#325413
  3173. // 3) If current image is "Dirty", we don't need to keep property items.
  3174. if ( (IsDirty() == FALSE)
  3175. &&(State >= MemBitmap)
  3176. &&(Img != NULL) )
  3177. {
  3178. ASSERT( Bmp != NULL )
  3179. Bmp->Release();
  3180. Bmp = NULL;
  3181. State = DecodedImg;
  3182. PixelFormatInMem = PixelFormatUndefined;
  3183. }
  3184. // We have to clone the image in memory if it is not an identical clone.
  3185. // So if the image hasn't been loaded into memory yet, load it
  3186. if ( (State == DecodedImg)
  3187. &&(FALSE == bIdenticalClone) )
  3188. {
  3189. // Note: Due to some general pixel format conversion limitation in the
  3190. // whole Engine, we try to avoid doing LoadIntoMemory(). Hopefully this
  3191. // will be fixed sometime later. So I add a !!!TODO {minliu} here.
  3192. // But for now, we have to load the current image into memory with the
  3193. // desired pixel format and throw it away when we are done.
  3194. if ( LoadIntoMemory(format) != Ok )
  3195. {
  3196. WARNING(("CopyOnWriteBitmap::Clone---LoadIntoMemory() failed"));
  3197. return NULL;
  3198. }
  3199. bNeedToDiscard = TRUE;
  3200. }
  3201. // Do clone according to the current Image State
  3202. if ( State == DecodedImg )
  3203. {
  3204. // Current source image hasn't been loaded and the caller wants to
  3205. // clone the WHOLE image
  3206. // Note: there are only two ways to construct a CopyOnWriteBitmap object
  3207. // and with the State = DecodedImg: CopyOnWriteBitmap(IStream*) and
  3208. // CopyOnWriteBitmap(WCHAR*). So what we need to do is to create a
  3209. // CopyOnWriteBitmap object by calling the same constructor
  3210. if ( this->Filename != NULL )
  3211. {
  3212. pRetBmp = new CopyOnWriteBitmap(this->Filename);
  3213. if ( pRetBmp == NULL )
  3214. {
  3215. WARNING(("CopyOnWrite::Clone--new CopyOnWriteBitmap() failed"));
  3216. return NULL;
  3217. }
  3218. }
  3219. else if ( this->Stream != NULL )
  3220. {
  3221. pRetBmp = new CopyOnWriteBitmap(this->Stream);
  3222. if ( pRetBmp == NULL )
  3223. {
  3224. WARNING(("CopyOnWrite::Clone--new CopyOnWriteBitmap() failed"));
  3225. return NULL;
  3226. }
  3227. }
  3228. }// State == DecodedImg
  3229. else if ( State == MemBitmap )
  3230. {
  3231. // Current source image has already been loaded into memory
  3232. // Note: the above checking (State == MemBitmap) might not be necessary.
  3233. // But we leave it here just to prevent someone adds another state in
  3234. // the State enum later.
  3235. IBitmapImage* newbmp = NULL;
  3236. HRESULT hResult;
  3237. if ( rect == NULL )
  3238. {
  3239. hResult = Bmp->Clone(NULL, &newbmp, bIdenticalClone);
  3240. }
  3241. else
  3242. {
  3243. RECT r =
  3244. {
  3245. rect->X,
  3246. rect->Y,
  3247. rect->GetRight(),
  3248. rect->GetBottom()
  3249. };
  3250. hResult = Bmp->Clone(&r, &newbmp, bIdenticalClone);
  3251. }
  3252. if ( FAILED(hResult) )
  3253. {
  3254. WARNING(("CopyOnWriteBitmap::Clone---Bmp->clone() failed"));
  3255. goto cleanup;
  3256. }
  3257. // !!! TODO
  3258. // We assume that IBitmapImage is the very first
  3259. // interface implemented by GpMemoryBitmap class.
  3260. pRetBmp = new CopyOnWriteBitmap((GpMemoryBitmap*)newbmp);
  3261. if ( pRetBmp == NULL )
  3262. {
  3263. WARNING(("CopyOnWriteBmp::Clone---new CopyOnWriteBitmap() failed"));
  3264. newbmp->Release();
  3265. goto cleanup;
  3266. }
  3267. // Clone the source info as well if it is an identical clone
  3268. if ( TRUE == bIdenticalClone )
  3269. {
  3270. if ( this->Filename != NULL )
  3271. {
  3272. pRetBmp->Filename = UnicodeStringDuplicate(this->Filename);
  3273. }
  3274. else if ( this->Stream != NULL )
  3275. {
  3276. pRetBmp->Stream = this->Stream;
  3277. pRetBmp->Stream->AddRef();
  3278. }
  3279. }
  3280. // Make sure clone has requested format. The reason we need to do this
  3281. // is because the source image might have different pixel format as the
  3282. // caller wants. This would be caused someone already did an
  3283. // LoadIntoMemory() call on current object before this clone() is called
  3284. PixelFormatID formatRetbmp;
  3285. GpStatus status = pRetBmp->GetPixelFormatID(&formatRetbmp);
  3286. if ( (status == Ok) && (format != formatRetbmp) )
  3287. {
  3288. status = pRetBmp->ConvertFormat(format, NULL, NULL);
  3289. }
  3290. if ( status != Ok )
  3291. {
  3292. WARNING(("CopyOnWrite:Clone-GetPixelFormatID() or Convert failed"));
  3293. pRetBmp->Dispose();
  3294. pRetBmp = NULL;
  3295. }
  3296. }// State == MemBitmap
  3297. cleanup:
  3298. if ( bNeedToDiscard == TRUE )
  3299. {
  3300. // Throw away the memory bits we loaded in this function and restore
  3301. // the State
  3302. if ( Bmp != NULL )
  3303. {
  3304. Bmp->Release();
  3305. Bmp = NULL;
  3306. State = DecodedImg;
  3307. }
  3308. }
  3309. // We need to check if the result of the clone is valid or not. If it is
  3310. // not valid, we should return a NULL pointer
  3311. if ( (pRetBmp != NULL) && (!pRetBmp->IsValid()) )
  3312. {
  3313. pRetBmp->Dispose();
  3314. pRetBmp = NULL;
  3315. }
  3316. if (pRetBmp)
  3317. {
  3318. // copy internal state into the new CopyOnWriteBitmap.
  3319. pRetBmp->ICMConvert = ICMConvert;
  3320. }
  3321. return pRetBmp;
  3322. }// Clone()
  3323. /**************************************************************************\
  3324. *
  3325. * Function Description:
  3326. *
  3327. * Set the palette for this bitmap
  3328. *
  3329. * Arguments:
  3330. *
  3331. * OUT palette - contains the palette.
  3332. *
  3333. * Return Value:
  3334. *
  3335. * Status code
  3336. *
  3337. \**************************************************************************/
  3338. GpStatus
  3339. CopyOnWriteBitmap::SetPalette(
  3340. ColorPalette *palette
  3341. )
  3342. {
  3343. ASSERT(IsValid());
  3344. GpStatus status;
  3345. switch(State) {
  3346. case ImageRef:
  3347. case ExtStream:
  3348. status = DereferenceStream();
  3349. if(status != Ok) { return status; }
  3350. // Put the image in at least DecodedImg state and
  3351. // fallthrough
  3352. case DecodedImg:
  3353. // Get the info from the encoded image without forcing the codec
  3354. // to decode the entire thing.
  3355. // !!! TODO: Actually we don't yet have a way of setting the palette
  3356. // directly from the codec.
  3357. status = LoadIntoMemory(PIXFMT_DONTCARE);
  3358. // Load into memory failed? Return the error code.
  3359. if(status != Ok) { return status; }
  3360. // !!! break; Fallthrough for now - till we get the codec query implemented
  3361. case MemBitmap:
  3362. {
  3363. // We're already fully decoded, just set the information.
  3364. HRESULT hr = Bmp->SetPalette(palette);
  3365. // Did we fail to set the palette?
  3366. if(hr != S_OK)
  3367. {
  3368. return GenericError;
  3369. }
  3370. }
  3371. break;
  3372. default:
  3373. // All image states need to be handled above.
  3374. // If we get in here, we have a CopyOnWriteBitmap in an invalid state or
  3375. // someone added a new state and needs to update the switch above.
  3376. ASSERT(FALSE);
  3377. return InvalidParameter;
  3378. }
  3379. return Ok;
  3380. }
  3381. /**************************************************************************\
  3382. *
  3383. * Function Description:
  3384. *
  3385. * Get the palette for this bitmap
  3386. *
  3387. * Arguments:
  3388. *
  3389. * OUT palette - contains the palette.
  3390. *
  3391. * Return Value:
  3392. *
  3393. * Status code
  3394. *
  3395. \**************************************************************************/
  3396. GpStatus
  3397. CopyOnWriteBitmap::GetPalette(
  3398. ColorPalette *palette,
  3399. INT size
  3400. )
  3401. {
  3402. ASSERT(IsValid());
  3403. ASSERT(palette != NULL); // need a buffer to store the data in.
  3404. if ( size < sizeof(ColorPalette) )
  3405. {
  3406. return InvalidParameter;
  3407. }
  3408. GpStatus status;
  3409. switch(State) {
  3410. case ImageRef:
  3411. case ExtStream:
  3412. status = DereferenceStream();
  3413. if(status != Ok) { return status; }
  3414. // Put the image in at least DecodedImg state and
  3415. // fallthrough
  3416. case DecodedImg:
  3417. // Get the info from the encoded image without forcing the codec
  3418. // to decode the entire thing.
  3419. // !!! TODO: Actually we don't yet have a way of getting the palette
  3420. // directly from the codec.
  3421. status = LoadIntoMemory(PIXFMT_DONTCARE);
  3422. // Load into memory failed? Return the error code.
  3423. if(status != Ok) { return status; }
  3424. // !!! break; Fallthrough for now - till we get the codec query implemented
  3425. case MemBitmap:
  3426. {
  3427. // We're already fully decoded, just get the information.
  3428. const ColorPalette *pal = Bmp->GetCurrentPalette();
  3429. if(pal)
  3430. {
  3431. // Make sure the size is correct.
  3432. if(size != (INT) (sizeof(ColorPalette)+(pal->Count-1)*sizeof(ARGB)) )
  3433. {
  3434. return InvalidParameter;
  3435. }
  3436. // Copy the palette into the user buffer.
  3437. GpMemcpy(palette, pal, sizeof(ColorPalette)+(pal->Count-1)*sizeof(ARGB));
  3438. }
  3439. else
  3440. {
  3441. // If there is no palette, we need to properly set the
  3442. // ColorPalette structure.
  3443. palette->Count = 0;
  3444. }
  3445. }
  3446. break;
  3447. default:
  3448. // All image states need to be handled above.
  3449. // If we get in here, we have a CopyOnWriteBitmap in an invalid state or
  3450. // someone added a new state and needs to update the switch above.
  3451. ASSERT(FALSE);
  3452. return InvalidParameter;
  3453. }
  3454. return Ok;
  3455. }
  3456. /**************************************************************************\
  3457. *
  3458. * Function Description:
  3459. *
  3460. * Returns the size, in bytes, needed for holding a palette for this bitmap
  3461. *
  3462. * Arguments:
  3463. *
  3464. * Return Value:
  3465. *
  3466. * The size, in bytes. Return 0 if there is no palette or something is wrong
  3467. *
  3468. * Note: should return -1 for something wrong.
  3469. *
  3470. \**************************************************************************/
  3471. INT
  3472. CopyOnWriteBitmap::GetPaletteSize(
  3473. )
  3474. {
  3475. ASSERT(IsValid());
  3476. GpStatus status;
  3477. switch(State)
  3478. {
  3479. case ImageRef:
  3480. case ExtStream:
  3481. status = DereferenceStream();
  3482. if(status != Ok)
  3483. {
  3484. return 0;
  3485. }
  3486. // Put the image in at least DecodedImg state and
  3487. // fallthrough
  3488. case DecodedImg:
  3489. // Get the info from the encoded image without forcing the codec
  3490. // to decode the entire thing.
  3491. // !!! TODO: Actually we don't yet have a way of getting the palette
  3492. // directly from the codec.
  3493. status = LoadIntoMemory(PIXFMT_DONTCARE);
  3494. // Load into memory failed? Return a zero palette size.
  3495. if ( status != Ok )
  3496. {
  3497. return 0;
  3498. }
  3499. // !!! break; Fallthrough for now - till we get the codec query implemented
  3500. case MemBitmap:
  3501. {
  3502. // We're already fully decoded, just get the information.
  3503. const ColorPalette *pal = Bmp->GetCurrentPalette();
  3504. // Extract the size.
  3505. if(pal)
  3506. {
  3507. return (sizeof(ColorPalette)+(pal->Count-1)*sizeof(ARGB));
  3508. }
  3509. else
  3510. {
  3511. // Note: if the image doesn't have a palette, we should still
  3512. // return at least the size of a ColorPalette, not zero here.
  3513. // The reason is to prevent some bad app which can cause GDI+'s
  3514. // GetPalette() to AV, see bug#372163
  3515. return sizeof(ColorPalette);
  3516. }
  3517. }
  3518. break;
  3519. default:
  3520. // All image states need to be handled above.
  3521. // If we get in here, we have a CopyOnWriteBitmap in an invalid state or
  3522. // someone added a new state and needs to update the switch above.
  3523. ASSERT(FALSE);
  3524. return 0;
  3525. }
  3526. return 0;
  3527. }
  3528. /**************************************************************************\
  3529. *
  3530. * Function Description:
  3531. *
  3532. * Returns total number of frames in the bitmap image
  3533. *
  3534. * Arguments:
  3535. *
  3536. * dimensionID - Dimension GUID the caller wants to query the count
  3537. * count - Total number of frames under specified dimension
  3538. *
  3539. * Return Value:
  3540. *
  3541. * Status code
  3542. *
  3543. * Revision History:
  3544. *
  3545. * 11/19/1999 minliu
  3546. * Created it.
  3547. *
  3548. \**************************************************************************/
  3549. GpStatus
  3550. CopyOnWriteBitmap::GetFrameCount(
  3551. const GUID* dimensionID,
  3552. UINT* count
  3553. ) const
  3554. {
  3555. ASSERT(IsValid());
  3556. if ( Img == NULL )
  3557. {
  3558. // This CopyOnWriteBitmap is not created from a source image. It doesn't
  3559. // have source Stream, nor source file name. It might be created
  3560. // from a BITMAPINFO structure or a memory bitmap. But anyway, it has
  3561. // one frame. So we return 1 here.
  3562. *count = 1;
  3563. return Ok;
  3564. }
  3565. HRESULT hResult = Img->GetFrameCount(dimensionID, count);
  3566. if ( hResult == E_NOTIMPL )
  3567. {
  3568. return NotImplemented;
  3569. }
  3570. else if ( hResult != S_OK )
  3571. {
  3572. return Win32Error;
  3573. }
  3574. return Ok;
  3575. }// GetFrameCount()
  3576. /**************************************************************************\
  3577. *
  3578. * Function Description:
  3579. *
  3580. * Get the total number of dimensions the image supports
  3581. *
  3582. * Arguments:
  3583. *
  3584. * count -- number of dimensions this image format supports
  3585. *
  3586. * Return Value:
  3587. *
  3588. * Status code
  3589. *
  3590. * Revision History:
  3591. *
  3592. * 03/20/2000 minliu
  3593. * Created it.
  3594. *
  3595. \**************************************************************************/
  3596. GpStatus
  3597. CopyOnWriteBitmap::GetFrameDimensionsCount(
  3598. UINT* count
  3599. ) const
  3600. {
  3601. ASSERT(IsValid());
  3602. if ( count == NULL )
  3603. {
  3604. return InvalidParameter;
  3605. }
  3606. if ( Img == NULL )
  3607. {
  3608. // This CopyOnWriteBitmap is not created from a source image. It doesn't
  3609. // have source Stream, nor source file name. It might be created
  3610. // from a BITMAPINFO structure or a memory bitmap. But anyway, it has
  3611. // one PAGE frame. So we set the return values accordingly.
  3612. *count = 1;
  3613. return Ok;
  3614. }
  3615. // Ask the lower level codec to give us the answer
  3616. HRESULT hResult = Img->GetFrameDimensionsCount(count);
  3617. if ( hResult == E_NOTIMPL )
  3618. {
  3619. return NotImplemented;
  3620. }
  3621. else if ( hResult != S_OK )
  3622. {
  3623. return Win32Error;
  3624. }
  3625. return Ok;
  3626. }// GetFrameDimensionsCount()
  3627. /**************************************************************************\
  3628. *
  3629. * Function Description:
  3630. *
  3631. * Get an ID list of dimensions the image supports
  3632. *
  3633. * Arguments:
  3634. *
  3635. * dimensionIDs---Memory buffer to hold the result ID list
  3636. * count -- number of dimensions this image format supports
  3637. *
  3638. * Return Value:
  3639. *
  3640. * Status code
  3641. *
  3642. * Revision History:
  3643. *
  3644. * 03/20/2000 minliu
  3645. * Created it.
  3646. *
  3647. \**************************************************************************/
  3648. GpStatus
  3649. CopyOnWriteBitmap::GetFrameDimensionsList(
  3650. GUID* dimensionIDs,
  3651. UINT count
  3652. ) const
  3653. {
  3654. ASSERT(IsValid());
  3655. if ( dimensionIDs == NULL )
  3656. {
  3657. return InvalidParameter;
  3658. }
  3659. if ( Img == NULL )
  3660. {
  3661. // This CopyOnWriteBitmap is not created from a source image. It doesn't
  3662. // have source Stream, nor source file name. It might be created
  3663. // from a BITMAPINFO structure or a memory bitmap. But anyway, it has
  3664. // one PAGE frame. So we set the return values accordingly.
  3665. // Note: in this case, the "count" has to be 1
  3666. if ( count == 1 )
  3667. {
  3668. dimensionIDs[0] = FRAMEDIM_PAGE;
  3669. return Ok;
  3670. }
  3671. else
  3672. {
  3673. return InvalidParameter;
  3674. }
  3675. }
  3676. // Ask the lower level codec to give us the answer
  3677. HRESULT hResult = Img->GetFrameDimensionsList(dimensionIDs, count);
  3678. if ( hResult == E_NOTIMPL )
  3679. {
  3680. return NotImplemented;
  3681. }
  3682. else if ( hResult != S_OK )
  3683. {
  3684. return Win32Error;
  3685. }
  3686. return Ok;
  3687. }// GetFrameDimensionsList()
  3688. /**************************************************************************\
  3689. *
  3690. * Function Description:
  3691. *
  3692. * Select active frame in a bitmap image
  3693. *
  3694. * Arguments:
  3695. *
  3696. * dimensionID - dimension GUID used to specify which dimention you want to
  3697. * set the active frame, PAGE, TIMER, RESOLUTION
  3698. * frameIndex -- Index number of the frame you want to set
  3699. *
  3700. * Return Value:
  3701. *
  3702. * Status code
  3703. *
  3704. * Revision History:
  3705. *
  3706. * 11/19/1999 minliu
  3707. * Created it.
  3708. *
  3709. \**************************************************************************/
  3710. GpStatus
  3711. CopyOnWriteBitmap::SelectActiveFrame(
  3712. const GUID* dimensionID,
  3713. UINT frameIndex
  3714. )
  3715. {
  3716. ASSERT(IsValid());
  3717. if ( frameIndex == CurrentFrameIndex )
  3718. {
  3719. // We are already at the required frame. Do nothing
  3720. return Ok;
  3721. }
  3722. // Cannot move onto another frame if the current bits is locked
  3723. if ( ObjRefCount > 1 )
  3724. {
  3725. return WrongState;
  3726. }
  3727. // Set active frame to caller asks for
  3728. // Note: we don't need to validate the "frameIndex" range since the lower
  3729. // level will return fail if the page number if not correct. By doing this
  3730. // way, we avoid remembering the total number of frames in an image
  3731. HRESULT hResult = S_OK;
  3732. if ( Img == NULL )
  3733. {
  3734. // Try to create a GpDecodedImage*
  3735. if ( NULL != Stream )
  3736. {
  3737. hResult = GpDecodedImage::CreateFromStream(Stream, &Img);
  3738. }
  3739. else if ( NULL != Filename )
  3740. {
  3741. hResult = GpDecodedImage::CreateFromFile(Filename, &Img);
  3742. }
  3743. else
  3744. {
  3745. // This CopyOnWriteBitmap is not created from a source image. It
  3746. // might be created from a BITMAPINFO structure or a memory bitmap.
  3747. // But anyway, the caller is allowed to call this function though it
  3748. // is just a NO-OP.
  3749. return Ok;
  3750. }
  3751. if ( FAILED(hResult) )
  3752. {
  3753. WARNING(("CopyOnWriteBitmap::SelectActiveFrame-Create Img failed"));
  3754. return Win32Error;
  3755. }
  3756. }
  3757. hResult = Img->SelectActiveFrame(dimensionID, frameIndex);
  3758. if ( hResult == E_NOTIMPL )
  3759. {
  3760. return NotImplemented;
  3761. }
  3762. else if ( hResult != S_OK )
  3763. {
  3764. WARNING(("Bitmap::SelectActiveFrame--Img->SelectActiveFrame() failed"));
  3765. return Win32Error;
  3766. }
  3767. // Get the image info of the new frame
  3768. // Note: we can't overwrite our "SrcImageInfo" for now until all the OPs
  3769. // are successful
  3770. ImageInfo tempImageInfo;
  3771. hResult = Img->GetImageInfo(&tempImageInfo);
  3772. if ( FAILED(hResult) )
  3773. {
  3774. return Win32Error;
  3775. }
  3776. // Create a temporary memory bitmap for the active frame.
  3777. // Note: we can't release Bmp first and stick &Bmp in the call because
  3778. // this call might fail. We don't want to lose the original if this happens
  3779. GpMemoryBitmap* newbmp;
  3780. hResult = GpMemoryBitmap::CreateFromImage(Img,
  3781. 0,
  3782. 0,
  3783. tempImageInfo.PixelFormat,
  3784. InterpolationHintDefault,
  3785. &newbmp,
  3786. NULL,
  3787. NULL);
  3788. if ( FAILED(hResult) )
  3789. {
  3790. return Win32Error;
  3791. }
  3792. // We can release the old one if there is one since we got the new frame
  3793. // successfully
  3794. // Note: it is possible there is no any old one because we haven't load the
  3795. // image into memory yet (Bmp == NULL)
  3796. if ( Bmp != NULL )
  3797. {
  3798. Bmp->Release();
  3799. }
  3800. Bmp = newbmp;
  3801. State = MemBitmap;
  3802. // Remember the image info of the source image and the pixel format in the
  3803. // memory. They are the same at this moment
  3804. GpMemcpy(&SrcImageInfo, &tempImageInfo, sizeof(ImageInfo));
  3805. PixelFormatInMem = SrcImageInfo.PixelFormat;
  3806. // Remember current frame index number
  3807. CurrentFrameIndex = frameIndex;
  3808. return Ok;
  3809. }// SelectActiveFrame()
  3810. /**************************************************************************\
  3811. *
  3812. * Function Description:
  3813. *
  3814. * Get the count of property items in the image
  3815. *
  3816. * Arguments:
  3817. *
  3818. * [OUT]numOfProperty - The number of property items in the image
  3819. *
  3820. * Return Value:
  3821. *
  3822. * Status code
  3823. *
  3824. * Revision History:
  3825. *
  3826. * 02/28/2000 minliu
  3827. * Created it.
  3828. *
  3829. \**************************************************************************/
  3830. GpStatus
  3831. CopyOnWriteBitmap::GetPropertyCount(
  3832. UINT* numOfProperty
  3833. )
  3834. {
  3835. ASSERT(IsValid());
  3836. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  3837. // is not created from a source image.It might be created from a BITMAPINFO
  3838. // structure or a memory bitmap.
  3839. HRESULT hResult = S_OK;
  3840. if ( Img != NULL )
  3841. {
  3842. hResult = Img->GetPropertyCount(numOfProperty);
  3843. }
  3844. else
  3845. {
  3846. ASSERT(Bmp != NULL);
  3847. hResult = Bmp->GetPropertyCount(numOfProperty);
  3848. }
  3849. return MapHRESULTToGpStatus(hResult);
  3850. }// GetPropertyCount()
  3851. /**************************************************************************\
  3852. *
  3853. * Function Description:
  3854. *
  3855. * Get a list of property IDs for all the property items in the image
  3856. *
  3857. * Arguments:
  3858. *
  3859. * [IN] numOfProperty - The number of property items in the image
  3860. * [OUT] list----------- A memory buffer the caller provided for storing the
  3861. * ID list
  3862. *
  3863. * Return Value:
  3864. *
  3865. * Status code
  3866. *
  3867. * Revision History:
  3868. *
  3869. * 02/28/2000 minliu
  3870. * Created it.
  3871. *
  3872. \**************************************************************************/
  3873. GpStatus
  3874. CopyOnWriteBitmap::GetPropertyIdList(
  3875. IN UINT numOfProperty,
  3876. IN OUT PROPID* list
  3877. )
  3878. {
  3879. ASSERT(IsValid());
  3880. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  3881. // is not created from a source image.It might be created from a BITMAPINFO
  3882. // structure or a memory bitmap.
  3883. HRESULT hResult = S_OK;
  3884. if ( Img != NULL )
  3885. {
  3886. hResult = Img->GetPropertyIdList(numOfProperty, list);
  3887. }
  3888. else
  3889. {
  3890. ASSERT(Bmp != NULL);
  3891. hResult = Bmp->GetPropertyIdList(numOfProperty, list);
  3892. }
  3893. return MapHRESULTToGpStatus(hResult);
  3894. }// GetPropertyIdList()
  3895. /**************************************************************************\
  3896. *
  3897. * Function Description:
  3898. *
  3899. * Get the size, in bytes, of a specific property item, specified by the
  3900. * property ID
  3901. *
  3902. * Arguments:
  3903. *
  3904. * [IN]propId - The ID of a property item caller is interested
  3905. * [OUT]size--- Size of this property, in bytes
  3906. *
  3907. * Return Value:
  3908. *
  3909. * Status code
  3910. *
  3911. * Revision History:
  3912. *
  3913. * 02/28/2000 minliu
  3914. * Created it.
  3915. *
  3916. \**************************************************************************/
  3917. GpStatus
  3918. CopyOnWriteBitmap::GetPropertyItemSize(
  3919. IN PROPID propId,
  3920. OUT UINT* size
  3921. )
  3922. {
  3923. ASSERT(IsValid());
  3924. HRESULT hResult = S_OK;
  3925. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  3926. // is not created from a source image.It might be created from a BITMAPINFO
  3927. // structure or a memory bitmap.
  3928. if ( Img != NULL )
  3929. {
  3930. hResult = Img->GetPropertyItemSize(propId, size);
  3931. }
  3932. else
  3933. {
  3934. ASSERT(Bmp != NULL);
  3935. hResult = Bmp->GetPropertyItemSize(propId, size);
  3936. }
  3937. return MapHRESULTToGpStatus(hResult);
  3938. }// GetPropertyItemSize()
  3939. /**************************************************************************\
  3940. *
  3941. * Function Description:
  3942. *
  3943. * Get a specific property item, specified by the prop ID.
  3944. *
  3945. * Arguments:
  3946. *
  3947. * [IN]propId -- The ID of the property item caller is interested
  3948. * [IN]propSize- Size of the property item. The caller has allocated these
  3949. * "bytes of memory" for storing the result
  3950. * [OUT]pBuffer- A memory buffer for storing this property item
  3951. *
  3952. * Return Value:
  3953. *
  3954. * Status code
  3955. *
  3956. * Revision History:
  3957. *
  3958. * 02/28/2000 minliu
  3959. * Created it.
  3960. *
  3961. \**************************************************************************/
  3962. GpStatus
  3963. CopyOnWriteBitmap::GetPropertyItem(
  3964. IN PROPID propId,
  3965. IN UINT propSize,
  3966. IN OUT PropertyItem* pBuffer
  3967. )
  3968. {
  3969. ASSERT(IsValid());
  3970. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  3971. // is not created from a source image.It might be created from a BITMAPINFO
  3972. // structure or a memory bitmap.
  3973. HRESULT hResult = S_OK;
  3974. if ( Img != NULL )
  3975. {
  3976. hResult = Img->GetPropertyItem(propId, propSize, pBuffer);
  3977. }
  3978. else
  3979. {
  3980. ASSERT(Bmp != NULL);
  3981. hResult = Bmp->GetPropertyItem(propId, propSize, pBuffer);
  3982. }
  3983. return MapHRESULTToGpStatus(hResult);
  3984. }// GetPropertyItem()
  3985. /**************************************************************************\
  3986. *
  3987. * Function Description:
  3988. *
  3989. * Get the size of ALL property items in the image
  3990. *
  3991. * Arguments:
  3992. *
  3993. * [OUT]totalBufferSize-- Total buffer size needed, in bytes, for storing all
  3994. * property items in the image
  3995. * [OUT]numOfProperty --- The number of property items in the image
  3996. *
  3997. * Return Value:
  3998. *
  3999. * Status code
  4000. *
  4001. * Revision History:
  4002. *
  4003. * 02/28/2000 minliu
  4004. * Created it.
  4005. *
  4006. \**************************************************************************/
  4007. GpStatus
  4008. CopyOnWriteBitmap::GetPropertySize(
  4009. OUT UINT* totalBufferSize,
  4010. OUT UINT* numProperties
  4011. )
  4012. {
  4013. ASSERT(IsValid());
  4014. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  4015. // is not created from a source image.It might be created from a BITMAPINFO
  4016. // structure or a memory bitmap.
  4017. HRESULT hResult = S_OK;
  4018. if ( Img != NULL )
  4019. {
  4020. hResult = Img->GetPropertySize(totalBufferSize, numProperties);
  4021. }
  4022. else
  4023. {
  4024. ASSERT(Bmp != NULL);
  4025. hResult = Bmp->GetPropertySize(totalBufferSize, numProperties);
  4026. }
  4027. return MapHRESULTToGpStatus(hResult);
  4028. }// GetPropertySize()
  4029. /**************************************************************************\
  4030. *
  4031. * Function Description:
  4032. *
  4033. * Get ALL property items in the image
  4034. *
  4035. * Arguments:
  4036. *
  4037. * [IN]totalBufferSize-- Total buffer size, in bytes, the caller has allocated
  4038. * memory for storing all property items in the image
  4039. * [IN]numOfProperty --- The number of property items in the image
  4040. * [OUT]allItems-------- A memory buffer caller has allocated for storing all
  4041. * the property items
  4042. *
  4043. * Return Value:
  4044. *
  4045. * Status code
  4046. *
  4047. * Revision History:
  4048. *
  4049. * 02/28/2000 minliu
  4050. * Created it.
  4051. *
  4052. \**************************************************************************/
  4053. GpStatus
  4054. CopyOnWriteBitmap::GetAllPropertyItems(
  4055. IN UINT totalBufferSize,
  4056. IN UINT numProperties,
  4057. IN OUT PropertyItem* allItems
  4058. )
  4059. {
  4060. ASSERT(IsValid());
  4061. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  4062. // is not created from a source image.It might be created from a BITMAPINFO
  4063. // structure or a memory bitmap.
  4064. HRESULT hResult = S_OK;
  4065. if ( Img != NULL )
  4066. {
  4067. hResult = Img->GetAllPropertyItems(totalBufferSize, numProperties,
  4068. allItems);
  4069. }
  4070. else
  4071. {
  4072. ASSERT(Bmp != NULL);
  4073. hResult = Bmp->GetAllPropertyItems(totalBufferSize, numProperties,
  4074. allItems);
  4075. }
  4076. return MapHRESULTToGpStatus(hResult);
  4077. }// GetAllPropertyItems()
  4078. /**************************************************************************\
  4079. *
  4080. * Function Description:
  4081. *
  4082. * Remove a specific property item, specified by the prop ID.
  4083. *
  4084. * Arguments:
  4085. *
  4086. * [IN]propId -- The ID of the property item to be removed
  4087. *
  4088. * Return Value:
  4089. *
  4090. * Status code
  4091. *
  4092. * Revision History:
  4093. *
  4094. * 02/28/2000 minliu
  4095. * Created it.
  4096. *
  4097. \**************************************************************************/
  4098. GpStatus
  4099. CopyOnWriteBitmap::RemovePropertyItem(
  4100. IN PROPID propId
  4101. )
  4102. {
  4103. ASSERT(IsValid());
  4104. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  4105. // is not created from a source image.It might be created from a BITMAPINFO
  4106. // structure or a memory bitmap.
  4107. HRESULT hResult = S_OK;
  4108. if ( Img != NULL )
  4109. {
  4110. hResult = Img->RemovePropertyItem(propId);
  4111. }
  4112. else
  4113. {
  4114. ASSERT(Bmp != NULL);
  4115. hResult = Bmp->RemovePropertyItem(propId);
  4116. }
  4117. return MapHRESULTToGpStatus(hResult);
  4118. }// RemovePropertyItem()
  4119. /**************************************************************************\
  4120. *
  4121. * Function Description:
  4122. *
  4123. * Set a property item, specified by the propertyitem structure. If the item
  4124. * already exists, then its contents will be updated. Otherwise a new item
  4125. * will be added
  4126. *
  4127. * Arguments:
  4128. *
  4129. * [IN]item -- A property item the caller wants to set
  4130. *
  4131. * Return Value:
  4132. *
  4133. * Status code
  4134. *
  4135. * Revision History:
  4136. *
  4137. * 02/28/2000 minliu
  4138. * Created it.
  4139. *
  4140. \**************************************************************************/
  4141. GpStatus
  4142. CopyOnWriteBitmap::SetPropertyItem(
  4143. IN PropertyItem* item
  4144. )
  4145. {
  4146. if ( item == NULL )
  4147. {
  4148. WARNING(("CopyOnWriteBitmap::SetPropertyItem-Invalid input parameter"));
  4149. return InvalidParameter;
  4150. }
  4151. ASSERT(IsValid());
  4152. HRESULT hResult = S_OK;
  4153. // Check if we have a source image. Img is NULL means this CopyOnWriteBitmap
  4154. // is not created from a source image.It might be created from a BITMAPINFO
  4155. // structure or a memory bitmap.
  4156. // If "SpecialJPEGSave" is TRUE, it means, the image has been rotated in
  4157. // memory, but the "Img" pointer might not be released yet
  4158. if (( Img != NULL ) && (SpecialJPEGSave == FALSE))
  4159. {
  4160. hResult = Img->SetPropertyItem(*item);
  4161. }
  4162. else
  4163. {
  4164. ASSERT(Bmp != NULL);
  4165. hResult = Bmp->SetPropertyItem(*item);
  4166. }
  4167. return MapHRESULTToGpStatus(hResult);
  4168. }// SetPropertyItem()
  4169. /**************************************************************************\
  4170. *
  4171. * Function Description:
  4172. *
  4173. * Get bitmap image thumbnail
  4174. *
  4175. * Arguments:
  4176. *
  4177. * thumbWidth, thumbHeight - Desired width and height of thumbnail
  4178. * Both zero means pick a default size
  4179. *
  4180. * Return Value:
  4181. *
  4182. * Pointer to the new thumbnail image object
  4183. * NULL if there is an error
  4184. *
  4185. \**************************************************************************/
  4186. CopyOnWriteBitmap *
  4187. CopyOnWriteBitmap::GetThumbnail(
  4188. UINT thumbWidth,
  4189. UINT thumbHeight,
  4190. GetThumbnailImageAbort callback,
  4191. VOID *callbackData
  4192. )
  4193. {
  4194. ASSERT(IsValid());
  4195. HRESULT hr = S_OK;
  4196. IImage *newImage = NULL;
  4197. // Ask the lower level codec to give us the thumbnail stored in the image.
  4198. // Note: If there is no thumbnail stored in the original image, this
  4199. // function will return us a scaled version of the original image as the
  4200. // thumbnail image, at DEFAULT_THUMBNAIL_SIZE
  4201. // Note: Img might be zero, it means this CopyOnWriteBitmap is not created from an
  4202. // stream or file. It might be created from an memory buffer or something
  4203. // else. One scenario will be Do a GetThumbnail() and then do another
  4204. // GetThumbnail from this thumbnail. Though it is a weird scenario. But it
  4205. // could happen. So if the Img is NULL, then we create a thumbnail from
  4206. // the memory bitmap
  4207. if ( Img != NULL )
  4208. {
  4209. hr = Img->GetThumbnail(thumbWidth, thumbHeight, &newImage);
  4210. }
  4211. else
  4212. {
  4213. GpStatus status = LoadIntoMemory();
  4214. if ( status != Ok )
  4215. {
  4216. return NULL;
  4217. }
  4218. hr = Bmp->GetThumbnail(thumbWidth, thumbHeight, &newImage);
  4219. }
  4220. if ( FAILED(hr) )
  4221. {
  4222. return NULL;
  4223. }
  4224. // Create a GpMemoryBitmap from IImage
  4225. ImageInfo srcImageInfo;
  4226. newImage->GetImageInfo(&srcImageInfo);
  4227. GpMemoryBitmap* pMemBitmap;
  4228. hr = GpMemoryBitmap::CreateFromImage(newImage,
  4229. srcImageInfo.Width,
  4230. srcImageInfo.Height,
  4231. srcImageInfo.PixelFormat,
  4232. InterpolationHintDefault,
  4233. &pMemBitmap,
  4234. (DrawImageAbort) callback,
  4235. callbackData
  4236. );
  4237. // Release the COM obj IImage
  4238. newImage->Release();
  4239. if ( FAILED(hr) )
  4240. {
  4241. return NULL;
  4242. }
  4243. CopyOnWriteBitmap* thumbBitmap = new CopyOnWriteBitmap(pMemBitmap);
  4244. return thumbBitmap;
  4245. }
  4246. /**************************************************************************\
  4247. *
  4248. * Function Description:
  4249. *
  4250. * Access bitmap pixel data
  4251. *
  4252. * Arguments:
  4253. *
  4254. * rect - Specifies the interested image area
  4255. * NULL means the entire image
  4256. * flags - Desired access mode
  4257. * format - Desired pixel format
  4258. * bmpdata - Returns information about bitmap pixel data
  4259. * width,
  4260. * height - suggested width and height to decode to.
  4261. * zero is the source image width and height.
  4262. *
  4263. * Return Value:
  4264. *
  4265. * Status code
  4266. *
  4267. \**************************************************************************/
  4268. GpStatus
  4269. CopyOnWriteBitmap::LockBits(
  4270. const GpRect* rect,
  4271. UINT flags,
  4272. PixelFormatID format,
  4273. BitmapData* bmpdata,
  4274. INT width,
  4275. INT height
  4276. ) const
  4277. {
  4278. ASSERT(IsValid());
  4279. ASSERT(width>=0);
  4280. ASSERT(height>=0);
  4281. // LockBits cannot be nested
  4282. if ( ObjRefCount > 1 )
  4283. {
  4284. return WrongState;
  4285. }
  4286. // Do some sanity check to see if we can do it or not
  4287. if ( (format == PIXFMT_DONTCARE)
  4288. ||(!IsValidPixelFormat(format)) )
  4289. {
  4290. // Wrong pixel format
  4291. WARNING(("CopyOnWriteBitmap::LockBits---invalid format"));
  4292. return InvalidParameter;
  4293. }
  4294. // Valid format. If the lock is for READ, we need to check if we can
  4295. // convert the current source to this format
  4296. EpFormatConverter linecvt;
  4297. if ( flags & ImageLockModeRead )
  4298. {
  4299. if ( IsDirty() == FALSE )
  4300. {
  4301. if ( linecvt.CanDoConvert(SrcImageInfo.PixelFormat, format)==FALSE )
  4302. {
  4303. WARNING(("LockBits--can't convert src to specified fmt"));
  4304. return InvalidParameter;
  4305. }
  4306. }
  4307. else if (linecvt.CanDoConvert(PixelFormatInMem, format) == FALSE )
  4308. {
  4309. WARNING(("LockBits--can't convert src to specified fmt"));
  4310. return InvalidParameter;
  4311. }
  4312. }
  4313. // If the lock is for WRITE, we need to check if we can convert the format
  4314. // back to current source format. The reason we need to do this checking is
  4315. // when the user calls UnLockBits() after he has modified the locked area,
  4316. // we need to convert this small area back to the format the whole image is
  4317. // at. E.x. For an 4 bpp image, the caller can lock a small area at 32 bpp
  4318. // (this makes the app code easier), do some pixel modification on that
  4319. // area, unlock it. We need to convert that small area back to 4 bpp.
  4320. if ( flags & ImageLockModeWrite )
  4321. {
  4322. if ( IsDirty() == FALSE )
  4323. {
  4324. if ( linecvt.CanDoConvert(format, SrcImageInfo.PixelFormat)==FALSE )
  4325. {
  4326. WARNING(("LockBits--can't convert specified fmt back to src"));
  4327. return InvalidParameter;
  4328. }
  4329. }
  4330. else if (linecvt.CanDoConvert(format, PixelFormatInMem) == FALSE )
  4331. {
  4332. WARNING(("LockBits--can't convert specified format back to src"));
  4333. return InvalidParameter;
  4334. }
  4335. }
  4336. HRESULT hr;
  4337. if ( (IsDirty() == FALSE)
  4338. &&(State >= MemBitmap)
  4339. &&(format != PixelFormatInMem)
  4340. &&(SrcImageInfo.PixelFormat != PixelFormatInMem)
  4341. &&(Img != NULL) )
  4342. {
  4343. // If the image is:
  4344. // 1) Not dirty
  4345. // 2) Was loaded into memory with different color depth for some reason,
  4346. // like DrawImage()
  4347. // 3) The color depth the caller wants to locked for is different than
  4348. // the one in memory
  4349. // 4) We have an source image
  4350. //
  4351. // Then we can throw away the bits in memory and reload the bits from
  4352. // the original with the color depth user asks for. The purpose of this
  4353. // is to increase the success rate for LockBits(). One of the problem
  4354. // we are having now is that our DrawImage() always load image into
  4355. // memory at 32PARGB format. This makes tasks like printing very
  4356. // expensive because it has to send 32PARGB format to the print. We'd
  4357. // like to send the original color depth to the printer
  4358. //
  4359. // Note: this "throw away" approach won't hurt our DrawImage() work flow
  4360. // Here is the reason why: say we have a 4 bpp source image. We do a
  4361. // DrawImage() first, thus we load it into memory at 32 PARGB. When the
  4362. // printing request coming. It prefers to send down 4bpp to the printer.
  4363. // So we through away the 32 PARGB in memory and reload the image in
  4364. // 4 bpp mode and send it to printer. Later on, if DrawImage() is called
  4365. // again. It can still pass the above "if" checking condition and reload
  4366. // the image in as 32 PARGB.
  4367. ASSERT( Bmp != NULL )
  4368. Bmp->Release();
  4369. Bmp = NULL;
  4370. State = DecodedImg;
  4371. PixelFormatInMem = PixelFormatUndefined;
  4372. }
  4373. // Load the image into memory using the suggested width and height.
  4374. // if the suggested width and height are zero, use the source
  4375. // image width and height.
  4376. // Load the image into memory before querying the pixel format because
  4377. // the load could potentially change the in-memory format.
  4378. GpStatus status = LoadIntoMemory(format, NULL, NULL, width, height);
  4379. if (status != Ok)
  4380. {
  4381. WARNING(("CopyOnWriteBitmap::LockBits()----LoadIntoMemory() failed"));
  4382. return status;
  4383. }
  4384. if ( rect == NULL )
  4385. {
  4386. hr = Bmp->LockBits(NULL, flags, format, bmpdata);
  4387. }
  4388. else
  4389. {
  4390. RECT r =
  4391. {
  4392. rect->X,
  4393. rect->Y,
  4394. rect->GetRight(),
  4395. rect->GetBottom()
  4396. };
  4397. hr = Bmp->LockBits(&r, flags, format, bmpdata);
  4398. }
  4399. if ( FAILED(hr) )
  4400. {
  4401. WARNING(("CopyOnWriteBitmap::LockBits()----LockBits() failed"));
  4402. return (MapHRESULTToGpStatus(hr));
  4403. }
  4404. ObjRefCount++;
  4405. if ( flags & ImageLockModeWrite )
  4406. {
  4407. // Mark the bits dirty since the user might have changed the bits during
  4408. // the lock period
  4409. SetDirtyFlag(TRUE);
  4410. }
  4411. return Ok;
  4412. }// LockBits()
  4413. GpStatus
  4414. CopyOnWriteBitmap::UnlockBits(
  4415. BitmapData* bmpdata,
  4416. BOOL Destroy
  4417. ) const
  4418. {
  4419. ASSERT(ObjRefCount == 2);
  4420. if ( NULL == Bmp )
  4421. {
  4422. // The caller should not call UnlockBits() if it hasn't called
  4423. // LockBits() yet
  4424. WARNING(("UnlockBits---Call UnlockBits() without calling LockBits()"));
  4425. return GenericError;
  4426. }
  4427. HRESULT hr = Bmp->UnlockBits(bmpdata);
  4428. ObjRefCount--;
  4429. // Called to destroy the decoded bits because we decoded a partial image
  4430. // and it won't be valid on the next call.
  4431. if(Destroy)
  4432. {
  4433. // Revert the state back to DecodedImg (which means not decoded).
  4434. ASSERT(Img != NULL);
  4435. delete Bmp;
  4436. Bmp = NULL;
  4437. State = DecodedImg;
  4438. }
  4439. if (FAILED(hr))
  4440. {
  4441. WARNING(("GpBitmap::UnlockBits---Bmp->UnlockBits() failed"));
  4442. return (MapHRESULTToGpStatus(hr));
  4443. }
  4444. return Ok;
  4445. }// UnlockBits()
  4446. /**************************************************************************\
  4447. *
  4448. * Function Description:
  4449. *
  4450. * Get a pixel
  4451. *
  4452. * Arguments:
  4453. *
  4454. * IN x, y: Coordinates of the pixel to get.
  4455. * OUT color: color value of the specified pixel.
  4456. *
  4457. * Return Value:
  4458. *
  4459. * Status code
  4460. *
  4461. \**************************************************************************/
  4462. GpStatus
  4463. CopyOnWriteBitmap::GetPixel(INT x, INT y, ARGB *color)
  4464. {
  4465. // Get the bitmap info.
  4466. BitmapData bmpData;
  4467. // Only lock the required rectangle.
  4468. GpRect pixelRect(x, y, 1, 1);
  4469. GpStatus status = LockBits(
  4470. &pixelRect,
  4471. IMGLOCK_READ,
  4472. PIXFMT_32BPP_ARGB,
  4473. &bmpData
  4474. );
  4475. // Failed to lock the bits.
  4476. if(status != Ok)
  4477. {
  4478. return(status);
  4479. }
  4480. ARGB *pixel = static_cast<ARGB *>(bmpData.Scan0);
  4481. *color = *pixel;
  4482. return UnlockBits(&bmpData);
  4483. }
  4484. /**************************************************************************\
  4485. *
  4486. * Function Description:
  4487. *
  4488. * Set a pixel
  4489. *
  4490. * Arguments:
  4491. *
  4492. * IN x, y: Coordinates of the pixel to set.
  4493. * IN color: color value for the specified pixel.
  4494. *
  4495. * Return Value:
  4496. *
  4497. * Status code
  4498. *
  4499. \**************************************************************************/
  4500. GpStatus
  4501. CopyOnWriteBitmap::SetPixel(INT x, INT y, ARGB color)
  4502. {
  4503. // Get the bitmap info.
  4504. BitmapData bmpData;
  4505. // Only lock the required rectangle.
  4506. GpRect pixelRect(x, y, 1, 1);
  4507. GpStatus status = LockBits(
  4508. &pixelRect,
  4509. IMGLOCK_WRITE,
  4510. PIXFMT_32BPP_ARGB,
  4511. &bmpData
  4512. );
  4513. // Failed to lock the bits.
  4514. if(status != Ok)
  4515. {
  4516. return(status);
  4517. }
  4518. ARGB* pixel = static_cast<ARGB *>(bmpData.Scan0);
  4519. *pixel = color;
  4520. return UnlockBits(&bmpData);
  4521. }
  4522. /**************************************************************************\
  4523. *
  4524. * Function Description:
  4525. *
  4526. * Convert bitmap image to a different pixel format
  4527. *
  4528. * Arguments:
  4529. *
  4530. * format - Specifies the new pixel format
  4531. *
  4532. * Return Value:
  4533. *
  4534. * Status code
  4535. *
  4536. \**************************************************************************/
  4537. GpStatus
  4538. CopyOnWriteBitmap::ConvertFormat(
  4539. PixelFormatID format,
  4540. DrawImageAbort callback,
  4541. VOID *callbackData
  4542. )
  4543. {
  4544. ASSERT(ObjRefCount == 1);
  4545. // If bitmap not in memory yet, simply force load using specified format:
  4546. if ( State < MemBitmap )
  4547. {
  4548. return LoadIntoMemory(format, callback, callbackData);
  4549. }
  4550. HRESULT hr;
  4551. if ( PixelFormatInMem != format)
  4552. {
  4553. GpMemoryBitmap* newbmp;
  4554. hr = GpMemoryBitmap::CreateFromImage(
  4555. Bmp,
  4556. 0,
  4557. 0,
  4558. format,
  4559. InterpolationHintDefault,
  4560. &newbmp,
  4561. callback,
  4562. callbackData);
  4563. if ( FAILED(hr) )
  4564. {
  4565. WARNING(("CopyOnWriteBitmap::ConvertFormat---CreateFromImage() failed"));
  4566. return OutOfMemory;
  4567. }
  4568. Bmp->Release();
  4569. Bmp = newbmp;
  4570. PixelFormatInMem = format;
  4571. // We change the source pixel format info as well because this image
  4572. // is dirty now and we should not convert it back to original format
  4573. SrcImageInfo.PixelFormat = format;
  4574. // Mark the bits dirty since the original image bits got changed
  4575. // !!! TODO: we can't set it dirty for now because DrawImage() always
  4576. // convert an image to 32 bpp first. When this temporary solution is removed
  4577. // we should reset this flag
  4578. //
  4579. // SetDirtyFlag(TRUE);
  4580. }
  4581. return Ok;
  4582. }
  4583. /**************************************************************************\
  4584. *
  4585. * Function Description:
  4586. *
  4587. * Derive a graphics context on top of the bitmap object
  4588. *
  4589. * Arguments:
  4590. *
  4591. * NONE
  4592. *
  4593. * Return Value:
  4594. *
  4595. * Pointer to the derived graphics context
  4596. * NULL if there is an error
  4597. *
  4598. \**************************************************************************/
  4599. /******************************Public*Routine******************************\
  4600. *
  4601. * Function Description:
  4602. *
  4603. * Derive an HDC on top of the bitmap object for GDI interop
  4604. *
  4605. * Arguments:
  4606. *
  4607. * NONE
  4608. *
  4609. * Return Value:
  4610. *
  4611. * HDC with a bitmap selected into it that is associated with this GDI+
  4612. * bitmap.
  4613. * NULL if there is an error
  4614. *
  4615. \**************************************************************************/
  4616. HDC
  4617. CopyOnWriteBitmap::GetHdc()
  4618. {
  4619. HDC hdc = NULL;
  4620. HBITMAP hbm = NULL;
  4621. // Create the HDC and HBITMAP if needed.
  4622. if (InteropData.Hdc == NULL)
  4623. {
  4624. ImageInfo imageInfo;
  4625. CopyOnWriteBitmap::GetImageInfo(&imageInfo);
  4626. hdc = CreateCompatibleDC(NULL);
  4627. if (hdc == NULL)
  4628. {
  4629. goto cleanup_exit;
  4630. }
  4631. BITMAPINFO gdiBitmapInfo;
  4632. gdiBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  4633. gdiBitmapInfo.bmiHeader.biWidth = imageInfo.Width;
  4634. gdiBitmapInfo.bmiHeader.biHeight = - static_cast<LONG>
  4635. (imageInfo.Height);
  4636. gdiBitmapInfo.bmiHeader.biPlanes = 1;
  4637. gdiBitmapInfo.bmiHeader.biBitCount = 32;
  4638. gdiBitmapInfo.bmiHeader.biCompression = BI_RGB;
  4639. gdiBitmapInfo.bmiHeader.biSizeImage = 0;
  4640. gdiBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  4641. gdiBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  4642. gdiBitmapInfo.bmiHeader.biClrUsed = 0;
  4643. gdiBitmapInfo.bmiHeader.biClrImportant = 0;
  4644. hbm = CreateDIBSection(hdc,
  4645. &gdiBitmapInfo,
  4646. DIB_RGB_COLORS,
  4647. &InteropData.Bits,
  4648. NULL,
  4649. 0);
  4650. DIBSECTION gdiDibInfo;
  4651. if ((hbm == NULL) ||
  4652. (GetObjectA(hbm, sizeof(gdiDibInfo), &gdiDibInfo) == 0) ||
  4653. (gdiDibInfo.dsBmih.biSize == 0) ||
  4654. (SelectObject(hdc, hbm) == NULL))
  4655. {
  4656. goto cleanup_exit;
  4657. }
  4658. InteropData.Hdc = hdc;
  4659. InteropData.Hbm = hbm;
  4660. InteropData.Width = imageInfo.Width;
  4661. InteropData.Height = imageInfo.Height;
  4662. InteropData.Stride = gdiDibInfo.dsBm.bmWidthBytes;
  4663. // Since it's a 32bpp bitmap, we can assume that a tightly packed
  4664. // bitmap is already satisfies the scanline align constraints
  4665. // (letting us fill the bitmap with a very simple loop).
  4666. ASSERT(gdiDibInfo.dsBm.bmWidthBytes == static_cast<LONG>(imageInfo.Width * 4));
  4667. }
  4668. ASSERT(InteropData.Hdc != NULL);
  4669. // Fill the bitmap with a sentinal pattern.
  4670. {
  4671. INT count = InteropData.Width * InteropData.Height;
  4672. UINT32 *bits = static_cast<UINT32*>(InteropData.Bits);
  4673. while (count--)
  4674. {
  4675. *bits++ = GDIP_TRANSPARENT_COLOR_KEY;
  4676. }
  4677. }
  4678. return InteropData.Hdc;
  4679. cleanup_exit:
  4680. if (hdc)
  4681. DeleteDC(hdc);
  4682. if (hbm)
  4683. DeleteObject(hbm);
  4684. return reinterpret_cast<HDC>(NULL);
  4685. }
  4686. /******************************Public*Routine******************************\
  4687. *
  4688. * Function Description:
  4689. *
  4690. * Release the HDC returned by CopyOnWriteBitmap::GetHdc. If necessary, updates
  4691. * the GDI+ bitmap with the GDI drawing (may not be necessary if the
  4692. * GDI and GDI+ bitmaps share a common underlying pixel buffer).
  4693. *
  4694. * Arguments:
  4695. *
  4696. * HDC to release
  4697. *
  4698. * Return Value:
  4699. *
  4700. * Pointer to the derived graphics context
  4701. * NULL if there is an error
  4702. *
  4703. \**************************************************************************/
  4704. VOID
  4705. CopyOnWriteBitmap::ReleaseHdc(HDC hdc)
  4706. {
  4707. ASSERT(hdc == InteropData.Hdc);
  4708. GdiFlush();
  4709. // Scan the GDI bitmap to see if any of the sentinal pixels have changed.
  4710. // If any are detected, copy it to the GDI+ bitmap with opaque alpha set.
  4711. int curRow, curCol;
  4712. BYTE *interopScan = static_cast<BYTE*>(InteropData.Bits);
  4713. GpStatus status = Ok;
  4714. for (curRow = 0; (curRow < InteropData.Height) && (status == Ok); curRow++)
  4715. {
  4716. BOOL rowLocked = FALSE;
  4717. BitmapData bitmapData;
  4718. ARGB *interopPixel = static_cast<ARGB*>(static_cast<VOID*>(interopScan));
  4719. ARGB *pixel = NULL;
  4720. for (curCol = 0; curCol < InteropData.Width; curCol++)
  4721. {
  4722. if ((*interopPixel & 0x00ffffff) != GDIP_TRANSPARENT_COLOR_KEY)
  4723. {
  4724. if (!rowLocked)
  4725. {
  4726. GpRect lockRect(0, curRow, InteropData.Width, 1);
  4727. status = LockBits(&lockRect,
  4728. IMGLOCK_READ | IMGLOCK_WRITE,
  4729. PIXFMT_32BPP_ARGB,
  4730. &bitmapData);
  4731. if (status == Ok)
  4732. {
  4733. pixel = static_cast<ARGB*>(bitmapData.Scan0) + curCol;
  4734. rowLocked = TRUE;
  4735. }
  4736. else
  4737. {
  4738. break;
  4739. }
  4740. }
  4741. *pixel = *interopPixel | 0xFF000000;
  4742. }
  4743. interopPixel++;
  4744. pixel++;
  4745. }
  4746. if (rowLocked)
  4747. UnlockBits(&bitmapData);
  4748. interopScan += InteropData.Stride;
  4749. }
  4750. }
  4751. // Data flags
  4752. #define COMPRESSED_IMAGE 0x00000001
  4753. class BitmapRecordData : public ObjectTypeData
  4754. {
  4755. public:
  4756. INT32 Width;
  4757. INT32 Height;
  4758. INT32 Stride;
  4759. INT32 PixelFormat;
  4760. INT32 Flags;
  4761. };
  4762. /**************************************************************************\
  4763. *
  4764. * Function Description:
  4765. *
  4766. * Get the bitmap data.
  4767. *
  4768. * Arguments:
  4769. *
  4770. * [IN] dataBuffer - fill this buffer with the data
  4771. * [IN/OUT] size - IN - size of buffer; OUT - number bytes written
  4772. *
  4773. * Return Value:
  4774. *
  4775. * GpStatus - Ok or error code
  4776. *
  4777. * Created:
  4778. *
  4779. * 9/13/1999 DCurtis
  4780. *
  4781. \**************************************************************************/
  4782. GpStatus
  4783. CopyOnWriteBitmap::GetData(
  4784. IStream * stream
  4785. ) const
  4786. {
  4787. ASSERT(stream);
  4788. GpStatus status;
  4789. BitmapRecordData bitmapRecordData;
  4790. IStream* imageStream = NULL;
  4791. STATSTG statStg;
  4792. BOOL needRelease = FALSE;
  4793. // variables used to track the stream state
  4794. LARGE_INTEGER zero = {0,0};
  4795. LARGE_INTEGER oldPos;
  4796. BOOL isSeekableStream = FALSE;
  4797. // try to get a imageStream
  4798. if (!IsDirty())
  4799. {
  4800. HRESULT hr;
  4801. if (Stream != NULL)
  4802. {
  4803. hr = Stream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&oldPos);
  4804. if (SUCCEEDED(hr))
  4805. {
  4806. hr = Stream->Seek(zero, STREAM_SEEK_SET, NULL);
  4807. if (SUCCEEDED(hr))
  4808. {
  4809. isSeekableStream = TRUE;
  4810. imageStream = Stream;
  4811. }
  4812. }
  4813. }
  4814. // if we don't have a CopyOnWriteBitmap::Stream but we have a filename
  4815. if ((imageStream == NULL) && (Filename != NULL))
  4816. {
  4817. hr = CreateStreamOnFileForRead(Filename, &imageStream);
  4818. if (SUCCEEDED(hr))
  4819. {
  4820. needRelease = TRUE;
  4821. }
  4822. }
  4823. }
  4824. // try to write the imageStream out to the metafile Stream
  4825. if (imageStream && imageStream->Stat(&statStg, STATFLAG_NONAME) == S_OK)
  4826. {
  4827. bitmapRecordData.Type = ImageTypeBitmap;
  4828. bitmapRecordData.Width = 0;
  4829. bitmapRecordData.Height = 0;
  4830. bitmapRecordData.Stride = 0;
  4831. bitmapRecordData.PixelFormat = 0;
  4832. bitmapRecordData.Flags = COMPRESSED_IMAGE;
  4833. stream->Write(&bitmapRecordData, sizeof(bitmapRecordData), NULL);
  4834. // Read data from the imageStream into the dest stream
  4835. // Unfortunately, we can't assume that CopyTo has been implemented.
  4836. // Is there some way to find out? !!!
  4837. #define COPY_BUFFER_SIZE 2048
  4838. BYTE buffer[COPY_BUFFER_SIZE];
  4839. UINT streamSize = statStg.cbSize.LowPart;
  4840. UINT sizeToRead = COPY_BUFFER_SIZE;
  4841. UINT numPadBytes = 0;
  4842. if ((streamSize & 0x03) != 0)
  4843. {
  4844. numPadBytes = 4 - (streamSize & 0x03);
  4845. }
  4846. status = Ok;
  4847. if (status == Ok)
  4848. {
  4849. HRESULT hr;
  4850. ULONG bytesRead = 0;
  4851. ULONG bytesWrite = 0;
  4852. while (streamSize > 0)
  4853. {
  4854. if (sizeToRead > streamSize)
  4855. {
  4856. sizeToRead = streamSize;
  4857. }
  4858. hr = imageStream->Read(buffer, sizeToRead, &bytesRead);
  4859. if (!SUCCEEDED(hr) || (sizeToRead != bytesRead))
  4860. {
  4861. WARNING(("Failed to read stream in CopyOnWriteBitmap::GetData"));
  4862. status = Win32Error;
  4863. break;
  4864. }
  4865. hr = stream->Write(buffer, sizeToRead, &bytesWrite);
  4866. if (!SUCCEEDED(hr) || (sizeToRead != bytesWrite))
  4867. {
  4868. WARNING(("Failed to write stream in CopyOnWriteBitmap::GetData"));
  4869. status = Win32Error;
  4870. break;
  4871. }
  4872. streamSize -= sizeToRead;
  4873. }
  4874. // align
  4875. if (numPadBytes > 0)
  4876. {
  4877. INT pad = 0;
  4878. stream->Write(&pad, numPadBytes, NULL);
  4879. }
  4880. }
  4881. if (isSeekableStream)
  4882. {
  4883. // move back to the old pos
  4884. Stream->Seek(oldPos, STREAM_SEEK_SET, NULL);
  4885. }
  4886. if (needRelease)
  4887. {
  4888. imageStream->Release();
  4889. }
  4890. return status;
  4891. }
  4892. // we can't record compressed data, record the uncompressed data
  4893. if ((status = (const_cast<CopyOnWriteBitmap *>(this))->LoadIntoMemory()) != Ok)
  4894. {
  4895. WARNING(("Couldn't load the image into memory"));
  4896. return status;
  4897. }
  4898. BitmapData bitmapData = *Bmp;
  4899. INT positiveStride = bitmapData.Stride;
  4900. BOOL upsideDown = FALSE;
  4901. INT paletteSize = 0;
  4902. INT pixelDataSize;
  4903. if (positiveStride < 0)
  4904. {
  4905. positiveStride = -positiveStride;
  4906. upsideDown = TRUE;
  4907. }
  4908. pixelDataSize = (bitmapData.Height * positiveStride);
  4909. if (IsIndexedPixelFormat(bitmapData.PixelFormat))
  4910. {
  4911. // We're an indexed pixel format - must have a valid palette.
  4912. ASSERT(Bmp->colorpal != NULL);
  4913. // Note sizeof(ColorPalette) includes the first palette entry.
  4914. paletteSize = sizeof(ColorPalette) +
  4915. sizeof(ARGB)*(Bmp->colorpal->Count-1);
  4916. }
  4917. bitmapRecordData.Type = ImageTypeBitmap;
  4918. bitmapRecordData.Width = bitmapData.Width;
  4919. bitmapRecordData.Height = bitmapData.Height;
  4920. bitmapRecordData.Stride = positiveStride;
  4921. bitmapRecordData.PixelFormat = bitmapData.PixelFormat;
  4922. bitmapRecordData.Flags = 0;
  4923. stream->Write(&bitmapRecordData, sizeof(bitmapRecordData), NULL);
  4924. if (paletteSize > 0)
  4925. {
  4926. // Write out the palette
  4927. stream->Write(Bmp->colorpal, paletteSize, NULL);
  4928. }
  4929. if (pixelDataSize > 0)
  4930. {
  4931. if (!upsideDown)
  4932. {
  4933. stream->Write(bitmapData.Scan0, pixelDataSize, NULL);
  4934. }
  4935. else
  4936. {
  4937. BYTE * scan = (BYTE *)bitmapData.Scan0;
  4938. for (INT i = bitmapData.Height; i > 0; i--)
  4939. {
  4940. stream->Write(scan, positiveStride, NULL);
  4941. scan -= positiveStride;
  4942. }
  4943. }
  4944. }
  4945. return Ok;
  4946. }
  4947. /**************************************************************************\
  4948. *
  4949. * Function Description:
  4950. *
  4951. * Get the compressed image data.
  4952. *
  4953. * Arguments:
  4954. *
  4955. * OUT compressed_data
  4956. *
  4957. * Return Value:
  4958. *
  4959. * GpStatus - Ok or error code
  4960. *
  4961. * Created:
  4962. *
  4963. \**************************************************************************/
  4964. GpStatus
  4965. CopyOnWriteBitmap::GetCompressedData(
  4966. DpCompressedData * compressed_data,
  4967. BOOL getJPEG,
  4968. BOOL getPNG,
  4969. HDC hdc
  4970. )
  4971. {
  4972. GpStatus status = Ok;
  4973. IStream* imageStream = NULL;
  4974. STATSTG statStg;
  4975. BOOL needRelease = FALSE;
  4976. // variables used to track the stream state
  4977. LARGE_INTEGER zero = {0,0};
  4978. LARGE_INTEGER oldPos;
  4979. BOOL isSeekableStream = FALSE;
  4980. ASSERT(compressed_data->buffer == NULL);
  4981. if (Img)
  4982. {
  4983. if (SrcImageInfo.RawDataFormat == IMGFMT_JPEG)
  4984. {
  4985. if (!getJPEG)
  4986. {
  4987. return Ok;
  4988. }
  4989. compressed_data->format = BI_JPEG;
  4990. }
  4991. else if (SrcImageInfo.RawDataFormat == IMGFMT_PNG)
  4992. {
  4993. if (!getPNG)
  4994. {
  4995. return Ok;
  4996. }
  4997. compressed_data->format = BI_PNG;
  4998. }
  4999. else
  5000. return Ok;
  5001. }
  5002. else
  5003. {
  5004. WARNING(("GetCompressedData: Decoded image not available."));
  5005. return Ok;
  5006. }
  5007. // try to get a imageStream
  5008. if (!IsDirty())
  5009. {
  5010. HRESULT hr;
  5011. if (Stream != NULL)
  5012. {
  5013. hr = Stream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&oldPos);
  5014. if (SUCCEEDED(hr))
  5015. {
  5016. hr = Stream->Seek(zero, STREAM_SEEK_SET, NULL);
  5017. if (SUCCEEDED(hr))
  5018. {
  5019. isSeekableStream = TRUE;
  5020. imageStream = Stream;
  5021. }
  5022. }
  5023. }
  5024. // if we don't have a CopyOnWriteBitmap::Stream but we have a filename
  5025. if ((imageStream == NULL) && (Filename != NULL))
  5026. {
  5027. hr = CreateStreamOnFileForRead(Filename, &imageStream);
  5028. if (SUCCEEDED(hr))
  5029. {
  5030. needRelease = TRUE;
  5031. }
  5032. }
  5033. }
  5034. if (imageStream && (imageStream->Stat(&statStg, STATFLAG_NONAME) == S_OK))
  5035. {
  5036. UINT streamSize = statStg.cbSize.LowPart;
  5037. ULONG bytesRead = 0;
  5038. VOID * buffer = (PVOID)GpMalloc(streamSize);
  5039. if (buffer)
  5040. {
  5041. HRESULT hr;
  5042. hr = imageStream->Read(buffer, streamSize, &bytesRead);
  5043. if (!SUCCEEDED(hr) || (streamSize != bytesRead))
  5044. {
  5045. WARNING(("Failed to read stream in CopyOnWriteBitmap::GetData"));
  5046. status = Win32Error;
  5047. }
  5048. else
  5049. {
  5050. compressed_data->bufferSize = streamSize;
  5051. compressed_data->buffer = buffer;
  5052. }
  5053. }
  5054. else
  5055. {
  5056. WARNING(("Out of memory"));
  5057. status = OutOfMemory;
  5058. }
  5059. }
  5060. if (isSeekableStream)
  5061. {
  5062. // move back to the old pos
  5063. Stream->Seek(oldPos, STREAM_SEEK_SET, NULL);
  5064. }
  5065. if (needRelease)
  5066. {
  5067. imageStream->Release();
  5068. }
  5069. if ((hdc != NULL) && (compressed_data->buffer != NULL))
  5070. {
  5071. DWORD EscapeValue = (compressed_data->format == BI_JPEG) ?
  5072. CHECKJPEGFORMAT : CHECKPNGFORMAT;
  5073. DWORD result = 0;
  5074. // Call escape to determine if this particular image is supported
  5075. if ((ExtEscape(hdc,
  5076. EscapeValue,
  5077. compressed_data->bufferSize,
  5078. (LPCSTR)compressed_data->buffer,
  5079. sizeof(DWORD),
  5080. (LPSTR)&result) <= 0) || (result != 1))
  5081. {
  5082. // Failed to support passthrough of this image, delete the
  5083. // compressed bits.
  5084. DeleteCompressedData(compressed_data);
  5085. }
  5086. }
  5087. return status;
  5088. }
  5089. GpStatus
  5090. CopyOnWriteBitmap::DeleteCompressedData(
  5091. DpCompressedData * compressed_data
  5092. )
  5093. {
  5094. GpStatus status = Ok;
  5095. if (compressed_data && compressed_data->buffer)
  5096. {
  5097. GpFree(compressed_data->buffer);
  5098. compressed_data->buffer = NULL;
  5099. }
  5100. return status;
  5101. }
  5102. UINT
  5103. CopyOnWriteBitmap::GetDataSize() const
  5104. {
  5105. UINT dataSize = 0;
  5106. // if CopyOnWriteBitmap is not dirty, we look at compressed data
  5107. if (!IsDirty())
  5108. {
  5109. STATSTG statStg;
  5110. HRESULT hr;
  5111. if (Stream != NULL)
  5112. {
  5113. // variables used to track the stream state
  5114. LARGE_INTEGER zero = {0,0};
  5115. LARGE_INTEGER oldPos;
  5116. BOOL isSeekableStream = FALSE;
  5117. hr = Stream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&oldPos);
  5118. if (SUCCEEDED(hr))
  5119. {
  5120. hr = Stream->Seek(zero, STREAM_SEEK_SET, NULL);
  5121. if (SUCCEEDED(hr))
  5122. {
  5123. if (Stream->Stat(&statStg, STATFLAG_NONAME) == S_OK)
  5124. {
  5125. dataSize = sizeof(BitmapRecordData) + statStg.cbSize.LowPart;
  5126. }
  5127. // move back to the old pos
  5128. Stream->Seek(oldPos, STREAM_SEEK_SET, NULL);
  5129. return ((dataSize + 3) & (~3)); // align
  5130. }
  5131. }
  5132. }
  5133. if (Filename != NULL)
  5134. {
  5135. IStream* stream = NULL;
  5136. hr = CreateStreamOnFileForRead(Filename, &stream);
  5137. if (SUCCEEDED(hr))
  5138. {
  5139. if (stream->Stat(&statStg, STATFLAG_NONAME) == S_OK)
  5140. {
  5141. dataSize = sizeof(BitmapRecordData) + statStg.cbSize.LowPart;
  5142. }
  5143. stream->Release();
  5144. }
  5145. return ((dataSize + 3) & (~3)); // align
  5146. }
  5147. }
  5148. // if we cannot get the compressed data
  5149. if ((const_cast<CopyOnWriteBitmap *>(this))->LoadIntoMemory() == Ok)
  5150. {
  5151. BitmapData bitmapData = *Bmp;
  5152. INT positiveStride = bitmapData.Stride;
  5153. INT paletteSize = 0;
  5154. INT pixelDataSize;
  5155. if (positiveStride < 0)
  5156. {
  5157. positiveStride = -positiveStride;
  5158. }
  5159. pixelDataSize = (bitmapData.Height * positiveStride);
  5160. if (IsIndexedPixelFormat(bitmapData.PixelFormat))
  5161. {
  5162. // We're an indexed pixel format - must have a valid palette.
  5163. ASSERT(Bmp->colorpal != NULL);
  5164. // Note sizeof(ColorPalette) includes the first palette entry.
  5165. paletteSize = sizeof(ColorPalette) +
  5166. sizeof(ARGB)*(Bmp->colorpal->Count - 1);
  5167. }
  5168. dataSize = sizeof(BitmapRecordData) + paletteSize + pixelDataSize;
  5169. }
  5170. return ((dataSize + 3) & (~3)); // align
  5171. }
  5172. /**************************************************************************\
  5173. *
  5174. * Function Description:
  5175. *
  5176. * Read the bitmap object from memory.
  5177. *
  5178. * Arguments:
  5179. *
  5180. * [IN] dataBuffer - the data that was read from the stream
  5181. * [IN] size - the size of the data
  5182. *
  5183. * Return Value:
  5184. *
  5185. * GpStatus - Ok or failure status
  5186. *
  5187. * Created:
  5188. *
  5189. * 4/26/1999 DCurtis
  5190. *
  5191. \**************************************************************************/
  5192. GpStatus
  5193. CopyOnWriteBitmap::SetData(
  5194. const BYTE * dataBuffer,
  5195. UINT size
  5196. )
  5197. {
  5198. ASSERT ((GpImageType)(((BitmapRecordData *)dataBuffer)->Type) == ImageTypeBitmap);
  5199. GpStatus status = Ok;
  5200. this->FreeData();
  5201. this->InitDefaults();
  5202. if (dataBuffer == NULL)
  5203. {
  5204. WARNING(("dataBuffer is NULL"));
  5205. return InvalidParameter;
  5206. }
  5207. if (size < sizeof(BitmapRecordData))
  5208. {
  5209. WARNING(("size too small"));
  5210. return InvalidParameter;
  5211. }
  5212. const BitmapRecordData * bitmapData;
  5213. bitmapData = reinterpret_cast<const BitmapRecordData *>(dataBuffer);
  5214. if (!bitmapData->MajorVersionMatches())
  5215. {
  5216. WARNING(("Version number mismatch"));
  5217. return InvalidParameter;
  5218. }
  5219. if (!(bitmapData->Flags & COMPRESSED_IMAGE))
  5220. {
  5221. Bmp = new GpMemoryBitmap();
  5222. if (Bmp != NULL)
  5223. {
  5224. // Mask out the pixel format
  5225. PixelFormatID pixelFormat = MaskPixelFormat(bitmapData->PixelFormat);
  5226. HRESULT hr = Bmp->InitNewBitmap(bitmapData->Width,
  5227. bitmapData->Height,
  5228. pixelFormat);
  5229. if (FAILED(hr))
  5230. {
  5231. WARNING(("InitNewBitmap failed"));
  5232. delete Bmp;
  5233. Bmp = NULL;
  5234. return GenericError;
  5235. }
  5236. // Fill image info structure
  5237. if ( Bmp->GetImageInfo(&SrcImageInfo) != S_OK )
  5238. {
  5239. WARNING(("InitNewBitmap failed"));
  5240. delete Bmp;
  5241. Bmp = NULL;
  5242. return GenericError;
  5243. }
  5244. PixelFormatInMem = SrcImageInfo.PixelFormat;
  5245. ASSERT(Bmp->Stride == bitmapData->Stride);
  5246. dataBuffer += sizeof(BitmapRecordData);
  5247. size -= sizeof(BitmapRecordData);
  5248. State = MemBitmap;
  5249. // If it's an indexed format, we'll have stored the palette next
  5250. if(IsIndexedPixelFormat(pixelFormat))
  5251. {
  5252. if (size < sizeof(ColorPalette))
  5253. {
  5254. WARNING(("size too small"));
  5255. return InvalidParameter;
  5256. }
  5257. UINT paletteSize;
  5258. ColorPalette *pal;
  5259. pal = (ColorPalette *)dataBuffer;
  5260. // Work out how big the palette is.
  5261. // sizeof(ColorPalette) includes the first entry.
  5262. paletteSize = sizeof(ColorPalette)+sizeof(ARGB)*(pal->Count-1);
  5263. if (size < paletteSize)
  5264. {
  5265. WARNING(("size too small"));
  5266. return InvalidParameter;
  5267. }
  5268. // Make the GpMemoryBitmap clone the palette into the right place
  5269. Bmp->SetPalette(pal);
  5270. // Update the dataBuffer stream to the beginning of the pixel data
  5271. dataBuffer += paletteSize;
  5272. size -= paletteSize;
  5273. }
  5274. }
  5275. else
  5276. {
  5277. WARNING(("Out of memory"));
  5278. return OutOfMemory;
  5279. }
  5280. ASSERT((Bmp != NULL) && (Bmp->Scan0 != NULL));
  5281. ULONG pixelSize = Bmp->Stride * Bmp->Height;
  5282. if (size >= pixelSize)
  5283. {
  5284. size = pixelSize;
  5285. }
  5286. else
  5287. {
  5288. WARNING(("Insufficient data to fill bitmap"));
  5289. status = InvalidParameter;
  5290. }
  5291. if (size > 0)
  5292. {
  5293. GpMemcpy(Bmp->Scan0, dataBuffer, size);
  5294. }
  5295. }
  5296. else
  5297. {
  5298. // Create an IStream on top of the memory buffer
  5299. GpReadOnlyMemoryStream* stream;
  5300. stream = new GpReadOnlyMemoryStream();
  5301. if (!stream)
  5302. {
  5303. WARNING(("Out of memory"));
  5304. return OutOfMemory;
  5305. }
  5306. dataBuffer += sizeof(BitmapRecordData);
  5307. size -= sizeof(BitmapRecordData);
  5308. stream->InitBuffer(dataBuffer, size);
  5309. // since we don't want to hold dataBuffer or make a copy of
  5310. // it, we just Load it into memory here.
  5311. Stream = stream;
  5312. State = ExtStream;
  5313. status = LoadIntoMemory();
  5314. if ( status == Ok )
  5315. {
  5316. // The source image is loaded into memory and we are not going to
  5317. // keep the source image connection any more. So we fill the image
  5318. // info with the memory bits info
  5319. if ( Bmp->GetImageInfo(&SrcImageInfo) != S_OK )
  5320. {
  5321. status = GenericError;
  5322. }
  5323. else
  5324. {
  5325. PixelFormatInMem = SrcImageInfo.PixelFormat;
  5326. }
  5327. }
  5328. stream->Release();
  5329. Stream = NULL;
  5330. if (Img)
  5331. {
  5332. Img->Release();
  5333. Img = NULL;
  5334. }
  5335. }
  5336. return status;
  5337. }
  5338. char ColorChannelName[4] = {'C', 'M', 'Y', 'K'};
  5339. /**************************************************************************\
  5340. *
  5341. * Function Description:
  5342. *
  5343. * Do the color adjustment if the lower level codec can do it.
  5344. *
  5345. * Arguments:
  5346. *
  5347. * [IN] recolor - Pointer to image attributes
  5348. *
  5349. * Return Value:
  5350. *
  5351. * Status code
  5352. * Return Ok -------------Lower level does it
  5353. * Return NotImplemented--Lower level can't do it
  5354. * Other status code
  5355. *
  5356. * Revision History:
  5357. *
  5358. * 11/22/1999 minliu
  5359. * Created it.
  5360. *
  5361. \**************************************************************************/
  5362. GpStatus
  5363. CopyOnWriteBitmap::ColorAdjustByCodec(
  5364. GpRecolor * recolor,
  5365. DrawImageAbort callback,
  5366. VOID *callbackData
  5367. )
  5368. {
  5369. if (recolor == NULL)
  5370. {
  5371. // The lower level codec doesn't know how to handle this, let the
  5372. // up level do it
  5373. return NotImplemented;
  5374. }
  5375. HRESULT hResult;
  5376. UINT uiCurrentFlag = recolor->GetValidFlags(ColorAdjustTypeBitmap);
  5377. BOOL bImgCreatedHere = FALSE;
  5378. // First we need to check if the current lower level decoder can do the
  5379. // job or not
  5380. if ( Img == NULL )
  5381. {
  5382. // Create a GpDecodedImage*
  5383. if ( NULL != Stream )
  5384. {
  5385. hResult = GpDecodedImage::CreateFromStream(Stream, &Img);
  5386. }
  5387. else
  5388. {
  5389. if ( Filename == NULL )
  5390. {
  5391. // We can't continue. Let the higher level do it
  5392. return NotImplemented;
  5393. }
  5394. hResult = GpDecodedImage::CreateFromFile(Filename, &Img);
  5395. }
  5396. if ( FAILED(hResult) )
  5397. {
  5398. WARNING(("Failed to create decoded image: %x", hResult));
  5399. return Win32Error;
  5400. }
  5401. // Remember that we creat a copy of Img here. Should be freed when done
  5402. bImgCreatedHere = TRUE;
  5403. }// (Img == NULL)
  5404. GUID DecoderParamGuid;
  5405. UINT DecoderParamLength;
  5406. PVOID DecoderParamPtr;
  5407. GpStatus rCode = Win32Error;
  5408. // Set the GUID and other parameters with respect to the image attributes
  5409. // Note: we won't have a recolor which has both ValidColorKeys and
  5410. // ValidOutputChannel set. This function won't be called if this case is
  5411. // TRUE. We checked this in ColorAdjust()
  5412. UINT value[2];
  5413. if ( uiCurrentFlag & (GpRecolorObject::ValidColorKeys) )
  5414. {
  5415. // Set color key
  5416. DecoderParamGuid = DECODER_TRANSCOLOR;
  5417. DecoderParamLength = 8;
  5418. value[0] = (UINT)(recolor->GetColorKeyLow(ColorAdjustTypeBitmap));
  5419. value[1] = (UINT)(recolor->GetColorKeyHigh(ColorAdjustTypeBitmap));
  5420. DecoderParamPtr = (VOID*)value;
  5421. }
  5422. else if ( uiCurrentFlag & (GpRecolorObject::ValidOutputChannel) )
  5423. {
  5424. // Asks the codec doing a color separation makes sense only when the
  5425. // source image is in CMYK space. Otherwise, we do it in our recolor
  5426. // object which contains a generic algorithem for doing it
  5427. if ( !( (SrcImageInfo.Flags & ImageFlagsColorSpaceCMYK)
  5428. ||(SrcImageInfo.Flags & ImageFlagsColorSpaceYCCK) ) )
  5429. {
  5430. // Not a CMYK image, do it in recolor object
  5431. rCode = NotImplemented;
  5432. goto CleanUp;
  5433. }
  5434. // Set channel output
  5435. DecoderParamGuid = DECODER_OUTPUTCHANNEL;
  5436. DecoderParamLength = 1;
  5437. DecoderParamPtr =
  5438. (VOID*)(&ColorChannelName[recolor->GetChannelIndex(ColorAdjustTypeBitmap)]);
  5439. }
  5440. // Query to see if the decoder can do it or not
  5441. hResult = Img->QueryDecoderParam(DecoderParamGuid);
  5442. if ( (hResult != E_NOTIMPL) && (hResult != S_OK) )
  5443. {
  5444. WARNING(("Failed to query decoder param: %x", hResult));
  5445. goto CleanUp;
  5446. }
  5447. else if ( hResult == E_NOTIMPL )
  5448. {
  5449. // The lower level decoder doesn't support this.
  5450. rCode = NotImplemented;
  5451. goto CleanUp;
  5452. }
  5453. // Set the decoder param to tell the lower level how to decode
  5454. hResult = Img->SetDecoderParam(DecoderParamGuid, DecoderParamLength,
  5455. DecoderParamPtr);
  5456. if ( (hResult != E_NOTIMPL) && (hResult != S_OK) )
  5457. {
  5458. WARNING(("Failed to set decoder param: %x", hResult));
  5459. goto CleanUp;
  5460. }
  5461. else if ( hResult == E_NOTIMPL )
  5462. {
  5463. // The lower level decoder doesn't support this.
  5464. rCode = NotImplemented;
  5465. goto CleanUp;
  5466. }
  5467. // Now we don't need the previous "Bmp" since we are going to ask the
  5468. // lower level decoder to create one for us
  5469. if ( Bmp != NULL )
  5470. {
  5471. Bmp->Release();
  5472. Bmp = NULL;
  5473. }
  5474. // Ask the decoder to create a 32BPP ARGB GpMemoryBitmap.
  5475. hResult = GpMemoryBitmap::CreateFromImage(Img,
  5476. 0,
  5477. 0,
  5478. PIXFMT_32BPP_ARGB,
  5479. InterpolationHintDefault,
  5480. &Bmp,
  5481. callback,
  5482. callbackData);
  5483. if ( FAILED(hResult) )
  5484. {
  5485. WARNING(("Failed to load image into memory: %x", hResult));
  5486. goto CleanUp;
  5487. }
  5488. State = MemBitmap;
  5489. PixelFormatInMem = PIXFMT_32BPP_ARGB;
  5490. // The lower level does the job for us.
  5491. rCode = Ok;
  5492. CleanUp:
  5493. if ( bImgCreatedHere == TRUE )
  5494. {
  5495. // Note: we don't need to check if Img == NULL or not because this flag
  5496. // would only be set when we successed in creating Img
  5497. Img->Release();
  5498. Img = NULL;
  5499. }
  5500. return rCode;
  5501. }// ColorAdjustByCodec()
  5502. GpStatus
  5503. CopyOnWriteBitmap::ColorAdjust(
  5504. GpRecolor * recolor,
  5505. PixelFormatID pixfmt,
  5506. DrawImageAbort callback,
  5507. VOID *callbackData
  5508. )
  5509. {
  5510. HRESULT hr;
  5511. ASSERT(ObjRefCount == 1);
  5512. ASSERT(recolor != NULL);
  5513. // Mark the result image (color adjusted image) as dirty
  5514. // Note: this won't damage the original source image because we always
  5515. // color adjust on a cloned copy of the original image
  5516. SetDirtyFlag(TRUE);
  5517. UINT uiCurrentFlag = recolor->GetValidFlags(ColorAdjustTypeBitmap);
  5518. // For color key output: we will ask the lower level decoder to do the job
  5519. // if there is no other recoloring flag is specified
  5520. // For color separation(channel output), we will ask the lower level decoder
  5521. // to do the job if there is no other recoloring flag is specified except
  5522. // for ValidColorProfile.
  5523. // If the codec can handle CMYK separation, then the profile is ignored.
  5524. // If the source is RGB image, then ColorAdjustByCodec() will do nothing
  5525. // and we will use the profile to do RGB to CMYK conversion before
  5526. // channel separation
  5527. if ( uiCurrentFlag
  5528. &&( ((uiCurrentFlag & GpRecolorObject::ValidColorKeys) == uiCurrentFlag)
  5529. ||((uiCurrentFlag
  5530. &(~GpRecolorObject::ValidChannelProfile)
  5531. &(GpRecolorObject::ValidOutputChannel))
  5532. == (GpRecolorObject::ValidOutputChannel) ) ) )
  5533. {
  5534. Status rCode = ColorAdjustByCodec(recolor, callback, callbackData);
  5535. if ( rCode != NotImplemented )
  5536. {
  5537. // Either the lower level did the job for us (rCode == Ok) or it
  5538. // failed somehow (rCode == Win32Error etc.). We just return here
  5539. return rCode;
  5540. }
  5541. // Lower level can't do it. We can just slip here to do the normal
  5542. // software version of color adjust
  5543. }// Color key and color channel handling
  5544. GpStatus status = LoadIntoMemory(pixfmt);
  5545. if ( status != Ok )
  5546. {
  5547. return status;
  5548. }
  5549. hr = Bmp->PerformColorAdjustment(recolor,
  5550. ColorAdjustTypeBitmap,
  5551. callback, callbackData);
  5552. if ( SUCCEEDED(hr) )
  5553. {
  5554. Bmp->SetAlphaHint(GpMemoryBitmap::ALPHA_UNKNOWN);
  5555. return Ok;
  5556. }
  5557. else if (hr == IMGERR_ABORT)
  5558. {
  5559. WARNING(("CopyOnWriteBitmap::ColorAdjust---Aborted"));
  5560. return Aborted;
  5561. }
  5562. else
  5563. {
  5564. WARNING(("CopyOnWriteBitmap::ColorAdjust---PerformColorAdjustment() failed"));
  5565. return GenericError;
  5566. }
  5567. }// ColorAdjust()
  5568. /**************************************************************************\
  5569. *
  5570. * Function Description:
  5571. *
  5572. * Get the (current) pixel format of the CopyOnWriteBitmap.
  5573. * Here "current" means the pixel format in the memory if it has been loaded,
  5574. * aka, a GpMemoryBitmap. If it is not in the memory, then we return the
  5575. * PixelFormat of the original image
  5576. *
  5577. *
  5578. * Arguments:
  5579. *
  5580. * [OUT] pixfmt - Pointer to pixel format
  5581. *
  5582. * Return Value:
  5583. *
  5584. * Status code
  5585. * Ok - success
  5586. * Win32Error - failed
  5587. *
  5588. * Revision History:
  5589. *
  5590. * 06/10/2000 asecchia
  5591. * Created it.
  5592. * 07/26/2000 minliu
  5593. * Re-wrote it
  5594. *
  5595. \**************************************************************************/
  5596. GpStatus
  5597. CopyOnWriteBitmap::GetPixelFormatID(
  5598. PixelFormatID *pixfmt
  5599. )
  5600. {
  5601. ASSERT(IsValid());
  5602. // If the image is in the memory, then we return the memory bitmap pixel
  5603. // format. Otherwise, return the source image format
  5604. if ( (State == MemBitmap) && (PixelFormatInMem != PixelFormatDontCare) )
  5605. {
  5606. *pixfmt = PixelFormatInMem;
  5607. }
  5608. else
  5609. {
  5610. *pixfmt = SrcImageInfo.PixelFormat;
  5611. }
  5612. return Ok;
  5613. }
  5614. CopyOnWriteBitmap*
  5615. CopyOnWriteBitmap::CloneColorAdjusted(
  5616. GpRecolor * recolor,
  5617. ColorAdjustType type
  5618. ) const
  5619. {
  5620. ASSERT(recolor != NULL);
  5621. CopyOnWriteBitmap * clonedBitmap = (CopyOnWriteBitmap *)this->Clone();
  5622. if (clonedBitmap != NULL)
  5623. {
  5624. if ((clonedBitmap->IsValid()) &&
  5625. (clonedBitmap->ColorAdjust(recolor, type) == Ok))
  5626. {
  5627. clonedBitmap->SetDirtyFlag(TRUE);
  5628. return clonedBitmap;
  5629. }
  5630. delete clonedBitmap;
  5631. }
  5632. return NULL;
  5633. }
  5634. GpStatus
  5635. CopyOnWriteBitmap::ColorAdjust(
  5636. GpRecolor * recolor,
  5637. ColorAdjustType type
  5638. )
  5639. {
  5640. ASSERT(recolor != NULL);
  5641. ASSERT(ObjRefCount == 1);
  5642. GpStatus status = LoadIntoMemory();
  5643. if (status != Ok)
  5644. {
  5645. return status;
  5646. }
  5647. if (type == ColorAdjustTypeDefault)
  5648. {
  5649. type = ColorAdjustTypeBitmap;
  5650. }
  5651. HRESULT hr = Bmp->PerformColorAdjustment(recolor, type, NULL, NULL);
  5652. if ( SUCCEEDED(hr) )
  5653. {
  5654. SetDirtyFlag(TRUE);
  5655. return Ok;
  5656. }
  5657. return GenericError;
  5658. }
  5659. /**************************************************************************\
  5660. *
  5661. * Function Description:
  5662. *
  5663. * Override the native resolution of the bitmap.
  5664. *
  5665. * Arguments:
  5666. *
  5667. * xdpi, ydpi - New resolution
  5668. *
  5669. * Return Value:
  5670. *
  5671. * Status code
  5672. *
  5673. \**************************************************************************/
  5674. GpStatus
  5675. CopyOnWriteBitmap::SetResolution(
  5676. REAL xdpi,
  5677. REAL ydpi
  5678. )
  5679. {
  5680. if ( (xdpi > 0.0) && (ydpi > 0.0) )
  5681. {
  5682. XDpiOverride = xdpi;
  5683. YDpiOverride = ydpi;
  5684. if ( Img )
  5685. {
  5686. Img->SetResolution(xdpi, ydpi);
  5687. }
  5688. if ( Bmp )
  5689. {
  5690. Bmp->SetResolution(xdpi, ydpi);
  5691. }
  5692. SrcImageInfo.Xdpi = xdpi;
  5693. SrcImageInfo.Ydpi = ydpi;
  5694. // Mark the bits dirty since we have to save the image with the new
  5695. // resolution info.
  5696. SetDirtyFlag(TRUE);
  5697. return Ok;
  5698. }
  5699. else
  5700. {
  5701. return InvalidParameter;
  5702. }
  5703. }// SetResolution()
  5704. /**************************************************************************\
  5705. *
  5706. * Function Description:
  5707. *
  5708. * INTEROP
  5709. *
  5710. * Create a GDI bitmap (HBITMAP) from a GDI+ bitmap.
  5711. *
  5712. * Arguments:
  5713. *
  5714. * phbm -- Return HBITMAP via this pointer
  5715. * background -- If GDI+ bitmap has alpha, blend with this color as the
  5716. * background
  5717. *
  5718. * Return Value:
  5719. *
  5720. * Status code
  5721. *
  5722. \**************************************************************************/
  5723. GpStatus
  5724. CopyOnWriteBitmap::CreateHBITMAP(HBITMAP *phbm, ARGB background)
  5725. {
  5726. GpStatus status;
  5727. // These objects need cleanup:
  5728. HDC hdc = NULL;
  5729. HBITMAP hbmOld = NULL;
  5730. HBITMAP hbmNew = NULL;
  5731. HBRUSH hbr = NULL;
  5732. HBRUSH hbrOld = NULL;
  5733. GpGraphics *g = NULL;
  5734. // Get format information for this bitmap:
  5735. // Create HDC:
  5736. hdc = CreateCompatibleDC(NULL);
  5737. if (!hdc)
  5738. {
  5739. WARNING(("CreateHBITMAP: CreateCompatibleDC failed"));
  5740. status = Win32Error;
  5741. goto error_cleanup;
  5742. }
  5743. // Create DIB section:
  5744. BITMAPINFO bmi;
  5745. VOID *pv;
  5746. GpMemset(&bmi, 0, sizeof(bmi));
  5747. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  5748. bmi.bmiHeader.biWidth = SrcImageInfo.Width;
  5749. bmi.bmiHeader.biHeight = SrcImageInfo.Height;
  5750. bmi.bmiHeader.biPlanes = 1;
  5751. bmi.bmiHeader.biBitCount = 32;
  5752. bmi.bmiHeader.biCompression = BI_RGB;
  5753. hbmNew = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pv, NULL, 0);
  5754. if (!hbmNew)
  5755. {
  5756. WARNING(("CreateHBITMAP: CreateDIBSection failed\n"));
  5757. status = Win32Error;
  5758. goto error_cleanup;
  5759. }
  5760. // Select DIB into DC:
  5761. hbmOld = (HBITMAP) SelectObject(hdc, hbmNew);
  5762. if (!hbmOld)
  5763. {
  5764. WARNING(("CreateHBITMAP: SelectObject(hbm) failed\n"));
  5765. status = Win32Error;
  5766. goto error_cleanup;
  5767. }
  5768. // Clear DIB to specified ARGB color:
  5769. LOGBRUSH lbr;
  5770. lbr.lbStyle = BS_SOLID;
  5771. lbr.lbColor = RGB(background & 0x00ff0000,
  5772. background & 0x0000ff00,
  5773. background & 0x000000ff);
  5774. hbr = CreateBrushIndirect(&lbr);
  5775. if (!hbr)
  5776. {
  5777. WARNING(("CreateHBITMAP: CreateBrushIndirect failed\n"));
  5778. status = Win32Error;
  5779. goto error_cleanup;
  5780. }
  5781. hbrOld = (HBRUSH) SelectObject(hdc, hbr);
  5782. if (!hbrOld)
  5783. {
  5784. WARNING(("CreateHBITMAP: SelectObject(hbr) failed\n"));
  5785. status = Win32Error;
  5786. goto error_cleanup;
  5787. }
  5788. PatBlt(hdc, 0, 0, SrcImageInfo.Width, SrcImageInfo.Height, PATCOPY);
  5789. // Derive Graphics from HDC:
  5790. g = GpGraphics::GetFromHdc(hdc);
  5791. if (!g)
  5792. {
  5793. WARNING(("CreateHBITMAP: GpGraphics::GetFromHdc failed\n"));
  5794. status = OutOfMemory;
  5795. goto error_cleanup;
  5796. }
  5797. // DrawImage bitmap to Graphics:
  5798. {
  5799. GpLock lock(g->GetObjectLock());
  5800. if (lock.IsValid())
  5801. {
  5802. FPUStateSaver fpState;
  5803. GpRectF rect(0.0, 0.0, TOREAL(SrcImageInfo.Width),
  5804. TOREAL(SrcImageInfo.Height));
  5805. GpBitmap tmpBitmap(this);
  5806. status = g->DrawImage(&tmpBitmap, rect, rect, UnitPixel);
  5807. if (status == Ok)
  5808. {
  5809. // Bypass cleanup of the bitmap, we want to keep it:
  5810. *phbm = hbmNew;
  5811. hbmNew = NULL;
  5812. }
  5813. else
  5814. {
  5815. WARNING(("CreateHBITMAP: GpGraphics::DrawImage failed"));
  5816. }
  5817. }
  5818. else
  5819. {
  5820. status = ObjectBusy;
  5821. }
  5822. }
  5823. error_cleanup:
  5824. if (hdc)
  5825. {
  5826. if (hbmOld)
  5827. SelectObject(hdc, hbmOld);
  5828. if (hbrOld)
  5829. SelectObject(hdc, hbrOld);
  5830. DeleteDC(hdc);
  5831. }
  5832. if (hbmNew)
  5833. DeleteObject(hbmNew);
  5834. if (hbr)
  5835. DeleteObject(hbr);
  5836. if (g)
  5837. delete g;
  5838. return status;
  5839. }
  5840. /**************************************************************************\
  5841. *
  5842. * Function Description:
  5843. *
  5844. * INTEROP
  5845. *
  5846. * Create a Win32 icon (HICON) from a GDI+ bitmap.
  5847. *
  5848. * Arguments:
  5849. *
  5850. * phicon -- Return HICON via this pointer
  5851. *
  5852. * Return Value:
  5853. *
  5854. * Status code
  5855. *
  5856. \**************************************************************************/
  5857. VOID ExportMask32BPP(BitmapData* mask, BitmapData* src)
  5858. {
  5859. ASSERT(src->PixelFormat == PIXFMT_32BPP_ARGB);
  5860. ASSERT(mask->PixelFormat == PIXFMT_32BPP_RGB);
  5861. ASSERT(src->Width == mask->Width);
  5862. ASSERT(src->Height == mask->Height);
  5863. ASSERT(src->Scan0 != NULL);
  5864. ASSERT(mask->Scan0 != NULL);
  5865. BYTE* srcScan = static_cast<BYTE*>(src->Scan0);
  5866. BYTE* maskScan = static_cast<BYTE*>(mask->Scan0);
  5867. for (UINT row = 0; row < src->Height; row++)
  5868. {
  5869. ARGB *srcPixel = static_cast<ARGB*>(static_cast<VOID*>(srcScan));
  5870. ARGB *maskPixel = static_cast<ARGB*>(static_cast<VOID*>(maskScan));
  5871. for (UINT col = 0; col < src->Width; col++)
  5872. {
  5873. if ((*srcPixel & 0xff000000) == 0xff000000)
  5874. *maskPixel = 0; // Opaque
  5875. else
  5876. *maskPixel = 0x00ffffff; // Transparent
  5877. srcPixel++;
  5878. maskPixel++;
  5879. }
  5880. srcScan = srcScan + src->Stride;
  5881. maskScan = maskScan + mask->Stride;
  5882. }
  5883. }
  5884. GpStatus
  5885. CopyOnWriteBitmap::CreateHICON(
  5886. HICON *phicon
  5887. )
  5888. {
  5889. GpStatus status = Win32Error;
  5890. ICONINFO iconInfo;
  5891. iconInfo.fIcon = TRUE;
  5892. status = CreateHBITMAP(&iconInfo.hbmColor, 0);
  5893. if (status == Ok)
  5894. {
  5895. BitmapData bmpDataSrc;
  5896. status = this->LockBits(NULL,
  5897. IMGLOCK_READ,
  5898. PIXFMT_32BPP_ARGB,
  5899. &bmpDataSrc);
  5900. if (status == Ok)
  5901. {
  5902. // From this point on, assume failure until we succeed:
  5903. status = Win32Error;
  5904. // Create empty bitmap for the icon mask:
  5905. iconInfo.hbmMask = CreateBitmap(bmpDataSrc.Width,
  5906. bmpDataSrc.Height,
  5907. 1, 1, NULL);
  5908. if (iconInfo.hbmMask != NULL)
  5909. {
  5910. VOID *gdiBitmapData = GpMalloc(bmpDataSrc.Width
  5911. * bmpDataSrc.Height
  5912. * 4);
  5913. if (gdiBitmapData)
  5914. {
  5915. // Convert alpha channel into a 32bpp DIB mask:
  5916. BitmapData bmpDataMask;
  5917. bmpDataMask.Width = bmpDataSrc.Width;
  5918. bmpDataMask.Height = bmpDataSrc.Height;
  5919. bmpDataMask.Stride = bmpDataSrc.Width * 4;
  5920. bmpDataMask.PixelFormat = PIXFMT_32BPP_RGB;
  5921. bmpDataMask.Scan0 = gdiBitmapData;
  5922. bmpDataMask.Reserved = 0;
  5923. ExportMask32BPP(&bmpDataMask, &bmpDataSrc);
  5924. // Set mask bits:
  5925. BYTE bufferBitmapInfo[sizeof(BITMAPINFO)];
  5926. BITMAPINFO *gdiBitmapInfo = (BITMAPINFO *) bufferBitmapInfo;
  5927. memset(bufferBitmapInfo, 0, sizeof(bufferBitmapInfo));
  5928. gdiBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  5929. gdiBitmapInfo->bmiHeader.biWidth = bmpDataSrc.Width;
  5930. gdiBitmapInfo->bmiHeader.biHeight = - static_cast<LONG>
  5931. (bmpDataSrc.Height);
  5932. gdiBitmapInfo->bmiHeader.biPlanes = 1;
  5933. gdiBitmapInfo->bmiHeader.biBitCount = 32;
  5934. gdiBitmapInfo->bmiHeader.biCompression = BI_RGB;
  5935. HDC hdc = GetDC(NULL);
  5936. if (hdc != NULL)
  5937. {
  5938. SetTextColor(hdc, RGB(0, 0, 0));
  5939. SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
  5940. SetBkMode(hdc, OPAQUE);
  5941. if (SetDIBits(hdc,
  5942. iconInfo.hbmMask,
  5943. 0,
  5944. bmpDataSrc.Height,
  5945. gdiBitmapData,
  5946. gdiBitmapInfo,
  5947. DIB_RGB_COLORS
  5948. ))
  5949. {
  5950. // Create icon:
  5951. *phicon = CreateIconIndirect(&iconInfo);
  5952. if (*phicon != NULL)
  5953. status = Ok;
  5954. else
  5955. {
  5956. WARNING(("CreateIconIndirect failed"));
  5957. }
  5958. }
  5959. else
  5960. {
  5961. WARNING(("SetDIBits failed"));
  5962. }
  5963. ReleaseDC(NULL, hdc);
  5964. }
  5965. GpFree(gdiBitmapData);
  5966. }
  5967. else
  5968. {
  5969. WARNING(("memory allocation failed"));
  5970. status = OutOfMemory;
  5971. }
  5972. DeleteObject(iconInfo.hbmMask);
  5973. }
  5974. else
  5975. {
  5976. WARNING(("CreateBitmap failed"));
  5977. }
  5978. this->UnlockBits(&bmpDataSrc);
  5979. }
  5980. else
  5981. {
  5982. WARNING(("LockBits failed"));
  5983. }
  5984. DeleteObject(iconInfo.hbmColor);
  5985. }
  5986. return status;
  5987. }
  5988. /**************************************************************************\
  5989. *
  5990. * Function Description:
  5991. *
  5992. * Prep the bitmap for drawing.
  5993. *
  5994. * Currently, the only thing we do is check if the bitmap is an ICON.
  5995. * If so, we set the DECODER_ICONRES parameters if supported.
  5996. *
  5997. * Arguments:
  5998. *
  5999. * numPoints
  6000. * dstPoints Specifies the destination area
  6001. *
  6002. * srcRect Specifies the source area
  6003. *
  6004. * numBitsPerPixel Specifies the bits-per-pixel of the destination
  6005. *
  6006. * Return Value:
  6007. *
  6008. * Status code
  6009. *
  6010. \**************************************************************************/
  6011. GpStatus
  6012. CopyOnWriteBitmap::PreDraw(
  6013. INT numPoints,
  6014. GpPointF *dstPoints,
  6015. GpRectF *srcRect,
  6016. INT numBitsPerPixel
  6017. )
  6018. {
  6019. // Check if ICON:
  6020. GpStatus status = Ok;
  6021. if ( SrcImageInfo.RawDataFormat == IMGFMT_ICO )
  6022. {
  6023. status = SetIconParameters(numPoints, dstPoints, srcRect,
  6024. numBitsPerPixel);
  6025. }
  6026. return status;
  6027. }
  6028. /**************************************************************************\
  6029. *
  6030. * Function Description:
  6031. *
  6032. * Set the decode parameters for multi-resolution icons.
  6033. *
  6034. * Arguments:
  6035. *
  6036. * numPoints
  6037. * dstPoints Specifies the destination area
  6038. *
  6039. * srcRect Specifies the source area
  6040. *
  6041. * numBitsPerPixel Specifies the bits-per-pixel of the destination
  6042. *
  6043. * Return Value:
  6044. *
  6045. * Status code
  6046. *
  6047. \**************************************************************************/
  6048. GpStatus
  6049. CopyOnWriteBitmap::SetIconParameters(
  6050. INT numPoints,
  6051. GpPointF *dstPoints,
  6052. GpRectF *srcRect,
  6053. INT numBitsPerPixel
  6054. )
  6055. {
  6056. // Check if DECODER_ICONRES supported:
  6057. HRESULT hResult;
  6058. BOOL imageCleanupNeeded = FALSE;
  6059. // First we need to check if the current lower level decoder can do the
  6060. // job or not
  6061. if (Img == NULL)
  6062. {
  6063. // Create a GpDecodedImage*
  6064. if (NULL != Stream)
  6065. {
  6066. hResult = GpDecodedImage::CreateFromStream(Stream, &Img);
  6067. }
  6068. else
  6069. {
  6070. if (Filename == NULL)
  6071. {
  6072. // We can't continue. Let the higher level do it
  6073. return GenericError;
  6074. }
  6075. hResult = GpDecodedImage::CreateFromFile(Filename, &Img);
  6076. }
  6077. if (FAILED(hResult))
  6078. {
  6079. WARNING(("Failed to create decoded image: %x", hResult));
  6080. return Win32Error;
  6081. }
  6082. // Remember that we creat a copy of Img here. Should be freed when done
  6083. imageCleanupNeeded = TRUE;
  6084. }
  6085. GpStatus status = Win32Error;
  6086. // Query to see if the decoder can do it or not
  6087. hResult = Img->QueryDecoderParam(DECODER_ICONRES);
  6088. if (hResult != S_OK)
  6089. {
  6090. if ((hResult == E_FAIL) || (hResult == E_NOTIMPL))
  6091. {
  6092. // Decoder doesn't want it, which is OK.
  6093. status = Ok;
  6094. goto CleanUp;
  6095. }
  6096. else
  6097. {
  6098. // Something else is wrong
  6099. goto CleanUp;
  6100. }
  6101. }
  6102. // Setup the GUID and decode parameters
  6103. {
  6104. UINT value[3];
  6105. value[0] = static_cast<UINT>
  6106. (GetDistance(dstPoints[0], dstPoints[1]) + 0.5);
  6107. value[1] = static_cast<UINT>
  6108. (GetDistance(dstPoints[0], dstPoints[2]) + 0.5);
  6109. value[2] = numBitsPerPixel;
  6110. UINT DecoderParamLength = 3*sizeof(UINT);
  6111. PVOID DecoderParamPtr = (VOID*) value;
  6112. // Set the decoder param to tell the lower level how to decode
  6113. hResult = Img->SetDecoderParam(DECODER_ICONRES,
  6114. DecoderParamLength,
  6115. DecoderParamPtr);
  6116. }
  6117. if (hResult != S_OK)
  6118. {
  6119. if ((hResult == E_FAIL) || (hResult == E_NOTIMPL))
  6120. {
  6121. // Decoder doesn't want it, which is OK.
  6122. status = Ok;
  6123. goto CleanUp;
  6124. }
  6125. else
  6126. {
  6127. // Something else is wrong
  6128. goto CleanUp;
  6129. }
  6130. }
  6131. // Now we don't need the previous "Bmp" since we are going to ask the
  6132. // lower level decoder to create one for us
  6133. if ( Bmp != NULL )
  6134. {
  6135. Bmp->Release();
  6136. Bmp = NULL;
  6137. }
  6138. // Ask the decoder to create a 32BPP ARGB GpMemoryBitmap.
  6139. hResult = GpMemoryBitmap::CreateFromImage(Img,
  6140. 0,
  6141. 0,
  6142. PIXFMT_32BPP_ARGB,
  6143. InterpolationHintDefault,
  6144. &Bmp,
  6145. NULL,
  6146. NULL);
  6147. if ( FAILED(hResult) )
  6148. {
  6149. WARNING(("Failed to load image into memory: %x", hResult));
  6150. goto CleanUp;
  6151. }
  6152. State = MemBitmap;
  6153. PixelFormatInMem = PIXFMT_32BPP_ARGB;
  6154. // The lower level does the job for us.
  6155. status = Ok;
  6156. CleanUp:
  6157. if ((status == Ok) && (srcRect != NULL))
  6158. {
  6159. // Icons are not allowed to clip
  6160. srcRect->X = 0;
  6161. srcRect->Y = 0;
  6162. srcRect->Width = (REAL) SrcImageInfo.Width;
  6163. srcRect->Height = (REAL) SrcImageInfo.Height;
  6164. }
  6165. if (imageCleanupNeeded == TRUE)
  6166. {
  6167. Img->Release();
  6168. Img = NULL;
  6169. }
  6170. return status;
  6171. }
  6172. /**************************************************************************\
  6173. *
  6174. * Function Description:
  6175. *
  6176. * Get the transparency state of the bitmap
  6177. *
  6178. * Arguments:
  6179. *
  6180. * transparency Returned state
  6181. *
  6182. * Return Value:
  6183. *
  6184. * Status code
  6185. *
  6186. \**************************************************************************/
  6187. GpStatus
  6188. CopyOnWriteBitmap::GetTransparencyHint(
  6189. DpTransparency* transparency
  6190. )
  6191. {
  6192. GpStatus status = GenericError;
  6193. if (Bmp != NULL)
  6194. {
  6195. INT alphaHint;
  6196. HRESULT hr = Bmp->GetAlphaHint(&alphaHint);
  6197. if (SUCCEEDED(hr))
  6198. {
  6199. // It's unfortunate that GpMemoryBitmap does not have
  6200. // a DpTransparency flag internally, but there's a conflict
  6201. // with imaging.dll and the include file structure that for
  6202. // now makes it necessary to keep a separate type for this info.
  6203. // In fact, ultimately it would be best if the overlap
  6204. // between DpBitmap and GpMemoryBitmap is resolved including
  6205. // a DpBitmap structure within the GpMemoryBitmap and then
  6206. // removing the redundant info out GpMemoryBitmap.
  6207. switch (alphaHint)
  6208. {
  6209. case GpMemoryBitmap::ALPHA_SIMPLE:
  6210. *transparency = TransparencySimple;
  6211. break;
  6212. case GpMemoryBitmap::ALPHA_OPAQUE:
  6213. *transparency = TransparencyOpaque;
  6214. break;
  6215. case GpMemoryBitmap::ALPHA_NONE:
  6216. *transparency = TransparencyNoAlpha;
  6217. break;
  6218. case GpMemoryBitmap::ALPHA_COMPLEX:
  6219. *transparency = TransparencyComplex;
  6220. break;
  6221. default:
  6222. *transparency = TransparencyUnknown;
  6223. break;
  6224. }
  6225. status = Ok;
  6226. }
  6227. else
  6228. {
  6229. ASSERT(SUCCEEDED(hr));
  6230. *transparency = TransparencyUnknown;
  6231. }
  6232. }
  6233. else
  6234. {
  6235. *transparency = TransparencyUnknown;
  6236. }
  6237. return status;
  6238. }
  6239. /**************************************************************************\
  6240. *
  6241. * Function Description:
  6242. *
  6243. * Get the transparency state of the bitmap. This routine returns accurate
  6244. * info while GetTransparencyHint just returns a hint
  6245. *
  6246. * This routine could scan the whole bitmap (32bpp) so whoever uses it should
  6247. * consider the perf hit.
  6248. *
  6249. * This is currently only for use by the printer drivers.
  6250. *
  6251. * Arguments:
  6252. *
  6253. * transparency Returned state
  6254. *
  6255. * Return Value:
  6256. *
  6257. * Status code
  6258. *
  6259. \**************************************************************************/
  6260. GpStatus
  6261. CopyOnWriteBitmap::GetTransparencyFlags(
  6262. DpTransparency* transparency,
  6263. PixelFormatID loadFormat,
  6264. BYTE* minA,
  6265. BYTE* maxA
  6266. )
  6267. {
  6268. GpStatus status = GenericError;
  6269. ARGB argb;
  6270. ARGB minAlpha = 0xff000000;
  6271. ARGB maxAlpha = 0;
  6272. INT newAlphaHint = GpMemoryBitmap::ALPHA_OPAQUE;
  6273. TestBmp:
  6274. if (Bmp != NULL)
  6275. {
  6276. INT alphaHint;
  6277. // the alpha transparency could change if the bitmap has changed
  6278. HRESULT hr = Bmp->GetAlphaHint(&alphaHint);
  6279. if (SUCCEEDED(hr))
  6280. {
  6281. // It's unfortunate that GpMemoryBitmap does not have
  6282. // a DpTransparency flag internally, but there's a conflict
  6283. // with imaging.dll and the include file structure that for
  6284. // now makes it necessary to keep a separate type for this info.
  6285. // In fact, ultimately it would be best if the overlap
  6286. // between DpBitmap and GpMemoryBitmap is resolved including
  6287. // a DpBitmap structure within the GpMemoryBitmap and then
  6288. // removing the redundant info out GpMemoryBitmap.
  6289. switch (alphaHint)
  6290. {
  6291. case GpMemoryBitmap::ALPHA_SIMPLE:
  6292. *transparency = TransparencySimple;
  6293. break;
  6294. case GpMemoryBitmap::ALPHA_OPAQUE:
  6295. *transparency = TransparencyOpaque;
  6296. break;
  6297. case GpMemoryBitmap::ALPHA_NONE:
  6298. *transparency = TransparencyNoAlpha;
  6299. break;
  6300. case GpMemoryBitmap::ALPHA_COMPLEX:
  6301. *transparency = TransparencyComplex;
  6302. break;
  6303. case GpMemoryBitmap::ALPHA_NEARCONSTANT:
  6304. *transparency = TransparencyNearConstant;
  6305. if (minA != NULL && maxA != NULL)
  6306. {
  6307. // if the flag is nearconstant alpha, we must have got valid min and max alpha
  6308. Bmp->GetMinMaxAlpha(minA, maxA);
  6309. }
  6310. break;
  6311. default:
  6312. *transparency = TransparencyUnknown;
  6313. break;
  6314. }
  6315. status = Ok;
  6316. // printing needs more accuarate info and is always loaded into memory
  6317. // before send down to the printer drivers
  6318. // 16bpp1555 is handled at initialization already.
  6319. // TransparencyUnknown means the bitmap can have alpha we just don't know what we have
  6320. // TransparencyNoAlpha means the bitmap format doesn't support alpha
  6321. if (*transparency == TransparencyUnknown)
  6322. {
  6323. if (IsAlphaPixelFormat(Bmp->PixelFormat))
  6324. {
  6325. // the memory bitmap must be locked before we enter here
  6326. // We don't require the object to be locked. The object should be
  6327. // decoded already in memory. This is true in the case of DrvDrawImage
  6328. // and texture brush images.
  6329. //ASSERT(ObjRefCount > 1);
  6330. *transparency = TransparencyOpaque;
  6331. if ((Bmp->PixelFormat == PIXFMT_32BPP_ARGB) || (Bmp->PixelFormat == PIXFMT_32BPP_PARGB))
  6332. {
  6333. *transparency = TransparencyOpaque;
  6334. UINT x, y;
  6335. BYTE *scanStart = static_cast<BYTE *>(Bmp->Scan0);
  6336. ARGB *scanPtr;
  6337. for (y = 0; y < Bmp->Height; y++)
  6338. {
  6339. scanPtr = reinterpret_cast<ARGB *>(scanStart);
  6340. for (x = 0; x < Bmp->Width; x++)
  6341. {
  6342. argb = (*scanPtr++) & 0xff000000;
  6343. if (argb < minAlpha)
  6344. {
  6345. minAlpha = argb;
  6346. }
  6347. if (argb > maxAlpha)
  6348. {
  6349. maxAlpha = argb;
  6350. }
  6351. if (argb != 0xff000000)
  6352. {
  6353. if (argb == 0)
  6354. {
  6355. // Prefast bug 518296 - the condition below is always true, this is definitely a bug
  6356. // and the || must be replaced with &&. We have no precedent however that this
  6357. // causes customer problems, hence it does not meet the SP bar.
  6358. /*
  6359. if ((*transparency != TransparencyComplex) ||
  6360. (*transparency != TransparencyNearConstant))
  6361. */
  6362. {
  6363. *transparency = TransparencySimple;
  6364. }
  6365. }
  6366. else
  6367. {
  6368. if ((maxAlpha - minAlpha) <= (NEARCONSTANTALPHA << 24))
  6369. {
  6370. *transparency = TransparencyNearConstant;
  6371. }
  6372. else
  6373. {
  6374. *transparency = TransparencyComplex;
  6375. goto done;
  6376. }
  6377. }
  6378. }
  6379. }
  6380. scanStart += Bmp->Stride;
  6381. }
  6382. goto done;
  6383. }
  6384. else
  6385. {
  6386. RIP(("TransparencyUnknown returned for pixel format w/ alpha"));
  6387. goto done;
  6388. }
  6389. }
  6390. else if (IsIndexedPixelFormat(Bmp->PixelFormat) &&
  6391. Bmp->colorpal)
  6392. {
  6393. // Compute transparancy hint from palette
  6394. // if we worry about cases
  6395. // that the transparent index is not used in the bitmap
  6396. // then we have to scan the whole bitmap.
  6397. // I believe this is sufficient for now unless someone
  6398. // run into problems that really need to scan the whole bitmap
  6399. *transparency = TransparencyOpaque;
  6400. for (UINT i = 0; i < Bmp->colorpal->Count; i++)
  6401. {
  6402. argb = Bmp->colorpal->Entries[i] & 0xff000000;
  6403. if (argb < minAlpha)
  6404. {
  6405. minAlpha = argb;
  6406. }
  6407. if (argb > maxAlpha)
  6408. {
  6409. maxAlpha = argb;
  6410. }
  6411. if (argb != 0xff000000)
  6412. {
  6413. if (argb == 0)
  6414. {
  6415. // See the comments above.
  6416. /*
  6417. if ((*transparency != TransparencyComplex) ||
  6418. (*transparency != TransparencyNearConstant))
  6419. */
  6420. {
  6421. *transparency = TransparencySimple;
  6422. }
  6423. }
  6424. else
  6425. {
  6426. if ((maxAlpha - minAlpha) <= (NEARCONSTANTALPHA << 24))
  6427. {
  6428. *transparency = TransparencyNearConstant;
  6429. }
  6430. else
  6431. {
  6432. *transparency = TransparencyComplex;
  6433. goto done;
  6434. }
  6435. }
  6436. }
  6437. }
  6438. goto done;
  6439. }
  6440. else
  6441. {
  6442. // Native pixel format does not support alpha
  6443. *transparency = TransparencyNoAlpha;
  6444. }
  6445. }
  6446. }
  6447. else
  6448. {
  6449. *transparency = TransparencyUnknown;
  6450. }
  6451. }
  6452. else
  6453. {
  6454. status = LoadIntoMemory(loadFormat);
  6455. if (status == Ok)
  6456. {
  6457. ASSERT(Bmp != NULL);
  6458. goto TestBmp;
  6459. }
  6460. *transparency = TransparencyUnknown;
  6461. }
  6462. return status;
  6463. done:
  6464. // Set alpha hint back into GpMemoryBitmap
  6465. // so we don't have to scan the bitmap again later
  6466. if (*transparency == TransparencySimple)
  6467. {
  6468. newAlphaHint = GpMemoryBitmap::ALPHA_SIMPLE;
  6469. }
  6470. else if (*transparency == TransparencyComplex)
  6471. {
  6472. newAlphaHint = GpMemoryBitmap::ALPHA_COMPLEX;
  6473. }
  6474. else if (*transparency == TransparencyNearConstant)
  6475. {
  6476. if (minA != NULL && maxA != NULL)
  6477. {
  6478. *minA = (BYTE)(minAlpha >> 24);
  6479. *maxA = (BYTE)(maxAlpha >> 24);
  6480. }
  6481. Bmp->SetMinMaxAlpha((BYTE)(minAlpha >> 24), (BYTE)(maxAlpha >> 24));
  6482. newAlphaHint = GpMemoryBitmap::ALPHA_NEARCONSTANT;
  6483. }
  6484. else if (*transparency == TransparencyOpaque)
  6485. {
  6486. newAlphaHint = GpMemoryBitmap::ALPHA_OPAQUE;
  6487. }
  6488. Bmp->SetAlphaHint(newAlphaHint);
  6489. return status;
  6490. }
  6491. /**************************************************************************\
  6492. *
  6493. * Function Description:
  6494. *
  6495. * Set the transparency state of the bitmap
  6496. *
  6497. * Arguments:
  6498. *
  6499. * transparency Returned state
  6500. *
  6501. * Return Value:
  6502. *
  6503. * Status code
  6504. *
  6505. \**************************************************************************/
  6506. GpStatus
  6507. CopyOnWriteBitmap::SetTransparencyHint(
  6508. DpTransparency transparency
  6509. )
  6510. {
  6511. GpStatus status = GenericError;
  6512. if (Bmp != NULL)
  6513. {
  6514. INT alphaHint;
  6515. // It's unfortunate that GpMemoryBitmap does not have
  6516. // a DpTransparency flag internally, but there's a conflict
  6517. // with imaging.dll and the include file structure that for
  6518. // now makes it necessary to keep a separate type for this info.
  6519. // In fact, ultimately it would be best if the overlap
  6520. // between DpBitmap and GpMemoryBitmap is resolved including
  6521. // a DpBitmap structure within the GpMemoryBitmap and then
  6522. // removing the redundant info out GpMemoryBitmap.
  6523. switch (transparency)
  6524. {
  6525. case TransparencySimple:
  6526. alphaHint = GpMemoryBitmap::ALPHA_SIMPLE;
  6527. break;
  6528. case TransparencyOpaque:
  6529. alphaHint = GpMemoryBitmap::ALPHA_OPAQUE;
  6530. break;
  6531. case TransparencyNoAlpha:
  6532. alphaHint = GpMemoryBitmap::ALPHA_NONE;
  6533. break;
  6534. case TransparencyUnknown:
  6535. alphaHint = GpMemoryBitmap::ALPHA_UNKNOWN;
  6536. break;
  6537. default:
  6538. alphaHint = GpMemoryBitmap::ALPHA_COMPLEX;
  6539. break;
  6540. }
  6541. HRESULT hr = Bmp->SetAlphaHint(alphaHint);
  6542. if (SUCCEEDED(hr))
  6543. status = Ok;
  6544. }
  6545. return status;
  6546. }
  6547. /**************************************************************************\
  6548. *
  6549. * Function Description:
  6550. *
  6551. * Rotate and Flip the image in memory.
  6552. *
  6553. * Arguments:
  6554. *
  6555. * [IN]rfType -- Rotate and Flip type
  6556. *
  6557. * Return Value:
  6558. *
  6559. * Status code
  6560. *
  6561. * Revision History:
  6562. *
  6563. * 10/06/2000 minliu
  6564. * Created it.
  6565. *
  6566. \**************************************************************************/
  6567. GpStatus
  6568. CopyOnWriteBitmap::RotateFlip(
  6569. RotateFlipType rfType
  6570. )
  6571. {
  6572. if ( rfType == RotateNoneFlipNone )
  6573. {
  6574. // Same for Rotate180FlipXY, this is a No-OP
  6575. return Ok;
  6576. }
  6577. if ( (IsDirty() == FALSE)
  6578. &&(State >= MemBitmap)
  6579. &&(SrcImageInfo.PixelFormat != PixelFormatInMem)
  6580. &&(Img != NULL) )
  6581. {
  6582. // If the image is:
  6583. // 1) Not dirty
  6584. // 2) Was loaded into memory with different color depth for some reason,
  6585. // like DrawImage()
  6586. // 3) We have an source image
  6587. //
  6588. // Then we can throw away the bits in memory and reload the bits from
  6589. // the original. The purpose of this is that we should always do Rotate
  6590. // or Flip on the original image.
  6591. ASSERT( Bmp != NULL )
  6592. Bmp->Release();
  6593. Bmp = NULL;
  6594. State = DecodedImg;
  6595. PixelFormatInMem = PixelFormatUndefined;
  6596. }
  6597. // Rotate and Flip OP can only be done in memory
  6598. // If the image hasn't been loaded, load into memory with the original
  6599. // pixel format
  6600. GpStatus status = LoadIntoMemory(SrcImageInfo.PixelFormat);
  6601. if ( status != Ok )
  6602. {
  6603. WARNING(("CopyOnWriteBitmap::RotateFlip---LoadIntoMemory() failed"));
  6604. return status;
  6605. }
  6606. IBitmapImage* newBmp = NULL;
  6607. HRESULT hResult = S_OK;
  6608. switch ( rfType )
  6609. {
  6610. case Rotate90FlipNone:
  6611. // Rotate270FlipXY = Rotate90FlipNone
  6612. hResult = Bmp->Rotate(90, INTERP_DEFAULT, &newBmp);
  6613. break;
  6614. case Rotate180FlipNone:
  6615. // RotateNoneFlipXY = Rotate180FlipNone
  6616. hResult = Bmp->Rotate(180, INTERP_DEFAULT, &newBmp);
  6617. break;
  6618. case Rotate270FlipNone:
  6619. // Rotate90FlipXY
  6620. hResult = Bmp->Rotate(270, INTERP_DEFAULT, &newBmp);
  6621. break;
  6622. case RotateNoneFlipX:
  6623. // Rotate180FlipY = RotateNoneFlipX
  6624. hResult = Bmp->Flip(TRUE, FALSE, &newBmp);
  6625. break;
  6626. case Rotate90FlipX:
  6627. // Rotate270FlipY = Rotate90FlipX
  6628. hResult = Bmp->Rotate(90, INTERP_DEFAULT, &newBmp);
  6629. if ( SUCCEEDED(hResult) )
  6630. {
  6631. Bmp->Release();
  6632. Bmp = (GpMemoryBitmap*)newBmp;
  6633. hResult = Bmp->Flip(TRUE, FALSE, &newBmp);
  6634. }
  6635. break;
  6636. case Rotate180FlipX:
  6637. // RotateNoneFlipY = Rotate180FlipX
  6638. hResult = Bmp->Rotate(180, INTERP_DEFAULT, &newBmp);
  6639. if ( SUCCEEDED(hResult) )
  6640. {
  6641. Bmp->Release();
  6642. Bmp = (GpMemoryBitmap*)newBmp;
  6643. hResult = Bmp->Flip(TRUE, FALSE, &newBmp);
  6644. }
  6645. break;
  6646. case Rotate270FlipX:
  6647. // Rotate90FlipY = Rotate270FlipX
  6648. hResult = Bmp->Rotate(270, INTERP_DEFAULT, &newBmp);
  6649. if ( SUCCEEDED(hResult) )
  6650. {
  6651. Bmp->Release();
  6652. Bmp = (GpMemoryBitmap*)newBmp;
  6653. hResult = Bmp->Flip(TRUE, FALSE, &newBmp);
  6654. }
  6655. break;
  6656. default:
  6657. WARNING(("CopyOnWriteBitmap::RotateFlip---Invalid input parameter"));
  6658. return InvalidParameter;
  6659. }
  6660. if ( FAILED(hResult) )
  6661. {
  6662. WARNING(("CopyOnWriteBitmap::RotateFlip---Rotate failed"));
  6663. return Win32Error;
  6664. }
  6665. // Check how many property items in this image
  6666. UINT uiNumOfProperty = 0;
  6667. status = GetPropertyCount(&uiNumOfProperty);
  6668. if ( status != Ok )
  6669. {
  6670. // It is OK if we failed to get property. We still have the Rotate/Flip
  6671. // result
  6672. WARNING(("CopyOnWriteBitmap::RotateFlip---GetPropertyCount() failed"));
  6673. }
  6674. if ( uiNumOfProperty > 0 )
  6675. {
  6676. PROPID* pList = (PROPID*)GpMalloc(uiNumOfProperty * sizeof(PROPID));
  6677. if ( pList == NULL )
  6678. {
  6679. WARNING(("CopyOnWriteBitmap::RotateFlip---GpMalloc() failed"));
  6680. return OutOfMemory;
  6681. }
  6682. status = GetPropertyIdList(uiNumOfProperty, pList);
  6683. if ( status != Ok )
  6684. {
  6685. WARNING(("COnWriteBitmap::RotateFlip-GetPropertyIdList() failed"));
  6686. GpFree(pList);
  6687. return status;
  6688. }
  6689. UINT uiItemSize = 0;
  6690. PropertyItem* pItem = NULL;
  6691. GpMemoryBitmap* pTempBmp = (GpMemoryBitmap*)newBmp;
  6692. // Loop through all the property items, get it from current image and
  6693. // set it to the new image. Filter out and adjust some if necessary
  6694. for ( int i = 0; i < (int)uiNumOfProperty; ++i )
  6695. {
  6696. // Get size for the i th property item
  6697. status = GetPropertyItemSize(pList[i], &uiItemSize);
  6698. if ( status != Ok )
  6699. {
  6700. WARNING(("COWBitmap::RotateFlip-GetPropertyItemSize() failed"));
  6701. GpFree(pList);
  6702. return status;
  6703. }
  6704. // Allocate memory buffer for receiving it
  6705. pItem = (PropertyItem*)GpMalloc(uiItemSize);
  6706. if ( pItem == NULL )
  6707. {
  6708. WARNING(("CopyOnWriteBitmap::RotateFlip---GpMalloc() failed"));
  6709. GpFree(pList);
  6710. return OutOfMemory;
  6711. }
  6712. // Get the i th property item
  6713. status = GetPropertyItem(pList[i], uiItemSize, pItem);
  6714. if ( status != Ok )
  6715. {
  6716. WARNING(("COWriteBitmap::RotateFlip-GetPropertyItem() failed"));
  6717. GpFree(pItem);
  6718. GpFree(pList);
  6719. return status;
  6720. }
  6721. // We need to do some property information adjustment here according
  6722. // to the rfType
  6723. if ( (rfType == Rotate90FlipNone)
  6724. ||(rfType == Rotate270FlipNone)
  6725. ||(rfType == Rotate90FlipX)
  6726. ||(rfType == Rotate270FlipX) )
  6727. {
  6728. // Swap the X and Y dimension info if rotate 90 or 270
  6729. switch ( pList[i] )
  6730. {
  6731. case PropertyTagImageWidth:
  6732. pItem->id = PropertyTagImageHeight;
  6733. break;
  6734. case PropertyTagImageHeight:
  6735. pItem->id = PropertyTagImageWidth;
  6736. break;
  6737. case PropertyTagXResolution:
  6738. pItem->id = PropertyTagYResolution;
  6739. break;
  6740. case PropertyTagYResolution:
  6741. pItem->id = PropertyTagXResolution;
  6742. break;
  6743. case PropertyTagResolutionXUnit:
  6744. pItem->id = PropertyTagResolutionYUnit;
  6745. break;
  6746. case PropertyTagResolutionYUnit:
  6747. pItem->id = PropertyTagResolutionXUnit;
  6748. break;
  6749. case PropertyTagResolutionXLengthUnit:
  6750. pItem->id = PropertyTagResolutionYLengthUnit;
  6751. break;
  6752. case PropertyTagResolutionYLengthUnit:
  6753. pItem->id = PropertyTagResolutionXLengthUnit;
  6754. break;
  6755. case PropertyTagExifPixXDim:
  6756. pItem->id = PropertyTagExifPixYDim;
  6757. break;
  6758. case PropertyTagExifPixYDim:
  6759. pItem->id = PropertyTagExifPixXDim;
  6760. break;
  6761. default:
  6762. // For rest of property IDs, no need to swap
  6763. break;
  6764. }
  6765. }// Case of rotate 90 degree
  6766. // Set the property item in the new GpMemoryBitmap object
  6767. hResult = pTempBmp->SetPropertyItem(*pItem);
  6768. if ( hResult != S_OK )
  6769. {
  6770. WARNING(("COWriteBitmap::RotateFlip-SetPropertyItem() failed"));
  6771. GpFree(pItem);
  6772. GpFree(pList);
  6773. return MapHRESULTToGpStatus(hResult);
  6774. }
  6775. GpFree(pItem);
  6776. pItem = NULL;
  6777. }// Loop through all the property items
  6778. GpFree(pList);
  6779. }// if ( uiNumOfProperty > 0 )
  6780. // Replace the image
  6781. Bmp->Release();
  6782. Bmp = (GpMemoryBitmap*)newBmp;
  6783. State = MemBitmap;
  6784. // Set special hack for JPEG image
  6785. if (Img && (SpecialJPEGSave == TRUE))
  6786. {
  6787. Bmp->SetSpecialJPEG(Img);
  6788. }
  6789. SetDirtyFlag(TRUE);
  6790. // Since this image is dirty now, we don't need to have any connection
  6791. // with the original image if there is one
  6792. GpFree(Filename);
  6793. Filename = NULL;
  6794. if ( NULL != Stream )
  6795. {
  6796. Stream->Release();
  6797. Stream = NULL;
  6798. }
  6799. // We can't release the Img pointer until save() is called if this is a
  6800. // special JPEG lossless transform save case
  6801. if (Img && (SpecialJPEGSave == FALSE))
  6802. {
  6803. Img->Release();
  6804. Img = NULL;
  6805. }
  6806. // Update image info
  6807. hResult = Bmp->GetImageInfo(&SrcImageInfo);
  6808. if ( SUCCEEDED(hResult) )
  6809. {
  6810. PixelFormatInMem = SrcImageInfo.PixelFormat;
  6811. }
  6812. else
  6813. {
  6814. WARNING(("CopyOnWriteBitmap::RotateFlip---GetImageInfo() failed"));
  6815. return MapHRESULTToGpStatus(hResult);
  6816. }
  6817. return Ok;
  6818. }// RotateFlip()
  6819. // -------------------------------------------------------------------------
  6820. GpBitmap::GpBitmap(
  6821. const CopyOnWriteBitmap * internalBitmap
  6822. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6823. {
  6824. ASSERT((internalBitmap != NULL) && internalBitmap->IsValid());
  6825. InternalBitmap = (CopyOnWriteBitmap *)internalBitmap;
  6826. InternalBitmap->AddRef();
  6827. ScanBitmap.SetBitmap(this);
  6828. }
  6829. GpBitmap::GpBitmap(
  6830. BOOL createInternalBitmap
  6831. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6832. {
  6833. if (createInternalBitmap)
  6834. {
  6835. // this case is used by the object factory for metafile playback
  6836. InternalBitmap = new CopyOnWriteBitmap();
  6837. }
  6838. else
  6839. {
  6840. InternalBitmap = NULL;
  6841. }
  6842. ScanBitmap.SetBitmap(this);
  6843. }
  6844. GpBitmap::GpBitmap(
  6845. const GpBitmap * bitmap
  6846. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6847. {
  6848. ASSERT ((bitmap != NULL) && (bitmap->InternalBitmap != NULL) && bitmap->InternalBitmap->IsValid());
  6849. InternalBitmap = (CopyOnWriteBitmap *)bitmap->InternalBitmap;
  6850. InternalBitmap->AddRef();
  6851. ScanBitmap.SetBitmap(this);
  6852. }
  6853. // Destructor
  6854. // We don't want apps to use delete operator directly.
  6855. // Instead, they should use the Dispose method.
  6856. GpBitmap::~GpBitmap()
  6857. {
  6858. if (InternalBitmap != NULL)
  6859. {
  6860. InternalBitmap->Release();
  6861. InternalBitmap = NULL;
  6862. }
  6863. ScanBitmap.FreeData();
  6864. }
  6865. CopyOnWriteBitmap *
  6866. GpBitmap::LockForWrite()
  6867. {
  6868. ASSERT(InternalBitmap != NULL);
  6869. CopyOnWriteBitmap * writeableBitmap;
  6870. writeableBitmap = (CopyOnWriteBitmap *)InternalBitmap->LockForWrite();
  6871. if (writeableBitmap != NULL)
  6872. {
  6873. InternalBitmap = writeableBitmap;
  6874. UpdateUid();
  6875. return writeableBitmap;
  6876. }
  6877. return NULL;
  6878. }
  6879. VOID
  6880. GpBitmap::Unlock() const
  6881. {
  6882. ASSERT(InternalBitmap != NULL);
  6883. BOOL valid = InternalBitmap->IsValid();
  6884. InternalBitmap->Unlock();
  6885. // If the operation we did on the internal bitmap somehow invalidated
  6886. // it then invalidate this GpBitmap object as well.
  6887. if (!valid)
  6888. {
  6889. InternalBitmap->Release();
  6890. ((GpBitmap *)this)->InternalBitmap = NULL;
  6891. }
  6892. }
  6893. VOID
  6894. GpBitmap::LockForRead() const
  6895. {
  6896. ASSERT(InternalBitmap != NULL);
  6897. InternalBitmap->LockForRead();
  6898. }
  6899. // Constructors
  6900. GpBitmap::GpBitmap(
  6901. const WCHAR* filename
  6902. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6903. {
  6904. InternalBitmap = CopyOnWriteBitmap::Create(filename);
  6905. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6906. ScanBitmap.SetBitmap(this);
  6907. }
  6908. GpBitmap::GpBitmap(
  6909. IStream* stream
  6910. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6911. {
  6912. InternalBitmap = CopyOnWriteBitmap::Create(stream);
  6913. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6914. ScanBitmap.SetBitmap(this);
  6915. }
  6916. GpBitmap::GpBitmap(
  6917. INT width,
  6918. INT height,
  6919. PixelFormatID format
  6920. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6921. {
  6922. InternalBitmap = CopyOnWriteBitmap::Create(width, height, format);
  6923. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6924. ScanBitmap.SetBitmap(this);
  6925. }
  6926. GpBitmap::GpBitmap(
  6927. INT width,
  6928. INT height,
  6929. PixelFormatID format,
  6930. GpGraphics * graphics
  6931. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6932. {
  6933. InternalBitmap = CopyOnWriteBitmap::Create(width, height, format, graphics);
  6934. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6935. ScanBitmap.SetBitmap(this);
  6936. }
  6937. GpBitmap::GpBitmap(
  6938. INT width,
  6939. INT height,
  6940. INT stride, // negative for bottom-up bitmaps
  6941. PixelFormatID format,
  6942. BYTE * scan0
  6943. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6944. {
  6945. InternalBitmap = CopyOnWriteBitmap::Create(width, height, stride, format, scan0);
  6946. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6947. ScanBitmap.SetBitmap(this);
  6948. }
  6949. GpBitmap::GpBitmap(
  6950. BITMAPINFO* gdiBitmapInfo,
  6951. VOID* gdiBitmapData,
  6952. BOOL ownBitmapData
  6953. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6954. {
  6955. InternalBitmap = CopyOnWriteBitmap::Create(gdiBitmapInfo, gdiBitmapData, ownBitmapData);
  6956. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6957. ScanBitmap.SetBitmap(this);
  6958. }
  6959. GpBitmap::GpBitmap(
  6960. IDirectDrawSurface7 * surface
  6961. ) : GpImage(ImageTypeBitmap), ScanBitmapRef(1)
  6962. {
  6963. InternalBitmap = CopyOnWriteBitmap::Create(surface);
  6964. ASSERT((InternalBitmap == NULL) || InternalBitmap->IsValid());
  6965. ScanBitmap.SetBitmap(this);
  6966. }
  6967. GpImage*
  6968. GpBitmap::Clone() const
  6969. {
  6970. return new GpBitmap(this);
  6971. }
  6972. GpBitmap*
  6973. GpBitmap::Clone(
  6974. const GpRect* rect,
  6975. PixelFormatID format
  6976. ) const
  6977. {
  6978. BOOL isFullRect;
  6979. isFullRect = ((rect == NULL) ||
  6980. ((rect->X == 0) && (rect->Y == 0) &&
  6981. (rect->Width == (INT)InternalBitmap->SrcImageInfo.Width) &&
  6982. (rect->Height == (INT)InternalBitmap->SrcImageInfo.Height)));
  6983. // If rect is full size and format is same,
  6984. // don't have to clone InternalBitmap.
  6985. if (isFullRect &&
  6986. ((format == PixelFormatDontCare) ||
  6987. (format == InternalBitmap->SrcImageInfo.PixelFormat)))
  6988. {
  6989. return (GpBitmap *)this->Clone();
  6990. }
  6991. // else we have to do a clone of the internal bitmap
  6992. GpBitmap * newBitmap = new GpBitmap(FALSE);
  6993. if (newBitmap != NULL)
  6994. {
  6995. LockForRead();
  6996. if (isFullRect)
  6997. {
  6998. // It's faster to do the clone followed by the convert than
  6999. // to do the convert as part of the clone.
  7000. newBitmap->InternalBitmap = (CopyOnWriteBitmap *)InternalBitmap->Clone();
  7001. if (newBitmap->InternalBitmap != NULL)
  7002. {
  7003. if (newBitmap->InternalBitmap->ConvertFormat(format, NULL, NULL) != Ok)
  7004. {
  7005. newBitmap->InternalBitmap->Release();
  7006. newBitmap->InternalBitmap = NULL;
  7007. }
  7008. }
  7009. }
  7010. else
  7011. {
  7012. newBitmap->InternalBitmap = InternalBitmap->Clone(rect, format);
  7013. }
  7014. Unlock();
  7015. if (newBitmap->InternalBitmap == NULL)
  7016. {
  7017. delete newBitmap;
  7018. newBitmap = NULL;
  7019. }
  7020. else
  7021. {
  7022. ASSERT(newBitmap->InternalBitmap->IsValid());
  7023. }
  7024. }
  7025. return newBitmap;
  7026. }
  7027. GpImage*
  7028. GpBitmap::CloneColorAdjusted(
  7029. GpRecolor * recolor,
  7030. ColorAdjustType type
  7031. ) const
  7032. {
  7033. GpBitmap * newBitmap = new GpBitmap(FALSE);
  7034. if (newBitmap != NULL)
  7035. {
  7036. LockForRead();
  7037. newBitmap->InternalBitmap = InternalBitmap->CloneColorAdjusted(recolor, type);
  7038. Unlock();
  7039. if (newBitmap->InternalBitmap == NULL)
  7040. {
  7041. delete newBitmap;
  7042. newBitmap = NULL;
  7043. }
  7044. else
  7045. {
  7046. ASSERT(newBitmap->InternalBitmap->IsValid());
  7047. }
  7048. }
  7049. return newBitmap;
  7050. }
  7051. // Similar to CloneColorAdjusted
  7052. GpStatus
  7053. GpBitmap::Recolor(
  7054. GpRecolor * recolor,
  7055. GpBitmap ** dstBitmap,
  7056. DrawImageAbort callback,
  7057. VOID * callbackData,
  7058. GpRect * rect
  7059. )
  7060. {
  7061. GpStatus status = GenericError;
  7062. if (dstBitmap == NULL)
  7063. {
  7064. // recolor this object -- need write lock
  7065. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7066. if (writeableBitmap != NULL)
  7067. {
  7068. status = writeableBitmap->Recolor(recolor, NULL, callback, callbackData, rect);
  7069. writeableBitmap->Unlock();
  7070. UpdateUid();
  7071. }
  7072. }
  7073. else // recolor into dstBitmap
  7074. {
  7075. GpBitmap * newBitmap = new GpBitmap(FALSE);
  7076. if (newBitmap != NULL)
  7077. {
  7078. LockForRead();
  7079. status = InternalBitmap->Recolor(recolor, &newBitmap->InternalBitmap, callback, callbackData, rect);
  7080. Unlock();
  7081. if (status != Ok)
  7082. {
  7083. delete newBitmap;
  7084. newBitmap = NULL;
  7085. }
  7086. else
  7087. {
  7088. ASSERT((newBitmap->InternalBitmap != NULL) && (newBitmap->InternalBitmap->IsValid()));
  7089. }
  7090. }
  7091. *dstBitmap = newBitmap;
  7092. }
  7093. return status;
  7094. }
  7095. GpStatus
  7096. GpBitmap::GetEncoderParameterListSize(
  7097. IN CLSID* clsidEncoder,
  7098. OUT UINT* size
  7099. )
  7100. {
  7101. GpStatus status;
  7102. LockForRead();
  7103. status = InternalBitmap->GetEncoderParameterListSize(clsidEncoder, size);
  7104. Unlock();
  7105. return status;
  7106. }
  7107. GpStatus
  7108. GpBitmap::GetEncoderParameterList(
  7109. IN CLSID* clsidEncoder,
  7110. IN UINT size,
  7111. OUT EncoderParameters* pBuffer
  7112. )
  7113. {
  7114. GpStatus status;
  7115. LockForRead();
  7116. status = InternalBitmap->GetEncoderParameterList(clsidEncoder, size, pBuffer);
  7117. Unlock();
  7118. return status;
  7119. }
  7120. GpStatus
  7121. GpBitmap::SaveToStream(
  7122. IStream* stream,
  7123. CLSID* clsidEncoder,
  7124. EncoderParameters* encoderParams
  7125. )
  7126. {
  7127. GpStatus status;
  7128. LockForRead();
  7129. status = InternalBitmap->SaveToStream(stream, clsidEncoder, encoderParams);
  7130. Unlock();
  7131. return status;
  7132. }
  7133. GpStatus
  7134. GpBitmap::SaveToFile(
  7135. const WCHAR* filename,
  7136. CLSID* clsidEncoder,
  7137. EncoderParameters* encoderParams
  7138. )
  7139. {
  7140. GpStatus status;
  7141. LockForRead();
  7142. status = InternalBitmap->SaveToFile(filename, clsidEncoder, encoderParams);
  7143. Unlock();
  7144. return status;
  7145. }
  7146. GpStatus
  7147. GpBitmap::SaveAdd(
  7148. const EncoderParameters* encoderParams
  7149. )
  7150. {
  7151. GpStatus status;
  7152. LockForRead();
  7153. status = InternalBitmap->SaveAdd(encoderParams);
  7154. Unlock();
  7155. return status;
  7156. }
  7157. GpStatus
  7158. GpBitmap::SaveAdd(
  7159. GpImage* newBits,
  7160. const EncoderParameters* encoderParams
  7161. )
  7162. {
  7163. ASSERT(newBits != NULL);
  7164. GpStatus status = InvalidParameter;
  7165. if (newBits->GetImageType() == ImageTypeBitmap)
  7166. {
  7167. LockForRead();
  7168. status = InternalBitmap->SaveAdd(((GpBitmap *)newBits)->InternalBitmap, encoderParams);
  7169. Unlock();
  7170. }
  7171. return status;
  7172. }
  7173. // Dispose the bitmap object
  7174. VOID
  7175. GpBitmap::Dispose()
  7176. {
  7177. if (InterlockedDecrement(&ScanBitmapRef) <= 0)
  7178. {
  7179. delete this;
  7180. }
  7181. }
  7182. // Get bitmap information
  7183. GpStatus
  7184. GpBitmap::GetResolution(
  7185. REAL* xdpi,
  7186. REAL* ydpi
  7187. ) const
  7188. {
  7189. GpStatus status = Ok;
  7190. LockForRead();
  7191. *xdpi = (REAL)InternalBitmap->SrcImageInfo.Xdpi;
  7192. *ydpi = (REAL)InternalBitmap->SrcImageInfo.Ydpi;
  7193. Unlock();
  7194. return status;
  7195. }
  7196. GpStatus
  7197. GpBitmap::GetPhysicalDimension(
  7198. REAL* width,
  7199. REAL* height
  7200. ) const
  7201. {
  7202. GpStatus status = Ok;
  7203. LockForRead();
  7204. *width = (REAL)InternalBitmap->SrcImageInfo.Width;
  7205. *height = (REAL)InternalBitmap->SrcImageInfo.Height;
  7206. Unlock();
  7207. return status;
  7208. }
  7209. GpStatus
  7210. GpBitmap::GetBounds(
  7211. GpRectF* rect,
  7212. GpPageUnit* unit
  7213. ) const
  7214. {
  7215. GpStatus status = Ok;
  7216. LockForRead();
  7217. rect->X = rect->Y = 0;
  7218. rect->Width = (REAL) InternalBitmap->SrcImageInfo.Width;
  7219. rect->Height = (REAL) InternalBitmap->SrcImageInfo.Height;
  7220. *unit = UnitPixel;
  7221. Unlock();
  7222. return status;
  7223. }
  7224. GpStatus
  7225. GpBitmap::GetSize(
  7226. Size* size
  7227. ) const
  7228. {
  7229. GpStatus status = Ok;
  7230. LockForRead();
  7231. size->Width = InternalBitmap->SrcImageInfo.Width;
  7232. size->Height = InternalBitmap->SrcImageInfo.Height;
  7233. Unlock();
  7234. return status;
  7235. }
  7236. GpStatus
  7237. GpBitmap::GetImageInfo(
  7238. ImageInfo * imageInfo
  7239. ) const
  7240. {
  7241. if (NULL == imageInfo)
  7242. {
  7243. return InvalidParameter;
  7244. }
  7245. GpStatus status = Ok;
  7246. LockForRead();
  7247. InternalBitmap->GetImageInfo(imageInfo);
  7248. Unlock();
  7249. return status;
  7250. }
  7251. GpImage*
  7252. GpBitmap::GetThumbnail(
  7253. UINT thumbWidth,
  7254. UINT thumbHeight,
  7255. GetThumbnailImageAbort callback,
  7256. VOID * callbackData
  7257. )
  7258. {
  7259. GpBitmap * newBitmap = new GpBitmap(FALSE);
  7260. if (newBitmap != NULL)
  7261. {
  7262. LockForRead();
  7263. newBitmap->InternalBitmap = InternalBitmap->GetThumbnail(thumbWidth, thumbHeight, callback, callbackData);
  7264. Unlock();
  7265. if (newBitmap->InternalBitmap == NULL)
  7266. {
  7267. delete newBitmap;
  7268. newBitmap = NULL;
  7269. }
  7270. else
  7271. {
  7272. ASSERT(newBitmap->InternalBitmap->IsValid());
  7273. }
  7274. }
  7275. return newBitmap;
  7276. }
  7277. GpStatus
  7278. GpBitmap::GetFrameCount(
  7279. const GUID* dimensionID,
  7280. UINT* count
  7281. ) const
  7282. {
  7283. GpStatus status;
  7284. LockForRead();
  7285. status = InternalBitmap->GetFrameCount(dimensionID, count);
  7286. Unlock();
  7287. return status;
  7288. }
  7289. GpStatus
  7290. GpBitmap::GetFrameDimensionsCount(
  7291. OUT UINT* count
  7292. ) const
  7293. {
  7294. GpStatus status;
  7295. LockForRead();
  7296. status = InternalBitmap->GetFrameDimensionsCount(count);
  7297. Unlock();
  7298. return status;
  7299. }
  7300. GpStatus
  7301. GpBitmap::GetFrameDimensionsList(
  7302. OUT GUID* dimensionIDs,
  7303. IN UINT count
  7304. ) const
  7305. {
  7306. GpStatus status;
  7307. LockForRead();
  7308. status = InternalBitmap->GetFrameDimensionsList(dimensionIDs, count);
  7309. Unlock();
  7310. return status;
  7311. }
  7312. GpStatus
  7313. GpBitmap::SelectActiveFrame(
  7314. const GUID* dimensionID,
  7315. UINT frameIndex
  7316. )
  7317. {
  7318. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7319. if (writeableBitmap != NULL)
  7320. {
  7321. GpStatus status;
  7322. status = writeableBitmap->SelectActiveFrame(dimensionID, frameIndex);
  7323. writeableBitmap->Unlock();
  7324. UpdateUid();
  7325. return status;
  7326. }
  7327. return GenericError;
  7328. }
  7329. GpStatus
  7330. GpBitmap::GetPalette(
  7331. ColorPalette * palette,
  7332. INT size
  7333. )
  7334. {
  7335. GpStatus status;
  7336. LockForRead();
  7337. status = InternalBitmap->GetPalette(palette, size);
  7338. Unlock();
  7339. return status;
  7340. }
  7341. GpStatus
  7342. GpBitmap::SetPalette(
  7343. ColorPalette * palette
  7344. )
  7345. {
  7346. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7347. if (writeableBitmap != NULL)
  7348. {
  7349. GpStatus status;
  7350. status = writeableBitmap->SetPalette(palette);
  7351. writeableBitmap->Unlock();
  7352. UpdateUid();
  7353. return status;
  7354. }
  7355. return GenericError;
  7356. }
  7357. INT
  7358. GpBitmap::GetPaletteSize()
  7359. {
  7360. INT size;
  7361. LockForRead();
  7362. size = InternalBitmap->GetPaletteSize();
  7363. Unlock();
  7364. return size;
  7365. }
  7366. GpStatus
  7367. GpBitmap::GetTransparencyHint(
  7368. DpTransparency* transparency
  7369. )
  7370. {
  7371. GpStatus status;
  7372. LockForRead();
  7373. status = InternalBitmap->GetTransparencyHint(transparency);
  7374. Unlock();
  7375. return status;
  7376. }
  7377. GpStatus
  7378. GpBitmap::SetTransparencyHint(
  7379. DpTransparency transparency
  7380. )
  7381. {
  7382. GpStatus status;
  7383. LockForRead();
  7384. status = InternalBitmap->SetTransparencyHint(transparency);
  7385. Unlock();
  7386. UpdateUid();
  7387. return status;
  7388. }
  7389. GpStatus
  7390. GpBitmap::GetTransparencyFlags(
  7391. DpTransparency* transparency,
  7392. PixelFormatID loadFormat,
  7393. BYTE* minAlpha,
  7394. BYTE* maxAlpha
  7395. )
  7396. {
  7397. GpStatus status;
  7398. LockForRead();
  7399. status = InternalBitmap->GetTransparencyFlags(transparency, loadFormat, minAlpha, maxAlpha);
  7400. Unlock();
  7401. return status;
  7402. }
  7403. // Property related functions
  7404. GpStatus
  7405. GpBitmap::GetPropertyCount(
  7406. UINT* numOfProperty
  7407. )
  7408. {
  7409. GpStatus status;
  7410. LockForRead();
  7411. status = InternalBitmap->GetPropertyCount(numOfProperty);
  7412. Unlock();
  7413. return status;
  7414. }
  7415. GpStatus
  7416. GpBitmap::GetPropertyIdList(
  7417. UINT numOfProperty,
  7418. PROPID* list
  7419. )
  7420. {
  7421. GpStatus status;
  7422. LockForRead();
  7423. status = InternalBitmap->GetPropertyIdList(numOfProperty, list);
  7424. Unlock();
  7425. return status;
  7426. }
  7427. GpStatus
  7428. GpBitmap::GetPropertyItemSize(
  7429. PROPID propId,
  7430. UINT* size
  7431. )
  7432. {
  7433. GpStatus status;
  7434. LockForRead();
  7435. status = InternalBitmap->GetPropertyItemSize(propId, size);
  7436. Unlock();
  7437. return status;
  7438. }
  7439. GpStatus
  7440. GpBitmap::GetPropertyItem(
  7441. PROPID propId,
  7442. UINT propSize,
  7443. PropertyItem* buffer
  7444. )
  7445. {
  7446. GpStatus status;
  7447. LockForRead();
  7448. status = InternalBitmap->GetPropertyItem(propId, propSize, buffer);
  7449. Unlock();
  7450. return status;
  7451. }
  7452. GpStatus
  7453. GpBitmap::GetPropertySize(
  7454. UINT* totalBufferSize,
  7455. UINT* numProperties
  7456. )
  7457. {
  7458. GpStatus status;
  7459. LockForRead();
  7460. status = InternalBitmap->GetPropertySize(totalBufferSize, numProperties);
  7461. Unlock();
  7462. return status;
  7463. }
  7464. GpStatus
  7465. GpBitmap::GetAllPropertyItems(
  7466. UINT totalBufferSize,
  7467. UINT numProperties,
  7468. PropertyItem* allItems
  7469. )
  7470. {
  7471. GpStatus status;
  7472. LockForRead();
  7473. status = InternalBitmap->GetAllPropertyItems(totalBufferSize, numProperties, allItems);
  7474. Unlock();
  7475. return status;
  7476. }
  7477. GpStatus
  7478. GpBitmap::RemovePropertyItem(
  7479. PROPID propId
  7480. )
  7481. {
  7482. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7483. if (writeableBitmap != NULL)
  7484. {
  7485. GpStatus status;
  7486. status = writeableBitmap->RemovePropertyItem(propId);
  7487. writeableBitmap->Unlock();
  7488. UpdateUid();
  7489. return status;
  7490. }
  7491. return GenericError;
  7492. }
  7493. GpStatus
  7494. GpBitmap::SetPropertyItem(
  7495. PropertyItem* item
  7496. )
  7497. {
  7498. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7499. if (writeableBitmap != NULL)
  7500. {
  7501. GpStatus status;
  7502. status = writeableBitmap->SetPropertyItem(item);
  7503. writeableBitmap->Unlock();
  7504. UpdateUid();
  7505. return status;
  7506. }
  7507. return GenericError;
  7508. }
  7509. // Retrieve bitmap data
  7510. GpStatus
  7511. GpBitmap::LockBits(
  7512. const GpRect* rect,
  7513. UINT flags,
  7514. PixelFormatID pixelFormat,
  7515. BitmapData* bmpdata,
  7516. INT width,
  7517. INT height
  7518. ) const
  7519. {
  7520. ASSERT(InternalBitmap != NULL);
  7521. if (flags & ImageLockModeWrite)
  7522. {
  7523. CopyOnWriteBitmap * writeableBitmap = ((GpBitmap *)this)->LockForWrite();
  7524. if (writeableBitmap != NULL)
  7525. {
  7526. GpStatus status;
  7527. status = writeableBitmap->LockBits(rect, flags, pixelFormat, bmpdata, width, height);
  7528. writeableBitmap->Unlock();
  7529. return status;
  7530. }
  7531. return GenericError;
  7532. }
  7533. else
  7534. {
  7535. // Lock For read case
  7536. // First we need to check if this is the 1st LockForRead on this image
  7537. // object or not.
  7538. if ( InternalBitmap->ObjRefCount > 1 )
  7539. {
  7540. // We have more than one LockForRead on this object
  7541. // Note: this part needs to be re-visited in V2. We have a big
  7542. // problem here not allowing user to do more than once for LockBits
  7543. // for read. So we need to make a copy even though theory says
  7544. // that we should not have to.
  7545. CopyOnWriteBitmap * writeableBitmap = ((GpBitmap *)this)->LockForWrite();
  7546. if (writeableBitmap != NULL)
  7547. {
  7548. GpStatus status;
  7549. status = writeableBitmap->LockBits(rect, flags, pixelFormat, bmpdata, width, height);
  7550. writeableBitmap->Unlock();
  7551. return status;
  7552. }
  7553. return GenericError;
  7554. }
  7555. else
  7556. {
  7557. GpStatus status;
  7558. LockForRead();
  7559. status = InternalBitmap->LockBits(rect, flags, pixelFormat, bmpdata, width, height);
  7560. Unlock();
  7561. return status;
  7562. }
  7563. }
  7564. }
  7565. GpStatus
  7566. GpBitmap::UnlockBits(
  7567. BitmapData* bmpdata,
  7568. BOOL Destroy
  7569. ) const
  7570. {
  7571. GpStatus status;
  7572. LockForRead();
  7573. status = InternalBitmap->UnlockBits(bmpdata, Destroy);
  7574. Unlock();
  7575. return status;
  7576. }
  7577. // Get and set pixel on the bitmap.
  7578. GpStatus
  7579. GpBitmap::GetPixel(
  7580. INT x,
  7581. INT y,
  7582. ARGB * color
  7583. )
  7584. {
  7585. GpStatus status;
  7586. LockForRead();
  7587. status = InternalBitmap->GetPixel(x, y, color);
  7588. Unlock();
  7589. return status;
  7590. }
  7591. GpStatus
  7592. GpBitmap::SetPixel(
  7593. INT x,
  7594. INT y,
  7595. ARGB color
  7596. )
  7597. {
  7598. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7599. if (writeableBitmap != NULL)
  7600. {
  7601. GpStatus status;
  7602. status = writeableBitmap->SetPixel(x, y, color);
  7603. writeableBitmap->Unlock();
  7604. UpdateUid();
  7605. return status;
  7606. }
  7607. return GenericError;
  7608. }
  7609. GpStatus
  7610. GpBitmap::RotateFlip(
  7611. RotateFlipType rfType
  7612. )
  7613. {
  7614. CopyOnWriteBitmap* pWriteableBitmap = LockForWrite();
  7615. if ( pWriteableBitmap != NULL )
  7616. {
  7617. GpStatus status = pWriteableBitmap->RotateFlip(rfType);
  7618. pWriteableBitmap->Unlock();
  7619. UpdateUid();
  7620. return status;
  7621. }
  7622. return GenericError;
  7623. }// RotateFlip()
  7624. BOOL
  7625. GpBitmap::IsDirty() const
  7626. {
  7627. LockForRead();
  7628. BOOL dirty = InternalBitmap->IsDirty();
  7629. Unlock();
  7630. return dirty;
  7631. }
  7632. // Derive a graphics context on top of the bitmap object
  7633. GpGraphics*
  7634. GpBitmap::GetGraphicsContext()
  7635. {
  7636. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7637. if (writeableBitmap != NULL)
  7638. {
  7639. GpGraphics * g = NULL;
  7640. // NTRAID#NTBUG9-368452-2001-04-13-gilmanw "ISSUE: allow only one GpGraphics per bitmap"
  7641. //
  7642. // Currently create a new GpGraphics each time GetGraphicsContext
  7643. // is called. Perhaps should cache the GpGraphics and return that
  7644. // to all callers. Otherwise, there may be synchronization issues
  7645. // if there are multiple GpGraphics per surface.
  7646. if (writeableBitmap->State == MemBitmap && writeableBitmap->Bmp != NULL &&
  7647. writeableBitmap->Bmp->creationFlag == GpMemoryBitmap::CREATEDFROM_DDRAWSURFACE)
  7648. {
  7649. // NTRAID#NTBUG9-368458-2001-04-13-gilmanw "ISSUE: lose association with Image for DDraw surfs"
  7650. //
  7651. // The Image as well as the graphics are only wrappers around the
  7652. // direct draw surface. When we create the GpGraphics in this
  7653. // way we lose all association with the Image (CopyOnWriteBitmap)
  7654. // object. This may not be the right behavior.
  7655. g = GpGraphics::GetFromDirectDrawSurface(writeableBitmap->Bmp->ddrawSurface);
  7656. }
  7657. else
  7658. {
  7659. ImageInfo imageInfo;
  7660. writeableBitmap->GetImageInfo(&imageInfo);
  7661. // since GpGraphics will end up pointing to ScanBitmap structure
  7662. // we need to make sure bitmap won't be deleted while
  7663. // there is a graphics wrapped around it
  7664. IncScanBitmapRef();
  7665. g = GpGraphics::GetFromGdipBitmap(this, &imageInfo, &ScanBitmap, writeableBitmap->Display);
  7666. if (!CheckValid(g))
  7667. {
  7668. DecScanBitmapRef();
  7669. }
  7670. }
  7671. writeableBitmap->Unlock();
  7672. return g;
  7673. }
  7674. return NULL;
  7675. }
  7676. GpStatus
  7677. GpBitmap::InitializeSurfaceForGdipBitmap(
  7678. DpBitmap * surface,
  7679. INT width,
  7680. INT height
  7681. )
  7682. {
  7683. GpStatus status = Ok;
  7684. // Currently this is only called when preparing a surface as a source
  7685. // surface, not as a dest surface, so we only need a read lock.
  7686. LockForRead();
  7687. ImageInfo imageInfo;
  7688. InternalBitmap->GetImageInfo(&imageInfo);
  7689. surface->InitializeForGdipBitmap(width, height, &imageInfo, &ScanBitmap, InternalBitmap->Display);
  7690. Unlock();
  7691. return status;
  7692. }
  7693. // Derive an HDC for interop on top of the bitmap object
  7694. HDC
  7695. GpBitmap::GetHdc()
  7696. {
  7697. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7698. if (writeableBitmap != NULL)
  7699. {
  7700. HDC hdc;
  7701. hdc = writeableBitmap->GetHdc();
  7702. writeableBitmap->Unlock();
  7703. return hdc;
  7704. }
  7705. return NULL;
  7706. }
  7707. VOID
  7708. GpBitmap::ReleaseHdc(HDC hdc)
  7709. {
  7710. LockForRead();
  7711. InternalBitmap->ReleaseHdc(hdc);
  7712. Unlock();
  7713. return;
  7714. }
  7715. // Serialization
  7716. UINT
  7717. GpBitmap::GetDataSize() const
  7718. {
  7719. UINT dataSize;
  7720. LockForRead();
  7721. dataSize = InternalBitmap->GetDataSize();
  7722. Unlock();
  7723. return dataSize;
  7724. }
  7725. GpStatus
  7726. GpBitmap::GetData(
  7727. IStream * stream
  7728. ) const
  7729. {
  7730. GpStatus status;
  7731. LockForRead();
  7732. status = InternalBitmap->GetData(stream);
  7733. Unlock();
  7734. return status;
  7735. }
  7736. GpStatus
  7737. GpBitmap::SetData(
  7738. const BYTE * dataBuffer,
  7739. UINT size
  7740. )
  7741. {
  7742. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7743. if (writeableBitmap != NULL)
  7744. {
  7745. GpStatus status;
  7746. status = writeableBitmap->SetData(dataBuffer, size);
  7747. writeableBitmap->Unlock();
  7748. UpdateUid();
  7749. return status;
  7750. }
  7751. return GenericError;
  7752. }
  7753. GpStatus
  7754. GpBitmap::GetCompressedData(
  7755. DpCompressedData * compressed_data,
  7756. BOOL getJPEG,
  7757. BOOL getPNG,
  7758. HDC hdc
  7759. )
  7760. {
  7761. GpStatus status;
  7762. LockForRead();
  7763. status = InternalBitmap->GetCompressedData(compressed_data, getJPEG, getPNG, hdc);
  7764. Unlock();
  7765. return status;
  7766. }
  7767. GpStatus
  7768. GpBitmap::DeleteCompressedData(
  7769. DpCompressedData * compressed_data
  7770. )
  7771. {
  7772. GpStatus status;
  7773. LockForRead();
  7774. status = InternalBitmap->DeleteCompressedData(compressed_data);
  7775. Unlock();
  7776. UpdateUid();
  7777. return status;
  7778. }
  7779. // Color adjust
  7780. GpStatus
  7781. GpBitmap::ColorAdjust(
  7782. GpRecolor * recolor,
  7783. ColorAdjustType type
  7784. )
  7785. {
  7786. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7787. if (writeableBitmap != NULL)
  7788. {
  7789. GpStatus status;
  7790. status = writeableBitmap->ColorAdjust(recolor, type);
  7791. writeableBitmap->Unlock();
  7792. UpdateUid();
  7793. return status;
  7794. }
  7795. return GenericError;
  7796. }
  7797. GpStatus
  7798. GpBitmap::ColorAdjust(
  7799. GpRecolor * recolor,
  7800. PixelFormatID pixfmt,
  7801. DrawImageAbort callback,
  7802. VOID * callbackData
  7803. )
  7804. {
  7805. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7806. if (writeableBitmap != NULL)
  7807. {
  7808. GpStatus status;
  7809. status = writeableBitmap->ColorAdjust(recolor, pixfmt, callback, callbackData);
  7810. writeableBitmap->Unlock();
  7811. UpdateUid();
  7812. return status;
  7813. }
  7814. return GenericError;
  7815. }
  7816. GpStatus
  7817. GpBitmap::GetPixelFormatID(
  7818. PixelFormatID* pixfmt
  7819. )
  7820. {
  7821. GpStatus status;
  7822. LockForRead();
  7823. status = InternalBitmap->GetPixelFormatID(pixfmt);
  7824. Unlock();
  7825. return status;
  7826. }
  7827. INT
  7828. GpBitmap::GetDecodeState()
  7829. {
  7830. INT decodeState;
  7831. LockForRead();
  7832. decodeState = InternalBitmap->State;
  7833. Unlock();
  7834. return decodeState;
  7835. }
  7836. GpStatus
  7837. GpBitmap::ForceValidation()
  7838. {
  7839. GpStatus status;
  7840. LockForRead();
  7841. status = InternalBitmap->LoadIntoMemory(PixelFormatDontCare, NULL, NULL);
  7842. Unlock();
  7843. return status;
  7844. }
  7845. GpStatus
  7846. GpBitmap::SetResolution(
  7847. REAL xdpi,
  7848. REAL ydpi
  7849. )
  7850. {
  7851. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  7852. if (writeableBitmap != NULL)
  7853. {
  7854. GpStatus status;
  7855. status = writeableBitmap->SetResolution(xdpi, ydpi);
  7856. writeableBitmap->Unlock();
  7857. UpdateUid();
  7858. return status;
  7859. }
  7860. return GenericError;
  7861. }
  7862. GpStatus
  7863. GpBitmap::PreDraw(
  7864. INT numPoints,
  7865. GpPointF * dstPoints,
  7866. GpRectF * srcRect,
  7867. INT numBitsPerPixel
  7868. )
  7869. {
  7870. GpStatus status;
  7871. LockForRead();
  7872. status = InternalBitmap->PreDraw(numPoints, dstPoints, srcRect, numBitsPerPixel);
  7873. Unlock();
  7874. return status;
  7875. }
  7876. // Interop:
  7877. GpStatus
  7878. GpBitmap::CreateFromHBITMAP(
  7879. HBITMAP hbm,
  7880. HPALETTE hpal,
  7881. GpBitmap** bitmap
  7882. )
  7883. {
  7884. ASSERT(bitmap != NULL);
  7885. GpStatus status = GenericError;
  7886. GpBitmap * newBitmap = new GpBitmap(FALSE);
  7887. if (newBitmap != NULL)
  7888. {
  7889. status = CopyOnWriteBitmap::CreateFromHBITMAP(hbm, hpal, &newBitmap->InternalBitmap);
  7890. if (status != Ok)
  7891. {
  7892. delete newBitmap;
  7893. newBitmap = NULL;
  7894. }
  7895. else
  7896. {
  7897. ASSERT((newBitmap->InternalBitmap != NULL) && (newBitmap->InternalBitmap->IsValid()));
  7898. }
  7899. }
  7900. *bitmap = newBitmap;
  7901. return status;
  7902. }
  7903. GpStatus
  7904. GpBitmap::CreateBitmapAndFillWithBrush(
  7905. InterpolationMode interpolationMode,
  7906. PixelOffsetMode pixelOffsetMode,
  7907. const GpMatrix * worldToDevice,
  7908. const GpRect * drawBounds,
  7909. GpBrush * brush,
  7910. GpBitmap ** bitmap,
  7911. PixelFormatID pixelFormat
  7912. )
  7913. {
  7914. ASSERT ((drawBounds->Width > 0) && (drawBounds->Height > 0));
  7915. ASSERT (bitmap != NULL);
  7916. GpStatus status = GenericError;
  7917. *bitmap = NULL;
  7918. // First, construct the correct brush transform to use when rendering
  7919. // into the bitmap. The brush transform is the concatenation of the
  7920. // current brush transform, the current worldToDevice transform, and
  7921. // a translation transform that maps from the drawBounds to the
  7922. // bitmap bounds.
  7923. GpMatrix saveBrushMatrix;
  7924. GpMatrix * deviceMatrix = const_cast<GpMatrix *>(&((brush->GetDeviceBrush())->Xform));
  7925. saveBrushMatrix = *deviceMatrix;
  7926. GpMatrix newBrushMatrix = saveBrushMatrix;
  7927. if (worldToDevice != NULL)
  7928. {
  7929. newBrushMatrix.Append(*worldToDevice);
  7930. }
  7931. newBrushMatrix.Translate(
  7932. (REAL)-(drawBounds->X),
  7933. (REAL)-(drawBounds->Y),
  7934. MatrixOrderAppend
  7935. );
  7936. BOOL restoreWrapMode = FALSE;
  7937. // When we're drawing a texture brush into a bitmap, if the texture is
  7938. // supposed to fill the bitmap, then don't use clamp mode, because clamp
  7939. // mode will end up bleeding alpha into the image along the right and
  7940. // bottom edges, which is undesirable -- especially for down-level bitmaps
  7941. // where we end up with what looks like a dotted line along the edges
  7942. // of the bitmap.
  7943. if ((brush->GetBrushType() == BrushTypeTextureFill) &&
  7944. (((GpTexture *)brush)->GetWrapMode() == WrapModeClamp) &&
  7945. (newBrushMatrix.IsTranslateScale()))
  7946. {
  7947. GpBitmap* brushBitmap = ((GpTexture *)brush)->GetBitmap();
  7948. if (brushBitmap != NULL)
  7949. {
  7950. Size size;
  7951. brushBitmap->GetSize(&size);
  7952. GpRectF transformedRect(0.0f, 0.0f, (REAL)size.Width, (REAL)size.Height);
  7953. newBrushMatrix.TransformRect(transformedRect);
  7954. // get the transformed width
  7955. INT deltaValue = abs(GpRound(transformedRect.Width) - drawBounds->Width);
  7956. // We might be off a little because of the pixel offset mode
  7957. // or a matrix that isn't quite right for whatever reason.
  7958. if (deltaValue <= 2)
  7959. {
  7960. // get the transformed height
  7961. deltaValue = abs(GpRound(transformedRect.Height) - drawBounds->Height);
  7962. if (deltaValue <= 2)
  7963. {
  7964. if ((abs(GpRound(transformedRect.X)) <= 2) &&
  7965. (abs(GpRound(transformedRect.Y)) <= 2))
  7966. {
  7967. ((GpTexture *)brush)->SetWrapMode(WrapModeTileFlipXY);
  7968. restoreWrapMode = TRUE;
  7969. }
  7970. }
  7971. }
  7972. }
  7973. }
  7974. if (newBrushMatrix.IsInvertible())
  7975. {
  7976. *deviceMatrix = newBrushMatrix;
  7977. GpBitmap * bitmapImage = new GpBitmap(drawBounds->Width, drawBounds->Height, pixelFormat);
  7978. if (bitmapImage != NULL)
  7979. {
  7980. if (bitmapImage->IsValid())
  7981. {
  7982. GpGraphics * graphics = bitmapImage->GetGraphicsContext();
  7983. if (graphics != NULL)
  7984. {
  7985. if (graphics->IsValid())
  7986. {
  7987. // we have to lock the graphics so the driver doesn't assert
  7988. GpLock lockGraphics(graphics->GetObjectLock());
  7989. ASSERT(lockGraphics.IsValid());
  7990. graphics->SetCompositingMode(CompositingModeSourceCopy);
  7991. graphics->SetInterpolationMode(interpolationMode);
  7992. graphics->SetPixelOffsetMode(pixelOffsetMode);
  7993. // now fill the bitmap image with the brush
  7994. GpRectF destRect(0.0f, 0.0f, (REAL)drawBounds->Width, (REAL)drawBounds->Height);
  7995. status = graphics->FillRects(brush, &destRect, 1);
  7996. }
  7997. else
  7998. {
  7999. WARNING(("graphics from bitmap image not valid"));
  8000. }
  8001. delete graphics;
  8002. }
  8003. else
  8004. {
  8005. WARNING(("could not create graphics from bitmap image"));
  8006. }
  8007. }
  8008. else
  8009. {
  8010. WARNING(("bitmap image is not valid"));
  8011. }
  8012. if (status == Ok)
  8013. {
  8014. *bitmap = bitmapImage;
  8015. }
  8016. else
  8017. {
  8018. bitmapImage->Dispose();
  8019. }
  8020. }
  8021. else
  8022. {
  8023. WARNING(("could not create bitmap image"));
  8024. }
  8025. *deviceMatrix = saveBrushMatrix;
  8026. }
  8027. if (restoreWrapMode)
  8028. {
  8029. ((GpTexture *)brush)->SetWrapMode(WrapModeClamp);
  8030. }
  8031. return status;
  8032. }
  8033. GpStatus
  8034. GpBitmap::DrawAndHalftoneForStretchBlt(
  8035. HDC hdc,
  8036. BITMAPINFO * bmpInfo,
  8037. BYTE * bits,
  8038. INT srcX,
  8039. INT srcY,
  8040. INT srcWidth,
  8041. INT srcHeight,
  8042. INT destWidth,
  8043. INT destHeight,
  8044. BITMAPINFO ** destBmpInfo,
  8045. BYTE ** destBmpBits,
  8046. HBITMAP * destDIBSection,
  8047. InterpolationMode interpolationMode
  8048. )
  8049. {
  8050. ASSERT(hdc != NULL && bmpInfo != NULL && bits != NULL &&
  8051. destBmpInfo != NULL && destBmpBits != NULL &&
  8052. destDIBSection != NULL);
  8053. ASSERT(destWidth > 0 && destHeight > 0);
  8054. GpStatus status = GenericError;
  8055. ASSERT(::GetDeviceCaps(hdc, BITSPIXEL) == 8);
  8056. *destBmpInfo = (BITMAPINFO*) GpMalloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
  8057. if (*destBmpInfo == NULL)
  8058. {
  8059. return OutOfMemory;
  8060. }
  8061. BITMAPINFO *dst = *destBmpInfo;
  8062. GpMemset(dst, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
  8063. dst->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  8064. dst->bmiHeader.biPlanes = 1;
  8065. dst->bmiHeader.biBitCount = 8;
  8066. dst->bmiHeader.biWidth = destWidth;
  8067. dst->bmiHeader.biHeight = destHeight;
  8068. // We need to create a Memory DC to select a DibSection into it and finally
  8069. // wrap a graphics around it.
  8070. HPALETTE currentPalette = (HPALETTE)::GetCurrentObject(hdc, OBJ_PAL);
  8071. WORD paletteEntries;
  8072. ::GetObjectA(currentPalette, sizeof(WORD), (LPVOID)&paletteEntries);
  8073. ::GetPaletteEntries(currentPalette, 0, paletteEntries, (LPPALETTEENTRY) &(dst->bmiColors));
  8074. dst->bmiHeader.biClrUsed = paletteEntries;
  8075. HDC memDC = ::CreateCompatibleDC(hdc);
  8076. *destDIBSection = ::CreateDIBSection(hdc, dst, DIB_RGB_COLORS,
  8077. (VOID**) destBmpBits, NULL, 0);
  8078. if (*destDIBSection != NULL && memDC != NULL)
  8079. {
  8080. ::SelectObject(memDC, *destDIBSection);
  8081. ::SelectPalette(memDC, currentPalette, FALSE);
  8082. ::RealizePalette(memDC);
  8083. GpGraphics *g = GpGraphics::GetFromHdc(memDC);
  8084. if (g != NULL)
  8085. {
  8086. if(g->IsValid())
  8087. {
  8088. GpBitmap *src = new GpBitmap(bmpInfo, bits, FALSE);
  8089. if (src != NULL)
  8090. {
  8091. if( src->IsValid())
  8092. {
  8093. GpLock lock(g->GetObjectLock());
  8094. g->SetCompositingMode(CompositingModeSourceCopy);
  8095. g->SetInterpolationMode(interpolationMode);
  8096. g->SetPixelOffsetMode(PixelOffsetModeHalf);
  8097. status = g->DrawImage(src,
  8098. GpRectF(0.0f, 0.0f, (REAL)destWidth, (REAL)destHeight),
  8099. GpRectF((REAL)srcX, (REAL)srcY, (REAL)srcWidth, (REAL)srcHeight),
  8100. UnitPixel);
  8101. }
  8102. src->Dispose();
  8103. }
  8104. delete g;
  8105. }
  8106. }
  8107. }
  8108. if (memDC != NULL)
  8109. {
  8110. ::DeleteDC(memDC);
  8111. }
  8112. // If we failed delete our allocations
  8113. if (status != Ok)
  8114. {
  8115. GpFree(*destBmpInfo);
  8116. *destBmpInfo = NULL;
  8117. if (*destDIBSection != NULL)
  8118. {
  8119. ::DeleteObject(*destDIBSection);
  8120. *destDIBSection = NULL;
  8121. }
  8122. *destBmpBits = NULL;
  8123. }
  8124. return status;
  8125. }
  8126. GpStatus
  8127. GpBitmap::CreateHBITMAP(
  8128. HBITMAP * phbm,
  8129. ARGB background
  8130. )
  8131. {
  8132. GpStatus status;
  8133. LockForRead();
  8134. status = InternalBitmap->CreateHBITMAP(phbm, background);
  8135. Unlock();
  8136. return status;
  8137. }
  8138. GpStatus
  8139. GpBitmap::ICMFrontEnd(
  8140. GpBitmap ** dstBitmap,
  8141. DrawImageAbort callback,
  8142. VOID * callbackData,
  8143. GpRect * rect
  8144. )
  8145. {
  8146. GpStatus status = GenericError;
  8147. if (dstBitmap == NULL)
  8148. {
  8149. // change this object -- need write lock
  8150. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  8151. if (writeableBitmap != NULL)
  8152. {
  8153. status = writeableBitmap->ICMFrontEnd(NULL, callback, callbackData, rect);
  8154. writeableBitmap->Unlock();
  8155. UpdateUid();
  8156. }
  8157. }
  8158. else // use dstBitmap
  8159. {
  8160. GpBitmap * newBitmap = new GpBitmap(FALSE);
  8161. if (newBitmap != NULL)
  8162. {
  8163. LockForRead();
  8164. status = InternalBitmap->ICMFrontEnd(&newBitmap->InternalBitmap, callback, callbackData, rect);
  8165. Unlock();
  8166. if (status != Ok)
  8167. {
  8168. delete newBitmap;
  8169. newBitmap = NULL;
  8170. }
  8171. else
  8172. {
  8173. ASSERT((newBitmap->InternalBitmap != NULL) && (newBitmap->InternalBitmap->IsValid()));
  8174. }
  8175. }
  8176. *dstBitmap = newBitmap;
  8177. }
  8178. return status;
  8179. }
  8180. GpStatus
  8181. GpBitmap::CreateFromHICON(
  8182. HICON hicon,
  8183. GpBitmap** bitmap
  8184. )
  8185. {
  8186. ASSERT(bitmap != NULL);
  8187. GpStatus status = GenericError;
  8188. GpBitmap * newBitmap = new GpBitmap(FALSE);
  8189. if (newBitmap != NULL)
  8190. {
  8191. status = CopyOnWriteBitmap::CreateFromHICON(hicon, &newBitmap->InternalBitmap);
  8192. if (status != Ok)
  8193. {
  8194. delete newBitmap;
  8195. newBitmap = NULL;
  8196. }
  8197. else
  8198. {
  8199. ASSERT((newBitmap->InternalBitmap != NULL) && (newBitmap->InternalBitmap->IsValid()));
  8200. }
  8201. }
  8202. *bitmap = newBitmap;
  8203. return status;
  8204. }
  8205. GpStatus
  8206. GpBitmap::CreateHICON(
  8207. HICON * phicon
  8208. )
  8209. {
  8210. GpStatus status;
  8211. LockForRead();
  8212. status = InternalBitmap->CreateHICON(phicon);
  8213. Unlock();
  8214. return status;
  8215. }
  8216. GpStatus
  8217. GpBitmap::CreateFromResource(
  8218. HINSTANCE hInstance,
  8219. LPWSTR lpBitmapName,
  8220. GpBitmap** bitmap
  8221. )
  8222. {
  8223. ASSERT(bitmap != NULL);
  8224. GpStatus status = GenericError;
  8225. GpBitmap * newBitmap = new GpBitmap(FALSE);
  8226. if (newBitmap != NULL)
  8227. {
  8228. status = CopyOnWriteBitmap::CreateFromResource(hInstance, lpBitmapName, &newBitmap->InternalBitmap);
  8229. if (status != Ok)
  8230. {
  8231. delete newBitmap;
  8232. newBitmap = NULL;
  8233. }
  8234. else
  8235. {
  8236. ASSERT((newBitmap->InternalBitmap != NULL) && (newBitmap->InternalBitmap->IsValid()));
  8237. }
  8238. }
  8239. *bitmap = newBitmap;
  8240. return status;
  8241. }
  8242. // We need to know if the bitmap is associated with a display
  8243. // so we know how to handle the page transform when it is
  8244. // set to UnitDisplay.
  8245. BOOL
  8246. GpBitmap::IsDisplay() const
  8247. {
  8248. BOOL isDisplay;
  8249. LockForRead();
  8250. isDisplay = InternalBitmap->Display;
  8251. Unlock();
  8252. return isDisplay;
  8253. }
  8254. VOID
  8255. GpBitmap::SetDisplay(
  8256. BOOL display
  8257. )
  8258. {
  8259. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  8260. if (writeableBitmap != NULL)
  8261. {
  8262. writeableBitmap->Display = display;
  8263. writeableBitmap->Unlock();
  8264. UpdateUid();
  8265. }
  8266. return;
  8267. }
  8268. BOOL
  8269. GpBitmap::IsICMConvert() const
  8270. {
  8271. BOOL isICMConvert;
  8272. LockForRead();
  8273. isICMConvert = InternalBitmap->ICMConvert;
  8274. Unlock();
  8275. return isICMConvert;
  8276. }
  8277. VOID
  8278. GpBitmap::SetICMConvert(
  8279. BOOL icm
  8280. )
  8281. {
  8282. CopyOnWriteBitmap * writeableBitmap = LockForWrite();
  8283. if (writeableBitmap != NULL)
  8284. {
  8285. writeableBitmap->ICMConvert = icm;
  8286. writeableBitmap->Unlock();
  8287. UpdateUid();
  8288. }
  8289. return;
  8290. }
  8291. BOOL
  8292. GpBitmap::IsValid() const
  8293. {
  8294. // If the bitmap came from a different version of GDI+, its tag
  8295. // will not match, and it won't be considered valid.
  8296. return ((InternalBitmap != NULL) && InternalBitmap->IsValid()
  8297. && GpImage::IsValid());
  8298. }
  8299. GpStatus
  8300. ConvertTo16BppAndFlip(
  8301. GpBitmap * sourceBitmap,
  8302. GpBitmap * & destBitmap
  8303. )
  8304. {
  8305. ASSERT ((sourceBitmap != NULL) && sourceBitmap->IsValid());
  8306. GpStatus status = GenericError;
  8307. Size size;
  8308. sourceBitmap->GetSize(&size);
  8309. destBitmap = new GpBitmap(size.Width, size.Height, PixelFormat16bppRGB555);
  8310. if ((destBitmap != NULL) && destBitmap->IsValid())
  8311. {
  8312. // We have to draw it with a graphics, because if we just
  8313. // clone it, then the format converter is used which doesn't
  8314. // do dithering.
  8315. GpGraphics * g = destBitmap->GetGraphicsContext();
  8316. if (g != NULL)
  8317. {
  8318. if (g->IsValid())
  8319. {
  8320. // we have to lock the graphics so the driver doesn't assert
  8321. GpLock lockGraphics(g->GetObjectLock());
  8322. ASSERT(lockGraphics.IsValid());
  8323. // flip it upside down like GDI wants it
  8324. GpRectF realDestRect(0.0f, (REAL)size.Height, (REAL)size.Width, (REAL)(-size.Height));
  8325. g->SetCompositingMode(CompositingModeSourceCopy);
  8326. g->SetInterpolationMode(InterpolationModeNearestNeighbor);
  8327. g->SetPixelOffsetMode(PixelOffsetModeHalf);
  8328. status = g->DrawImage(sourceBitmap, realDestRect);
  8329. }
  8330. delete g;
  8331. }
  8332. }
  8333. if ((status != Ok) && (destBitmap != NULL))
  8334. {
  8335. destBitmap->Dispose();
  8336. destBitmap = NULL;
  8337. }
  8338. return status;
  8339. }