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.

1831 lines
67 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Graphics APIs.
  8. *
  9. * Revision History:
  10. *
  11. * 11/23/1999 asecchia
  12. * Created it.
  13. * 05/08/2000 gillesk
  14. * Added code to handle rotations and shears in metafiles
  15. *
  16. \**************************************************************************/
  17. #include "precomp.hpp"
  18. const CLSID EncoderTransformationInternal =
  19. {
  20. 0x8d0eb2d1,
  21. 0xa58e,
  22. 0x4ea8,
  23. {0xaa, 0x14, 0x10, 0x80, 0x74, 0xb7, 0xb6, 0xf9}
  24. };
  25. const CLSID JpegCodecClsIDInternal =
  26. {
  27. 0x557cf401,
  28. 0x1a04,
  29. 0x11d3,
  30. {0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e}
  31. };
  32. /**************************************************************************\
  33. *
  34. * Function Description:
  35. *
  36. * Engine function to draw image.
  37. * Note: this function is not a driver function despite it's name.
  38. * it probably makes more sense to call this EngDrawImage.
  39. * This function sets up the call to the driver to draw an image.
  40. *
  41. * Return Value:
  42. *
  43. * A GpStatus value indicating success or failure.
  44. *
  45. * History:
  46. *
  47. * 11/23/1999 asecchia
  48. * Created it.
  49. *
  50. \**************************************************************************/
  51. GpStatus
  52. GpGraphics::DrvDrawImage(
  53. const GpRect *drawBounds,
  54. GpBitmap *inputBitmap,
  55. INT numPoints,
  56. const GpPointF *dstPointsOriginal,
  57. const GpRectF *srcRectOriginal,
  58. const GpImageAttributes *imageAttributes,
  59. DrawImageAbort callback,
  60. VOID *callbackData,
  61. DriverDrawImageFlags flags
  62. )
  63. {
  64. // Validate the input state.
  65. ASSERTMSG(
  66. GetObjectLock()->IsLocked(),
  67. ("Graphics object must be locked")
  68. );
  69. ASSERTMSG(
  70. Device->DeviceLock.IsLockedByCurrentThread(),
  71. ("DeviceLock must be held by current thread")
  72. );
  73. FPUStateSaver::AssertMode();
  74. // must be called with a parallelogram destination.
  75. ASSERT(numPoints==3);
  76. // Make a local copy of the points.
  77. GpPointF dstPoints[3];
  78. memcpy(dstPoints, dstPointsOriginal, sizeof(dstPoints));
  79. GpRectF srcRect = *srcRectOriginal;
  80. // trivial return if the parallelogram is empty, either there are at least
  81. // two points overlap or they are on one line
  82. // We check if the slope between point2 and point1 equals to the slope
  83. // between point0 and point1
  84. if (REALABS(
  85. (dstPoints[2].Y - dstPoints[0].Y) * (dstPoints[0].X - dstPoints[1].X) -
  86. (dstPoints[2].X - dstPoints[0].X) * (dstPoints[0].Y - dstPoints[1].Y)
  87. ) < REAL_EPSILON)
  88. {
  89. return Ok;
  90. }
  91. // Done input parameter validation.
  92. // Check some useful state up front.
  93. BOOL IsMetafile = (Driver == Globals::MetaDriver);
  94. BOOL IsRecolor = (
  95. (imageAttributes != NULL) &&
  96. (imageAttributes->recolor != NULL) &&
  97. (imageAttributes->recolor->HasRecoloring(ColorAdjustTypeBitmap))
  98. );
  99. // This is the format we will use to lock the bits.
  100. // Default is premultiplied, but some cases require non-premultiplied.
  101. PixelFormat lockedPixelFormat = PixelFormat32bppPARGB;
  102. // Metafiles need non-premultiplied pixel data.
  103. // Also, Recoloring uses ARGB as it's initial format, so we want
  104. // to respect that if we load the image into memory before the
  105. // recolor code.
  106. if(IsMetafile || IsRecolor)
  107. {
  108. lockedPixelFormat = PixelFormat32bppARGB;
  109. }
  110. Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
  111. // Set up the local tracking state.
  112. // Note: inputBitmap can change during the processing in this routine -
  113. // specifically when recoloring is done, it may be pointing to a clone
  114. // of the input bitmap with recoloring applied. Because of this, the
  115. // inputBitmap should never be directly referenced from here onward.
  116. GpStatus status = Ok;
  117. GpBitmap *srcBitmap = inputBitmap;
  118. GpBitmap *xformBitmap = NULL;
  119. BOOL restoreClipping = FALSE;
  120. GpRegion *clipRegion = NULL;
  121. // Compute the transform between the source rectangle and the destination
  122. // points transformed to device coordinates. This is used to detect and
  123. // intercept processing for some high level optimizations and workarounds.
  124. GpMatrix xForm;
  125. xForm.InferAffineMatrix(dstPoints, srcRect);
  126. // Special optimization for JPEG passthrough of rotated bitmaps.
  127. // Why does this not take the world to device matrix into account?
  128. // If the world to device is a non-trivial rotation, then this is invalid.
  129. if (IsPrinter())
  130. {
  131. MatrixRotate rotateBy;
  132. DriverPrint *dprint = (DriverPrint*)Driver;
  133. // Check if the source rectangle to destination point map is
  134. // simply a 90, 180, or 270 rotation, and the driver supports JPEG
  135. // passthrough, It's a JPEG image, no recoloring, not dirty.
  136. if (!Globals::IsWin95 &&
  137. dprint->SupportJPEGpassthrough &&
  138. Context->WorldToDevice.IsTranslateScale() &&
  139. ((rotateBy = xForm.GetRotation()) != MatrixRotateByOther) &&
  140. (rotateBy != MatrixRotateBy0) &&
  141. (!srcBitmap->IsDirty()) &&
  142. ((imageAttributes == NULL) ||
  143. (imageAttributes->recolor == NULL) ||
  144. (!imageAttributes->recolor->HasRecoloring(ColorAdjustTypeBitmap))))
  145. {
  146. ImageInfo imageInfo;
  147. status = srcBitmap->GetImageInfo(&imageInfo);
  148. if((status == Ok) &&
  149. (imageInfo.RawDataFormat == IMGFMT_JPEG))
  150. {
  151. // Allocate a stream to store the rotated JPEG.
  152. IStream * outputStream = NULL;
  153. BOOL succeededWithRotate = FALSE;
  154. if ((CreateStreamOnHGlobal(NULL,
  155. FALSE,
  156. &outputStream) == S_OK) &&
  157. outputStream != NULL)
  158. {
  159. EncoderParameters encoderParams;
  160. EncoderValue encoderValue;
  161. encoderParams.Count = 1;
  162. // Re-orient the destination parallelogram (rectangle) since
  163. // we now are assuming a 0 degree rotation.
  164. GpPointF newDestPoints[3] =
  165. {
  166. GpPointF(min(min(dstPoints[0].X, dstPoints[1].X), dstPoints[2].X),
  167. min(min(dstPoints[0].Y, dstPoints[1].Y), dstPoints[2].Y)),
  168. GpPointF(max(max(dstPoints[0].X, dstPoints[1].X), dstPoints[2].X),
  169. min(min(dstPoints[0].Y, dstPoints[1].Y), dstPoints[2].Y)),
  170. GpPointF(min(min(dstPoints[0].X, dstPoints[1].X), dstPoints[2].X),
  171. max(max(dstPoints[0].Y, dstPoints[1].Y), dstPoints[2].Y))
  172. };
  173. // Since the image is potentially flipped, the srcRect needs
  174. // to be flipped also.
  175. GpRectF newSrcRect = srcRect;
  176. GpMatrix transformSrc;
  177. // Construct the appropriate encoder parameters type.
  178. switch (rotateBy)
  179. {
  180. case MatrixRotateBy90:
  181. transformSrc.SetMatrix(0.0f,
  182. 1.0f,
  183. -1.0f,
  184. 0.0f,
  185. TOREAL(imageInfo.Height),
  186. 0.0f);
  187. encoderValue = EncoderValueTransformRotate90;
  188. break;
  189. case MatrixRotateBy180:
  190. transformSrc.SetMatrix(-1.0f,
  191. 0.0f,
  192. 0.0f,
  193. -1.0f,
  194. TOREAL(imageInfo.Width),
  195. TOREAL(imageInfo.Height));
  196. encoderValue = EncoderValueTransformRotate180;
  197. break;
  198. case MatrixRotateBy270:
  199. transformSrc.SetMatrix(0.0f,
  200. -1.0f,
  201. 1.0f,
  202. 0.0f,
  203. 0.0f,
  204. TOREAL(imageInfo.Width));
  205. encoderValue = EncoderValueTransformRotate270;
  206. break;
  207. default:
  208. encoderParams.Count = 0;
  209. ASSERT(FALSE);
  210. break;
  211. }
  212. // Transform the source rectangle from source image space
  213. // to rotated image space. Normalize the destination source
  214. // rectangle.
  215. // Note that the source rectangle may not originally be
  216. // normalized, but any rotational effects it emparts on the
  217. // draw image is represented by the xForm and thus our
  218. // newDestPoints.
  219. // NTRAID#NTBUG9-407211-2001-05-31-gillessk "Bad assert triggers when it shouldn't"
  220. // assert was transformSrc.IsTranslateScale, which fires when rotation is involved
  221. ASSERT(transformSrc.IsTranslateScale() || (transformSrc.GetRotation()==MatrixRotateBy90)
  222. || (transformSrc.GetRotation()==MatrixRotateBy270));
  223. transformSrc.TransformRect(newSrcRect);
  224. encoderParams.Parameter[0].Guid = EncoderTransformationInternal;
  225. encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
  226. encoderParams.Parameter[0].NumberOfValues = 1;
  227. encoderParams.Parameter[0].Value = (VOID*)&encoderValue;
  228. // Specify built in JPEG enocder for simplicity. We should
  229. // really copy the CLSID encoder from the srcBitmap.
  230. if (encoderParams.Count != 0 &&
  231. srcBitmap->SaveToStream(outputStream,
  232. const_cast<CLSID*>(&JpegCodecClsIDInternal),
  233. &encoderParams) == Ok)
  234. {
  235. // The stream contains the rotated JPEG. Wrap a bitmap
  236. // around this and recursively call on ourself. This sucks,
  237. // but the destructor to rotatedJPEG is private so we can't
  238. // define it as a stack variable.
  239. GpBitmap *rotatedJPEG = new GpBitmap(outputStream);
  240. if (rotatedJPEG != NULL)
  241. {
  242. if (rotatedJPEG->IsValid())
  243. {
  244. // Transform the source rectangle by the scale & translate
  245. // of the original xForm, but not the rotation! This could
  246. // equivalently be determined by querying M11,M22, Dx, Dy.
  247. status = DrvDrawImage(drawBounds,
  248. rotatedJPEG,
  249. numPoints,
  250. &newDestPoints[0],
  251. &newSrcRect,
  252. imageAttributes,
  253. callback,
  254. callbackData,
  255. flags);
  256. succeededWithRotate = TRUE;
  257. }
  258. rotatedJPEG->Dispose();
  259. }
  260. }
  261. outputStream->Release();
  262. if (succeededWithRotate)
  263. {
  264. return status;
  265. }
  266. else
  267. {
  268. return OutOfMemory;
  269. }
  270. }
  271. }
  272. }
  273. }
  274. // Create complete source image to device space transform.
  275. xForm.Append(Context->WorldToDevice);
  276. GpBitmap *cloneBitmap = NULL;
  277. // GpMatrix has a default constructor which sets it to ID so we may
  278. // as well copy it always.
  279. GpMatrix saveWorldToDevice = Context->WorldToDevice;
  280. // Check for special case rotate or flip.
  281. // Integer translate is handled natively by the driver.
  282. if(!xForm.IsIntegerTranslate())
  283. {
  284. RotateFlipType specialRotate = xForm.AnalyzeRotateFlip();
  285. if(specialRotate != RotateNoneFlipNone)
  286. {
  287. ImageInfo imageInfo;
  288. status = srcBitmap->GetImageInfo(&imageInfo);
  289. if(status != Ok)
  290. {
  291. goto cleanup;
  292. }
  293. // Clone the bitmap in the same format we'll be using later.
  294. // This will save a format conversion.
  295. // !!! PERF [asecchia]
  296. // This clones the entire image. When we do the RotateFlip call
  297. // it'll decode the entire image - which is potentially a
  298. // waste - we should clone only the relevant rectangle.
  299. // Note: this would have to be accounted for in the transform and
  300. // Clone would need to be fixed to account for outcropping.
  301. cloneBitmap = srcBitmap->Clone(NULL, lockedPixelFormat);
  302. if(cloneBitmap == NULL)
  303. {
  304. status = OutOfMemory;
  305. goto cleanup;
  306. }
  307. srcBitmap = cloneBitmap;
  308. // perform lossless pixel rotation in place.
  309. srcBitmap->RotateFlip(specialRotate);
  310. // Undo the pixel offset mode. We know we're not scaling so
  311. // this is correct.
  312. // Why do we have two different enums meaning exactly
  313. // the same thing?
  314. if((Context->PixelOffset == PixelOffsetModeHalf) ||
  315. (Context->PixelOffset == PixelOffsetModeHighQuality))
  316. {
  317. // Undo the pixel offset in the source rectangle.
  318. srcRect.Offset(0.5f, 0.5f);
  319. // Undo the pixel offset in the matrix. We apply the pre-offset
  320. // from the source rect and the post offset from the W2D matrix
  321. // For identity this would be a NOP because the matrixes for
  322. // pixel offset and non-pixel offset are identical, but they
  323. // apply in two different spaces for rotation.
  324. xForm.Translate(0.5f, 0.5f, MatrixOrderAppend);
  325. xForm.Translate(-0.5f, -0.5f, MatrixOrderPrepend);
  326. }
  327. // Remove the world to device rotation.
  328. xForm.SetMatrix(
  329. 1.0f, 0.0f,
  330. 0.0f, 1.0f,
  331. xForm.GetDx(),
  332. xForm.GetDy()
  333. );
  334. // Because RotateFlip applies in place, the resulting bitmap is
  335. // always still at the origin. This is actually a non-trivial
  336. // rotation in most cases - i.e. there is an implied translate
  337. // from where the real simple rotate matrix puts the image and
  338. // where it is now. Fix up the translate in the xForm to take
  339. // this into account.
  340. REAL temp;
  341. switch(specialRotate)
  342. {
  343. case RotateNoneFlipX:
  344. temp = (2.0f*srcRect.X+srcRect.Width);
  345. xForm.Translate(-(REAL)imageInfo.Width, 0.0f);
  346. srcRect.Offset(imageInfo.Width-temp, 0.0f);
  347. break;
  348. case RotateNoneFlipY:
  349. temp = (2.0f*srcRect.Y+srcRect.Height);
  350. xForm.Translate(0.0f, -(REAL)imageInfo.Height);
  351. srcRect.Offset(0.0f, imageInfo.Height-temp);
  352. break;
  353. case Rotate90FlipNone:
  354. SWAP(temp, srcRect.X, srcRect.Y);
  355. SWAP(temp, srcRect.Width, srcRect.Height);
  356. temp = (2.0f*srcRect.X+srcRect.Width);
  357. xForm.Translate(-(REAL)imageInfo.Height, 0.0f);
  358. srcRect.Offset(imageInfo.Height-temp, 0.0f);
  359. break;
  360. case Rotate90FlipX:
  361. SWAP(temp, srcRect.X, srcRect.Y);
  362. SWAP(temp, srcRect.Width, srcRect.Height);
  363. break;
  364. case Rotate180FlipNone:
  365. xForm.Translate(
  366. -(REAL)imageInfo.Width,
  367. -(REAL)imageInfo.Height
  368. );
  369. srcRect.Offset(
  370. imageInfo.Width -(2.0f*srcRect.X+srcRect.Width),
  371. imageInfo.Height-(2.0f*srcRect.Y+srcRect.Height)
  372. );
  373. break;
  374. case Rotate270FlipX:
  375. SWAP(temp, srcRect.X, srcRect.Y);
  376. SWAP(temp, srcRect.Width, srcRect.Height);
  377. xForm.Translate(
  378. -(REAL)imageInfo.Height,
  379. -(REAL)imageInfo.Width
  380. );
  381. srcRect.Offset(
  382. imageInfo.Height-(2.0f*srcRect.X+srcRect.Width),
  383. imageInfo.Width -(2.0f*srcRect.Y+srcRect.Height)
  384. );
  385. break;
  386. case Rotate270FlipNone:
  387. SWAP(temp, srcRect.X, srcRect.Y);
  388. SWAP(temp, srcRect.Width, srcRect.Height);
  389. temp = (2.0f*srcRect.Y+srcRect.Height);
  390. xForm.Translate(0.0f, -(REAL)imageInfo.Width);
  391. srcRect.Offset(0.0f, imageInfo.Width-temp);
  392. break;
  393. };
  394. // Set the world to device transform in the context. This causes
  395. // the driver to use our updated transform. We fix this up at the
  396. // end of this routine. (see goto cleanup)
  397. Context->WorldToDevice = xForm;
  398. // Normalize the destination because we've incorporated the
  399. // entire affine transform into the world to device matrix.
  400. dstPoints[0].X = srcRect.X;
  401. dstPoints[0].Y = srcRect.Y;
  402. dstPoints[1].X = srcRect.X+srcRect.Width;
  403. dstPoints[1].Y = srcRect.Y;
  404. dstPoints[2].X = srcRect.X;
  405. dstPoints[2].Y = srcRect.Y+srcRect.Height;
  406. }
  407. }
  408. // HighQuality filters doing rotation/shear?
  409. // This is a workable temporary solution to high quality bicubic
  410. // rotation. Note that when the underlying bicubic filtering code
  411. // is updated to support rotation, this block should be removed.
  412. if( (!xForm.IsTranslateScale()) && (!IsMetafile) && // don't scale down-level metafile record
  413. ((Context->FilterType==InterpolationModeHighQualityBicubic) ||
  414. (Context->FilterType==InterpolationModeHighQualityBilinear))
  415. )
  416. {
  417. // Before allocating the srcBitmap, see if we can save some memory
  418. // by only allocating the part of the srcBitmap that gets transfromed
  419. // in the case that we are outcropping.
  420. // This is only valid if we are in ClampMode and printing
  421. // We should do this all the time, but we would have to calculate the
  422. // area of influence of the kernel.
  423. // Printing doesn't support PixelOffsetting yet, so don't move the
  424. // srcRect
  425. if (IsPrinter() &&
  426. ((!imageAttributes) ||
  427. (imageAttributes->DeviceImageAttributes.wrapMode == WrapModeClamp)))
  428. {
  429. RectF clampedSrcRect;
  430. Unit srcUnit;
  431. srcBitmap->GetBounds(&clampedSrcRect, &srcUnit);
  432. ASSERT(srcUnit == UnitPixel);
  433. // Find the area of the srcrect that is included in the image
  434. clampedSrcRect.Intersect(srcRect);
  435. // If there's no intersection then don't do anything
  436. if (clampedSrcRect.IsEmptyArea())
  437. {
  438. goto cleanup;
  439. }
  440. // Don't do anything else if the srcRect is not outcropping
  441. if (!clampedSrcRect.Equals(srcRect))
  442. {
  443. GpMatrix srcDstXForm;
  444. if (srcDstXForm.InferAffineMatrix(dstPoints, srcRect) == Ok)
  445. {
  446. // Modify the srcRect and the dstPoints to match the new
  447. // section of the bitmap
  448. dstPoints[0] = PointF(clampedSrcRect.X, clampedSrcRect.Y);
  449. dstPoints[1].X = clampedSrcRect.GetRight();
  450. dstPoints[1].Y = clampedSrcRect.Y;
  451. dstPoints[2].X = clampedSrcRect.X;
  452. dstPoints[2].Y = clampedSrcRect.GetBottom();
  453. srcDstXForm.Transform(dstPoints, 3);
  454. srcRect = clampedSrcRect;
  455. }
  456. }
  457. }
  458. // Must make the determination of intermediate size based on the actual
  459. // device coordinates of the final destination points.
  460. GpPointF points[3];
  461. memcpy(points, dstPoints, sizeof(points));
  462. Context->WorldToDevice.Transform(points, 3);
  463. // Compute the width and height of the scale factor so that we
  464. // can decompose into a scale and then rotation.
  465. INT iwidth = GpCeiling( REALSQRT(
  466. (points[1].X-points[0].X)*(points[1].X-points[0].X)+
  467. (points[1].Y-points[0].Y)*(points[1].Y-points[0].Y)
  468. ));
  469. INT iheight = GpCeiling( REALSQRT(
  470. (points[2].X-points[0].X)*(points[2].X-points[0].X)+
  471. (points[2].Y-points[0].Y)*(points[2].Y-points[0].Y)
  472. ));
  473. ASSERT(iwidth>0);
  474. ASSERT(iheight>0);
  475. // Only do the scale if we really need to.
  476. // Note: This if statement prevents infinite recursion in DrvDrawImage
  477. if( (REALABS(iwidth-srcRect.Width) > REAL_EPSILON) &&
  478. (REALABS(iheight-srcRect.Height) > REAL_EPSILON) )
  479. {
  480. // Create a temporary bitmap to scale the image into.
  481. GpBitmap *scaleBitmap = NULL;
  482. // Crack the recoloring to figure out the optimal temporary bitmap
  483. // format.
  484. // Metafiles also need non-premultiplied (see the final LockBits
  485. // in this routine before calling the driver)
  486. PixelFormatID scaleFormat = PixelFormat32bppPARGB;
  487. if((IsMetafile) ||
  488. ( (imageAttributes) &&
  489. (imageAttributes->recolor) &&
  490. (imageAttributes->recolor->HasRecoloring(ColorAdjustTypeBitmap))
  491. ))
  492. {
  493. // Recoloring is enabled - optimal format is non-premultiplied.
  494. // In fact it's incorrect (lossy) to go to premultiplied before
  495. // recoloring is applied.
  496. scaleFormat = PixelFormat32bppARGB;
  497. }
  498. scaleBitmap = new GpBitmap(
  499. iwidth,
  500. iheight,
  501. scaleFormat
  502. );
  503. GpGraphics *scaleG = NULL;
  504. if(scaleBitmap && scaleBitmap->IsValid())
  505. {
  506. // The high quality filtering should be to an equivalent
  507. // dpi surface, bounded by the ultimate surface destination dpi.
  508. REAL dpiX, dpiY;
  509. srcBitmap->GetResolution(&dpiX, &dpiY);
  510. scaleBitmap->SetResolution(min(dpiX, Context->ContainerDpiX),
  511. min(dpiY, Context->ContainerDpiY));
  512. scaleG = scaleBitmap->GetGraphicsContext();
  513. }
  514. if(scaleG && scaleG->IsValid())
  515. {
  516. GpLock lock(scaleG->GetObjectLock());
  517. scaleG->SetInterpolationMode(Context->FilterType);
  518. scaleG->SetCompositingMode(CompositingModeSourceCopy);
  519. GpRectF scaleDst(
  520. 0,
  521. 0,
  522. (REAL)iwidth,
  523. (REAL)iheight
  524. );
  525. // To avoid bleeding transparent black into our image when
  526. // printing we temporarily set the WrapMode to TileFlipXY on
  527. // our preliminary drawimage (the scaling part) and clip to the
  528. // bounds later on when we do the rotate/skew.
  529. GpImageAttributes *tempImageAttributes = const_cast<GpImageAttributes*>(imageAttributes);
  530. if (IsPrinter())
  531. {
  532. if (imageAttributes == NULL)
  533. {
  534. tempImageAttributes = new GpImageAttributes();
  535. if(tempImageAttributes)
  536. {
  537. tempImageAttributes->SetWrapMode(WrapModeTileFlipXY);
  538. }
  539. }
  540. else if (imageAttributes->DeviceImageAttributes.wrapMode == WrapModeClamp)
  541. {
  542. tempImageAttributes = imageAttributes->Clone();
  543. if(tempImageAttributes)
  544. {
  545. tempImageAttributes->SetWrapMode(WrapModeTileFlipXY);
  546. }
  547. }
  548. }
  549. // Do the scale.
  550. status = scaleG->DrawImage(
  551. srcBitmap,
  552. scaleDst,
  553. srcRect,
  554. UnitPixel,
  555. tempImageAttributes,
  556. callback,
  557. callbackData
  558. );
  559. // If we allocated a new copy of the imageAttributes then delete it.
  560. if (tempImageAttributes != imageAttributes)
  561. {
  562. delete tempImageAttributes;
  563. }
  564. // Now we're at the right size, lets actually do some rotation.
  565. // Note we don't bother resetting the filtering mode because the
  566. // underlying driver code for HighQuality filters defaults to
  567. // the correct resampling code.
  568. // Also we shouldn't get recursion because of the width and height
  569. // check protecting this codeblock.
  570. if(status==Ok)
  571. {
  572. status = this->DrawImage(
  573. scaleBitmap,
  574. dstPoints,
  575. 3,
  576. scaleDst,
  577. UnitPixel,
  578. NULL,
  579. callback,
  580. callbackData
  581. );
  582. }
  583. }
  584. else
  585. {
  586. status = OutOfMemory;
  587. }
  588. delete scaleG;
  589. if (scaleBitmap)
  590. {
  591. scaleBitmap->Dispose();
  592. }
  593. goto cleanup; // completed or error.
  594. }
  595. }
  596. // Prep the bitmap for drawing:
  597. // if rendering to a meta surface (multimon) assume 32bpp for
  598. // the icon codec.
  599. status = srcBitmap->PreDraw(
  600. numPoints,
  601. dstPoints,
  602. &srcRect,
  603. GetPixelFormatSize(
  604. (Surface->PixelFormat == PixelFormatMulti) ?
  605. PixelFormat32bppRGB : Surface->PixelFormat
  606. )
  607. );
  608. if (status != Ok)
  609. {
  610. goto cleanup;
  611. }
  612. // Get the cached ImageInfo from the source bitmap. Any time the image
  613. // is changed or forced to be re-decoded, this will be invalidated and
  614. // will require an explicit re-initialization.
  615. ImageInfo srcBitmapImageInfo;
  616. status = srcBitmap->GetImageInfo(&srcBitmapImageInfo);
  617. if(status != Ok)
  618. {
  619. goto cleanup;
  620. }
  621. // Do the recoloring.
  622. // Note that Recoloring will clone the image if it needs to change the bits.
  623. // This means that srcBitmap will not be pointing to inputBitmap after
  624. // a successful call to the recoloring code.
  625. if((status == Ok) && (IsRecolor))
  626. {
  627. // cloneBitmap is set to NULL. Recolor into a cloned bitmap
  628. // cloneBitmap != NULL - we previously cloned, so it's ok to
  629. // recolor in place.
  630. status = srcBitmap->Recolor(
  631. imageAttributes->recolor,
  632. (cloneBitmap == NULL) ? &cloneBitmap : NULL,
  633. callback,
  634. callbackData
  635. );
  636. // Recoloring worked - set the srcBitmap to the clone that's been
  637. // recolored so that the rest of the pipe works on the recolored bitmap.
  638. if(status == Ok)
  639. {
  640. srcBitmap = cloneBitmap;
  641. status = srcBitmap->GetImageInfo(&srcBitmapImageInfo);
  642. // If it's not a metafile, we need to convert to PARGB for the
  643. // filtering.
  644. if(!IsMetafile)
  645. {
  646. lockedPixelFormat = PixelFormat32bppPARGB;
  647. }
  648. }
  649. }
  650. // Check the callbacks.
  651. if ((status == Ok) &&
  652. (callback) &&
  653. ((*callback)(callbackData)))
  654. {
  655. status = Aborted;
  656. }
  657. if(status == Ok)
  658. {
  659. // The code below explicitly assumes numPoints == 3. Yes I know we've
  660. // already asserted this above, but you can't be too careful.
  661. ASSERT(numPoints==3);
  662. // If we don't write a rotation into a metafile, copy the
  663. // points to the buffers that are used by the driver
  664. // These will only be changed if everything succeeded
  665. GpPointF fDst[3];
  666. GpRectF bboxSrcRect;
  667. GpMatrix worldDevice = Context->WorldToDevice;
  668. GpMemcpy(fDst, dstPoints, sizeof(GpPointF)*numPoints);
  669. bboxSrcRect = srcRect;
  670. // Before calling the driver if we have a rotated bitmap then try to
  671. // rotate it now and draw it transparent
  672. INT complexity = xForm.GetComplexity() ;
  673. if (!xForm.IsTranslateScale() && IsMetafile)
  674. {
  675. // We have a shear/rotate transformation.
  676. // Create a transparent bitmap and render into it
  677. // first, get new dest points
  678. GpPointF newDestPoints[3];
  679. GpRectF bboxWorkRectF;
  680. TransformBounds(&xForm,
  681. srcRect.X,
  682. srcRect.Y,
  683. srcRect.X+srcRect.Width,
  684. srcRect.Y+srcRect.Height,
  685. &bboxWorkRectF
  686. );
  687. newDestPoints[0].X = bboxWorkRectF.X;
  688. newDestPoints[0].Y = bboxWorkRectF.Y;
  689. newDestPoints[1].X = bboxWorkRectF.X + bboxWorkRectF.Width;
  690. newDestPoints[1].Y = bboxWorkRectF.Y;
  691. newDestPoints[2].X = bboxWorkRectF.X;
  692. newDestPoints[2].Y = bboxWorkRectF.Y + bboxWorkRectF.Height;
  693. // To keep the metafile size small, take out most of the
  694. // scaling up from the transform. We could do this by
  695. // a sophisticated algorithm to calculate the amount of
  696. // scaling in the matrix, but instead just assume anything
  697. // greater than 1 is a scale, which means we could actually
  698. // scale up by as much as 1.4 (for a 45-degree angle), but
  699. // that's close enough.
  700. GpMatrix unscaledXform = xForm;
  701. REAL xScale = 1.0f;
  702. REAL yScale = 1.0f;
  703. REAL col1;
  704. REAL col2;
  705. REAL max;
  706. // This should really use REALABS and max()
  707. col1 = xForm.GetM11();
  708. if (col1 < 0.0f)
  709. {
  710. col1 = -col1; // get absolute value
  711. }
  712. col2 = xForm.GetM12();
  713. if (col2 < 0.0f)
  714. {
  715. col2 = -col2; // get absolute value
  716. }
  717. max = (col1 >= col2) ? col1 : col2; // max scale value
  718. if (max > 1.0f)
  719. {
  720. xScale = 1.0f / max;
  721. }
  722. col1 = xForm.GetM21();
  723. if (col1 < 0.0f)
  724. {
  725. col1 = -col1; // get absolute value
  726. }
  727. col2 = xForm.GetM22();
  728. if (col2 < 0.0f)
  729. {
  730. col2 = -col2; // get absolute value
  731. }
  732. max = (col1 >= col2) ? col1 : col2; // max scale value
  733. if (max > 1.0f)
  734. {
  735. yScale = 1.0f / max;
  736. }
  737. unscaledXform.Scale(xScale, yScale, MatrixOrderPrepend);
  738. // Transform the original src coordinates to obtain the
  739. // dimensions of the bounding box for the rotated bitmap.
  740. TransformBounds(&unscaledXform,
  741. srcRect.X,
  742. srcRect.Y,
  743. srcRect.X+srcRect.Width,
  744. srcRect.Y+srcRect.Height,
  745. &bboxWorkRectF
  746. );
  747. // Add 1 because the rect for bitmaps is inclusive-inclusive
  748. INT rotatedWidth = GpRound(bboxWorkRectF.GetRight() - bboxWorkRectF.X + 1.0f);
  749. INT rotatedHeight = GpRound(bboxWorkRectF.GetBottom() - bboxWorkRectF.Y + 1.0f);
  750. // Convert the bounding box back to a 3 point system
  751. // This will be what's passed to the driver
  752. xformBitmap = new GpBitmap(rotatedWidth, rotatedHeight, PIXFMT_32BPP_ARGB);
  753. if (xformBitmap != NULL && xformBitmap->IsValid())
  754. {
  755. GpGraphics *graphics = xformBitmap->GetGraphicsContext();
  756. if (graphics != NULL && graphics->IsValid())
  757. {
  758. // we have to lock the graphics so the driver doesn't assert
  759. GpLock lockGraphics(graphics->GetObjectLock());
  760. graphics->Clear(GpColor(0,0,0,0));
  761. // Translate the world to be able to draw the whole image
  762. graphics->TranslateWorldTransform(-bboxWorkRectF.X, -bboxWorkRectF.Y);
  763. // Apply the transform from the Src to the Destination
  764. if (graphics->MultiplyWorldTransform(unscaledXform, MatrixOrderPrepend) == Ok)
  765. {
  766. GpImageAttributes imageAttributes;
  767. imageAttributes.SetWrapMode(WrapModeTileFlipXY);
  768. graphics->SetPixelOffsetMode(Context->PixelOffset);
  769. // Draw the rotated xformBitmap at the origin
  770. if (graphics->DrawImage(srcBitmap, srcRect, srcRect, UnitPixel, &imageAttributes) == Ok)
  771. {
  772. // Now that we have succeeded change the parameters
  773. bboxSrcRect.X = 0.0f;
  774. bboxSrcRect.Y = 0.0f;
  775. bboxSrcRect.Width = (REAL)rotatedWidth;
  776. bboxSrcRect.Height = (REAL)rotatedHeight;
  777. // Set the clipping in the graphics to be able to
  778. // mask out the edges
  779. clipRegion = GetClip();
  780. if (clipRegion != NULL)
  781. {
  782. // Create the outline of the picture as a path
  783. GpPointF pathPoints[4];
  784. BYTE pathTypes[4] = {
  785. PathPointTypeStart,
  786. PathPointTypeLine,
  787. PathPointTypeLine,
  788. PathPointTypeLine | PathPointTypeCloseSubpath };
  789. GpPointF pixelOffset(0.0f, 0.0f);
  790. if (Context->PixelOffset == PixelOffsetModeHalf || Context->PixelOffset == PixelOffsetModeHighQuality)
  791. {
  792. // Cannot use GetWorldPixelSize because it does an ABS
  793. GpMatrix deviceToWorld;
  794. if (GetDeviceToWorldTransform(&deviceToWorld) == Ok)
  795. {
  796. pixelOffset = GpPointF(-0.5f, -0.5f);
  797. deviceToWorld.VectorTransform(&pixelOffset);
  798. }
  799. }
  800. pathPoints[0] = dstPoints[0] + pixelOffset;
  801. pathPoints[1] = dstPoints[1] + pixelOffset;
  802. pathPoints[2].X = dstPoints[1].X - dstPoints[0].X + dstPoints[2].X + pixelOffset.X;
  803. pathPoints[2].Y = dstPoints[2].Y - dstPoints[0].Y + dstPoints[1].Y + pixelOffset.Y;
  804. pathPoints[3] = dstPoints[2] + pixelOffset;
  805. GpPath path(pathPoints, pathTypes, 4);
  806. if (path.IsValid())
  807. {
  808. if (SetClip(&path, CombineModeIntersect) == Ok)
  809. {
  810. restoreClipping = TRUE;
  811. }
  812. }
  813. }
  814. GpMemcpy(fDst, newDestPoints, sizeof(GpPointF)*3);
  815. Context->WorldToDevice.Reset();
  816. srcBitmap = xformBitmap;
  817. srcBitmap->GetImageInfo(&srcBitmapImageInfo);
  818. }
  819. }
  820. }
  821. if( graphics != NULL )
  822. {
  823. delete graphics ;
  824. }
  825. }
  826. }
  827. // This is the size we're going to request the codec decode into.
  828. // Both width and height == 0 means use the source width and height.
  829. // If a width and height are specified, the codec may decode to
  830. // something close - always larger than the requested size.
  831. REAL width = 0.0f;
  832. REAL height = 0.0f;
  833. // !!! PERF [asecchia] We should probably compute the size of
  834. // a rotational minification and work out the correct transforms
  835. // to take advantage of the codec minification for rotation.
  836. // Is an axis aligned minification happening?
  837. if(xForm.IsMinification())
  838. {
  839. // The code below explicitly assumes numPoints == 3. Yes I know
  840. // we've already asserted this above, but you can't be too careful.
  841. ASSERT(numPoints == 3);
  842. // We're axis aligned so we can assume a simplified width and
  843. // height computation.
  844. RectF boundsRect;
  845. TransformBounds(
  846. &xForm,
  847. srcRect.X,
  848. srcRect.Y,
  849. srcRect.X+srcRect.Width,
  850. srcRect.Y+srcRect.Height,
  851. &boundsRect
  852. );
  853. // Compute an upper bound on the width and height of the
  854. // destination.
  855. // we'll let the driver handle vertical an horizontal flips with
  856. // the scale transform.
  857. width = REALABS(boundsRect.GetRight()-boundsRect.GetLeft());
  858. height = REALABS(boundsRect.GetBottom()-boundsRect.GetTop());
  859. // In this case the Nyquist limit specifies that we can use a
  860. // cheap averaging decimation type algorithm for minification
  861. // down to double the size of the destination - after which we
  862. // must use the more expensive filter convolution for minification.
  863. // Note that the decimation algorithm is roughly equivalient to our
  864. // regular Bilinear interpolation so we can decimate below the
  865. // Nyquist limit for Bilinear.
  866. if(Context->FilterType != InterpolationModeBilinear)
  867. {
  868. width *= 2.0f;
  869. height *= 2.0f;
  870. }
  871. // The source image is smaller than the Nyquist limit in X
  872. // simply use the source width.
  873. if(width >= srcRect.Width)
  874. {
  875. width = srcRect.Width;
  876. }
  877. // The source image is smaller than the Nyquist limit in Y
  878. // simply use the source height.
  879. if(height >= srcRect.Height)
  880. {
  881. height = srcRect.Height;
  882. }
  883. // The source image is smaller than the Nyquist limit in
  884. // both X and Y. Set the parameters to zero to do no scaling
  885. // in the codec.
  886. // If width,height greater or equal to srcRect, set zero in the
  887. // width to ask the codec to return us the image native size.
  888. if( (width - srcRect.Width >= -REAL_EPSILON) &&
  889. (height - srcRect.Height >= -REAL_EPSILON) )
  890. {
  891. width = 0.0f;
  892. height = 0.0f;
  893. }
  894. // Undo the cropping effect to figure out how much to decimate
  895. // the entire image before cropping takes place.
  896. width = width * srcBitmapImageInfo.Width / srcRect.Width;
  897. height = height * srcBitmapImageInfo.Height / srcRect.Height;
  898. }
  899. BitmapData bmpDataSrc;
  900. DpCompressedData compressedData;
  901. DpTransparency transparency;
  902. BYTE minAlpha = 0, maxAlpha = 0xFF;
  903. // Determine the transparency status of the bitmap. If printing, then
  904. // must be accurate, otherwise we use cached flag.
  905. if ((status == Ok) &&
  906. (srcBitmap != NULL) &&
  907. (srcBitmap->IsValid()))
  908. {
  909. // Mark that we haven't locked the bits yet.
  910. BOOL bitsLoaded = FALSE;
  911. POINT gdiPoints[3];
  912. // When printing we want to punt simple DrawImage calls to
  913. // GDI using StretchDIBits. We check the criteria here, must
  914. // have simple transoformation.
  915. if (IsPrinter() &&
  916. (Context->WorldToDevice.IsTranslateScale()) &&
  917. (numPoints == 3) &&
  918. (REALABS(fDst[0].X - fDst[2].X) < REAL_EPSILON) &&
  919. (REALABS(fDst[0].Y - fDst[1].Y) < REAL_EPSILON) &&
  920. (fDst[1].X > fDst[0].X) &&
  921. (fDst[2].Y > fDst[0].Y) &&
  922. (Context->WorldToDevice.Transform(fDst, gdiPoints, 3),
  923. ((gdiPoints[1].x > gdiPoints[0].x) && // no flipping
  924. (gdiPoints[2].y > gdiPoints[0].y)) ) )
  925. {
  926. // try PNG or JPG passthrough of compressed bits on Win98/NT
  927. if (!Globals::IsWin95 &&
  928. (cloneBitmap == NULL) && // no recoloring
  929. (srcRect.Height >= ((height*9)/10)) &&
  930. (srcRect.Width >= ((width*9)/10)) &&
  931. (srcRect.Height >= 32) &&
  932. (srcRect.Width >= 32))
  933. {
  934. // !! ICM convert??
  935. // !! Source rectangle is outside of image or WrapMode* on bitmap
  936. HDC hdc;
  937. { // FPU Sandbox for potentially unsafe FPU code.
  938. FPUStateSandbox fpsb;
  939. hdc = Context->GetHdc(Surface);
  940. } // FPU Sandbox for potentially unsafe FPU code.
  941. if (hdc != NULL)
  942. {
  943. DriverPrint *dprint = (DriverPrint*)Driver;
  944. status = srcBitmap->GetCompressedData(&compressedData,
  945. dprint->SupportJPEGpassthrough,
  946. dprint->SupportPNGpassthrough,
  947. hdc);
  948. if (compressedData.buffer != NULL)
  949. {
  950. if (REALABS(width) < REAL_EPSILON ||
  951. REALABS(height) < REAL_EPSILON )
  952. {
  953. bmpDataSrc.Width = srcBitmapImageInfo.Width;
  954. bmpDataSrc.Height = srcBitmapImageInfo.Height;
  955. }
  956. else
  957. {
  958. bmpDataSrc.Width = GpRound(width);
  959. bmpDataSrc.Height = GpRound(height);
  960. }
  961. bmpDataSrc.Stride = 0;
  962. bmpDataSrc.PixelFormat = PixelFormatDontCare;
  963. bmpDataSrc.Scan0 = NULL;
  964. bmpDataSrc.Reserved = 0;
  965. bitsLoaded = TRUE;
  966. // Since the driver supports passthrough of
  967. // this image, it is responsible for any
  968. // transparency at printer level. From here,
  969. // we treat image as opaque.
  970. transparency = TransparencyOpaque;
  971. lockedPixelFormat = PixelFormatDontCare;
  972. }
  973. Context->ReleaseHdc(hdc, Surface);
  974. }
  975. }
  976. if (!bitsLoaded)
  977. {
  978. // If reasonable pixel format then get GDI to understand
  979. // the format natively.
  980. if (((srcBitmapImageInfo.PixelFormat & PixelFormatGDI) != 0) &&
  981. !IsAlphaPixelFormat(srcBitmapImageInfo.PixelFormat) &&
  982. !IsExtendedPixelFormat(srcBitmapImageInfo.PixelFormat) &&
  983. (GetPixelFormatSize(srcBitmapImageInfo.PixelFormat) <= 8))
  984. {
  985. lockedPixelFormat = srcBitmapImageInfo.PixelFormat;
  986. }
  987. if (Context->CompositingMode == CompositingModeSourceCopy)
  988. {
  989. transparency = TransparencyNoAlpha;
  990. }
  991. else
  992. {
  993. if (srcBitmap->GetTransparencyFlags(&transparency,
  994. lockedPixelFormat,
  995. &minAlpha,
  996. &maxAlpha) != Ok)
  997. {
  998. transparency = TransparencyUnknown;
  999. }
  1000. // We only want to lock at this pixel format if it
  1001. // is opaque, otherwise we won't punt to GDI. We take
  1002. // the hit of decoding twice, but notice it will likely
  1003. // be cheaper to load & test transparency at original
  1004. // depth.
  1005. if (transparency != TransparencyOpaque &&
  1006. transparency != TransparencyNoAlpha)
  1007. {
  1008. lockedPixelFormat = PIXFMT_32BPP_PARGB;
  1009. }
  1010. }
  1011. }
  1012. }
  1013. else
  1014. {
  1015. if (IsPrinter())
  1016. {
  1017. // SourceCopy implies there is no alpha transfer to
  1018. // destination.
  1019. if (Context->CompositingMode == CompositingModeSourceCopy)
  1020. {
  1021. transparency = TransparencyNoAlpha;
  1022. }
  1023. else
  1024. {
  1025. // Query image for accurate transparency flags. If
  1026. // necessary, load into memory at 32bpp PARGB.
  1027. if (srcBitmap->GetTransparencyFlags(&transparency,
  1028. lockedPixelFormat,
  1029. &minAlpha,
  1030. &maxAlpha) != Ok)
  1031. {
  1032. transparency = TransparencyUnknown;
  1033. }
  1034. }
  1035. }
  1036. else
  1037. {
  1038. // non-printing scenarios query transparency flags only
  1039. if (srcBitmap->GetTransparencyHint(&transparency) != Ok)
  1040. {
  1041. transparency = TransparencyUnknown;
  1042. }
  1043. }
  1044. }
  1045. // Lock the bits.
  1046. // It's important that we lock the bits in a premultiplied
  1047. // pixel format because the image filtering code for stretches
  1048. // and rotation requires premultiplied input data to avoid the
  1049. // "halo effect" on transparent borders.
  1050. // This is going to trigger an expensive image format conversion
  1051. // if the input data is not already premultiplied. This is
  1052. // obviously true if we've done Recoloring which requires
  1053. // and outputs non-premultiplied data.
  1054. // A notable exception is metafiling which requires
  1055. // non-premultiplied data.
  1056. // Note that the width and height that we get back in the
  1057. // bmpDataSrc are the 'real' width and height. They represent
  1058. // what the codec was actually able to do for us and may not
  1059. // be equal to the width and height passed in.
  1060. if (!bitsLoaded)
  1061. {
  1062. status = srcBitmap->LockBits(
  1063. NULL,
  1064. IMGLOCK_READ,
  1065. lockedPixelFormat,
  1066. &bmpDataSrc,
  1067. GpRound(width),
  1068. GpRound(height)
  1069. );
  1070. }
  1071. }
  1072. else
  1073. {
  1074. status = InvalidParameter;
  1075. }
  1076. // We have been successful at everything including locking the bits.
  1077. // Now lets actually set up the driver call.
  1078. if(status == Ok)
  1079. {
  1080. DpBitmap driverSurface;
  1081. // Fake up a DpBitmap for the driver call.
  1082. // We do this because the GpBitmap doesn't maintain the
  1083. // DpBitmap as a driver surface - instead it uses a
  1084. // GpMemoryBitmap.
  1085. srcBitmap->InitializeSurfaceForGdipBitmap(
  1086. &driverSurface,
  1087. bmpDataSrc.Width,
  1088. bmpDataSrc.Height
  1089. );
  1090. driverSurface.Bits = bmpDataSrc.Scan0;
  1091. driverSurface.Width = bmpDataSrc.Width;
  1092. driverSurface.Height = bmpDataSrc.Height;
  1093. driverSurface.Delta = bmpDataSrc.Stride;
  1094. driverSurface.PixelFormat = lockedPixelFormat;
  1095. // only valid when PixelFormat is 32bpp
  1096. driverSurface.NumBytes =
  1097. bmpDataSrc.Width*
  1098. bmpDataSrc.Height*
  1099. sizeof(ARGB);
  1100. if (compressedData.buffer != NULL)
  1101. {
  1102. driverSurface.CompressedData = &compressedData;
  1103. }
  1104. if (IsIndexedPixelFormat(lockedPixelFormat))
  1105. {
  1106. INT size = srcBitmap->GetPaletteSize();
  1107. if (size > 0)
  1108. {
  1109. driverSurface.PaletteTable = (ColorPalette*)GpMalloc(size);
  1110. if(driverSurface.PaletteTable)
  1111. {
  1112. status = srcBitmap->GetPalette(
  1113. driverSurface.PaletteTable,
  1114. size
  1115. );
  1116. }
  1117. else
  1118. {
  1119. status = OutOfMemory;
  1120. }
  1121. if(Ok != status)
  1122. {
  1123. goto cleanup;
  1124. }
  1125. }
  1126. }
  1127. driverSurface.SurfaceTransparency = transparency;
  1128. driverSurface.MinAlpha = minAlpha;
  1129. driverSurface.MaxAlpha = maxAlpha;
  1130. // Fake up a DpImageAttributes if the imageAttributes is NULL
  1131. // !!! PERF: [asecchia] It would be more efficient to not have
  1132. // to do the multiple DpImageAttributes copies here - rather
  1133. // we should pass it by pointer - that way we could use NULL
  1134. // for the common case (no imageAttributes).
  1135. DpImageAttributes dpImageAttributes;
  1136. if(imageAttributes)
  1137. {
  1138. dpImageAttributes = imageAttributes->DeviceImageAttributes;
  1139. }
  1140. BOOL DestroyBitsWhenDone = FALSE;
  1141. if(((INT)(bmpDataSrc.Width) != srcBitmapImageInfo.Width) ||
  1142. ((INT)(bmpDataSrc.Height) != srcBitmapImageInfo.Height))
  1143. {
  1144. ASSERT(srcBitmapImageInfo.Width != 0);
  1145. ASSERT(srcBitmapImageInfo.Height != 0);
  1146. // The size we got back from LockBits is different from
  1147. // the queried size of the image. This means that the codec
  1148. // was able to perform some scaling for us (presumably for
  1149. // some performance benefit).
  1150. // Scale the source rectangle appropriately.
  1151. REAL scaleFactorX = (REAL)(bmpDataSrc.Width)/srcBitmapImageInfo.Width;
  1152. REAL scaleFactorY = (REAL)(bmpDataSrc.Height)/srcBitmapImageInfo.Height;
  1153. bboxSrcRect.X = scaleFactorX*bboxSrcRect.X;
  1154. bboxSrcRect.Y = scaleFactorY*bboxSrcRect.Y;
  1155. bboxSrcRect.Width = scaleFactorX*bboxSrcRect.Width;
  1156. bboxSrcRect.Height = scaleFactorY*bboxSrcRect.Height;
  1157. // We have only a partial decode. That means the bits we have
  1158. // in memory may not be sufficient for the next draw, so
  1159. // blow the bits away to force a decode on the next draw.
  1160. DestroyBitsWhenDone = TRUE;
  1161. }
  1162. // Call the driver to draw the image.
  1163. status = Driver->DrawImage(
  1164. Context, &driverSurface, Surface,
  1165. drawBounds,
  1166. &dpImageAttributes,
  1167. numPoints, fDst,
  1168. &bboxSrcRect, flags
  1169. );
  1170. if (lockedPixelFormat != PixelFormatDontCare)
  1171. {
  1172. ASSERT(bmpDataSrc.Scan0 != NULL);
  1173. srcBitmap->UnlockBits(&bmpDataSrc, DestroyBitsWhenDone);
  1174. }
  1175. }
  1176. // delete compressed data allocation if any
  1177. if (compressedData.buffer != NULL)
  1178. {
  1179. srcBitmap->DeleteCompressedData(&compressedData);
  1180. }
  1181. // Restore the Transformation
  1182. Context->WorldToDevice = worldDevice;
  1183. if (clipRegion != NULL)
  1184. {
  1185. // What if we fail this?
  1186. if (restoreClipping)
  1187. {
  1188. SetClip(clipRegion, CombineModeReplace);
  1189. }
  1190. delete clipRegion;
  1191. }
  1192. }
  1193. cleanup:
  1194. // Throw away any temporary storage we used and clean up any state changes.
  1195. Context->WorldToDevice = saveWorldToDevice;
  1196. if (cloneBitmap)
  1197. {
  1198. cloneBitmap->Dispose();
  1199. }
  1200. if (xformBitmap)
  1201. {
  1202. xformBitmap->Dispose();
  1203. }
  1204. return status;
  1205. }
  1206. // This is really an ARGB array
  1207. BYTE GdipSolidColors216[224 * 4] = {
  1208. // blue grn red alpha
  1209. 0x00, 0x00, 0x00, 0xFF,
  1210. 0x00, 0x00, 0x80, 0xFF,
  1211. 0x00, 0x80, 0x00, 0xFF,
  1212. 0x00, 0x80, 0x80, 0xFF,
  1213. 0x80, 0x00, 0x00, 0xFF,
  1214. 0x80, 0x00, 0x80, 0xFF,
  1215. 0x80, 0x80, 0x00, 0xFF,
  1216. 0x80, 0x80, 0x80, 0xFF,
  1217. 0xC0, 0xC0, 0xC0, 0xFF,
  1218. 0xFF, 0x00, 0x00, 0xFF,
  1219. 0x00, 0xFF, 0x00, 0xFF,
  1220. 0xFF, 0xFF, 0x00, 0xFF,
  1221. 0x00, 0x00, 0xFF, 0xFF,
  1222. 0xFF, 0x00, 0xFF, 0xFF,
  1223. 0x00, 0xFF, 0xFF, 0xFF,
  1224. 0xFF, 0xFF, 0xFF, 0xFF,
  1225. 0x33, 0x00, 0x00, 0xFF,
  1226. 0x66, 0x00, 0x00, 0xFF,
  1227. 0x99, 0x00, 0x00, 0xFF,
  1228. 0xCC, 0x00, 0x00, 0xFF,
  1229. 0x00, 0x33, 0x00, 0xFF,
  1230. 0x33, 0x33, 0x00, 0xFF,
  1231. 0x66, 0x33, 0x00, 0xFF,
  1232. 0x99, 0x33, 0x00, 0xFF,
  1233. 0xCC, 0x33, 0x00, 0xFF,
  1234. 0xFF, 0x33, 0x00, 0xFF,
  1235. 0x00, 0x66, 0x00, 0xFF,
  1236. 0x33, 0x66, 0x00, 0xFF,
  1237. 0x66, 0x66, 0x00, 0xFF,
  1238. 0x99, 0x66, 0x00, 0xFF,
  1239. 0xCC, 0x66, 0x00, 0xFF,
  1240. 0xFF, 0x66, 0x00, 0xFF,
  1241. 0x00, 0x99, 0x00, 0xFF,
  1242. 0x33, 0x99, 0x00, 0xFF,
  1243. 0x66, 0x99, 0x00, 0xFF,
  1244. 0x99, 0x99, 0x00, 0xFF,
  1245. 0xCC, 0x99, 0x00, 0xFF,
  1246. 0xFF, 0x99, 0x00, 0xFF,
  1247. 0x00, 0xCC, 0x00, 0xFF,
  1248. 0x33, 0xCC, 0x00, 0xFF,
  1249. 0x66, 0xCC, 0x00, 0xFF,
  1250. 0x99, 0xCC, 0x00, 0xFF,
  1251. 0xCC, 0xCC, 0x00, 0xFF,
  1252. 0xFF, 0xCC, 0x00, 0xFF,
  1253. 0x33, 0xFF, 0x00, 0xFF,
  1254. 0x66, 0xFF, 0x00, 0xFF,
  1255. 0x99, 0xFF, 0x00, 0xFF,
  1256. 0xCC, 0xFF, 0x00, 0xFF,
  1257. 0x00, 0x00, 0x33, 0xFF,
  1258. 0x33, 0x00, 0x33, 0xFF,
  1259. 0x66, 0x00, 0x33, 0xFF,
  1260. 0x99, 0x00, 0x33, 0xFF,
  1261. 0xCC, 0x00, 0x33, 0xFF,
  1262. 0xFF, 0x00, 0x33, 0xFF,
  1263. 0x00, 0x33, 0x33, 0xFF,
  1264. 0x33, 0x33, 0x33, 0xFF,
  1265. 0x66, 0x33, 0x33, 0xFF,
  1266. 0x99, 0x33, 0x33, 0xFF,
  1267. 0xCC, 0x33, 0x33, 0xFF,
  1268. 0xFF, 0x33, 0x33, 0xFF,
  1269. 0x00, 0x66, 0x33, 0xFF,
  1270. 0x33, 0x66, 0x33, 0xFF,
  1271. 0x66, 0x66, 0x33, 0xFF,
  1272. 0x99, 0x66, 0x33, 0xFF,
  1273. 0xCC, 0x66, 0x33, 0xFF,
  1274. 0xFF, 0x66, 0x33, 0xFF,
  1275. 0x00, 0x99, 0x33, 0xFF,
  1276. 0x33, 0x99, 0x33, 0xFF,
  1277. 0x66, 0x99, 0x33, 0xFF,
  1278. 0x99, 0x99, 0x33, 0xFF,
  1279. 0xCC, 0x99, 0x33, 0xFF,
  1280. 0xFF, 0x99, 0x33, 0xFF,
  1281. 0x00, 0xCC, 0x33, 0xFF,
  1282. 0x33, 0xCC, 0x33, 0xFF,
  1283. 0x66, 0xCC, 0x33, 0xFF,
  1284. 0x99, 0xCC, 0x33, 0xFF,
  1285. 0xCC, 0xCC, 0x33, 0xFF,
  1286. 0xFF, 0xCC, 0x33, 0xFF,
  1287. 0x00, 0xFF, 0x33, 0xFF,
  1288. 0x33, 0xFF, 0x33, 0xFF,
  1289. 0x66, 0xFF, 0x33, 0xFF,
  1290. 0x99, 0xFF, 0x33, 0xFF,
  1291. 0xCC, 0xFF, 0x33, 0xFF,
  1292. 0xFF, 0xFF, 0x33, 0xFF,
  1293. 0x00, 0x00, 0x66, 0xFF,
  1294. 0x33, 0x00, 0x66, 0xFF,
  1295. 0x66, 0x00, 0x66, 0xFF,
  1296. 0x99, 0x00, 0x66, 0xFF,
  1297. 0xCC, 0x00, 0x66, 0xFF,
  1298. 0xFF, 0x00, 0x66, 0xFF,
  1299. 0x00, 0x33, 0x66, 0xFF,
  1300. 0x33, 0x33, 0x66, 0xFF,
  1301. 0x66, 0x33, 0x66, 0xFF,
  1302. 0x99, 0x33, 0x66, 0xFF,
  1303. 0xCC, 0x33, 0x66, 0xFF,
  1304. 0xFF, 0x33, 0x66, 0xFF,
  1305. 0x00, 0x66, 0x66, 0xFF,
  1306. 0x33, 0x66, 0x66, 0xFF,
  1307. 0x66, 0x66, 0x66, 0xFF,
  1308. 0x99, 0x66, 0x66, 0xFF,
  1309. 0xCC, 0x66, 0x66, 0xFF,
  1310. 0xFF, 0x66, 0x66, 0xFF,
  1311. 0x00, 0x99, 0x66, 0xFF,
  1312. 0x33, 0x99, 0x66, 0xFF,
  1313. 0x66, 0x99, 0x66, 0xFF,
  1314. 0x99, 0x99, 0x66, 0xFF,
  1315. 0xCC, 0x99, 0x66, 0xFF,
  1316. 0xFF, 0x99, 0x66, 0xFF,
  1317. 0x00, 0xCC, 0x66, 0xFF,
  1318. 0x33, 0xCC, 0x66, 0xFF,
  1319. 0x66, 0xCC, 0x66, 0xFF,
  1320. 0x99, 0xCC, 0x66, 0xFF,
  1321. 0xCC, 0xCC, 0x66, 0xFF,
  1322. 0xFF, 0xCC, 0x66, 0xFF,
  1323. 0x00, 0xFF, 0x66, 0xFF,
  1324. 0x33, 0xFF, 0x66, 0xFF,
  1325. 0x66, 0xFF, 0x66, 0xFF,
  1326. 0x99, 0xFF, 0x66, 0xFF,
  1327. 0xCC, 0xFF, 0x66, 0xFF,
  1328. 0xFF, 0xFF, 0x66, 0xFF,
  1329. 0x00, 0x00, 0x99, 0xFF,
  1330. 0x33, 0x00, 0x99, 0xFF,
  1331. 0x66, 0x00, 0x99, 0xFF,
  1332. 0x99, 0x00, 0x99, 0xFF,
  1333. 0xCC, 0x00, 0x99, 0xFF,
  1334. 0xFF, 0x00, 0x99, 0xFF,
  1335. 0x00, 0x33, 0x99, 0xFF,
  1336. 0x33, 0x33, 0x99, 0xFF,
  1337. 0x66, 0x33, 0x99, 0xFF,
  1338. 0x99, 0x33, 0x99, 0xFF,
  1339. 0xCC, 0x33, 0x99, 0xFF,
  1340. 0xFF, 0x33, 0x99, 0xFF,
  1341. 0x00, 0x66, 0x99, 0xFF,
  1342. 0x33, 0x66, 0x99, 0xFF,
  1343. 0x66, 0x66, 0x99, 0xFF,
  1344. 0x99, 0x66, 0x99, 0xFF,
  1345. 0xCC, 0x66, 0x99, 0xFF,
  1346. 0xFF, 0x66, 0x99, 0xFF,
  1347. 0x00, 0x99, 0x99, 0xFF,
  1348. 0x33, 0x99, 0x99, 0xFF,
  1349. 0x66, 0x99, 0x99, 0xFF,
  1350. 0x99, 0x99, 0x99, 0xFF,
  1351. 0xCC, 0x99, 0x99, 0xFF,
  1352. 0xFF, 0x99, 0x99, 0xFF,
  1353. 0x00, 0xCC, 0x99, 0xFF,
  1354. 0x33, 0xCC, 0x99, 0xFF,
  1355. 0x66, 0xCC, 0x99, 0xFF,
  1356. 0x99, 0xCC, 0x99, 0xFF,
  1357. 0xCC, 0xCC, 0x99, 0xFF,
  1358. 0xFF, 0xCC, 0x99, 0xFF,
  1359. 0x00, 0xFF, 0x99, 0xFF,
  1360. 0x33, 0xFF, 0x99, 0xFF,
  1361. 0x66, 0xFF, 0x99, 0xFF,
  1362. 0x99, 0xFF, 0x99, 0xFF,
  1363. 0xCC, 0xFF, 0x99, 0xFF,
  1364. 0xFF, 0xFF, 0x99, 0xFF,
  1365. 0x00, 0x00, 0xCC, 0xFF,
  1366. 0x33, 0x00, 0xCC, 0xFF,
  1367. 0x66, 0x00, 0xCC, 0xFF,
  1368. 0x99, 0x00, 0xCC, 0xFF,
  1369. 0xCC, 0x00, 0xCC, 0xFF,
  1370. 0xFF, 0x00, 0xCC, 0xFF,
  1371. 0x00, 0x33, 0xCC, 0xFF,
  1372. 0x33, 0x33, 0xCC, 0xFF,
  1373. 0x66, 0x33, 0xCC, 0xFF,
  1374. 0x99, 0x33, 0xCC, 0xFF,
  1375. 0xCC, 0x33, 0xCC, 0xFF,
  1376. 0xFF, 0x33, 0xCC, 0xFF,
  1377. 0x00, 0x66, 0xCC, 0xFF,
  1378. 0x33, 0x66, 0xCC, 0xFF,
  1379. 0x66, 0x66, 0xCC, 0xFF,
  1380. 0x99, 0x66, 0xCC, 0xFF,
  1381. 0xCC, 0x66, 0xCC, 0xFF,
  1382. 0xFF, 0x66, 0xCC, 0xFF,
  1383. 0x00, 0x99, 0xCC, 0xFF,
  1384. 0x33, 0x99, 0xCC, 0xFF,
  1385. 0x66, 0x99, 0xCC, 0xFF,
  1386. 0x99, 0x99, 0xCC, 0xFF,
  1387. 0xCC, 0x99, 0xCC, 0xFF,
  1388. 0xFF, 0x99, 0xCC, 0xFF,
  1389. 0x00, 0xCC, 0xCC, 0xFF,
  1390. 0x33, 0xCC, 0xCC, 0xFF,
  1391. 0x66, 0xCC, 0xCC, 0xFF,
  1392. 0x99, 0xCC, 0xCC, 0xFF,
  1393. 0xCC, 0xCC, 0xCC, 0xFF,
  1394. 0xFF, 0xCC, 0xCC, 0xFF,
  1395. 0x00, 0xFF, 0xCC, 0xFF,
  1396. 0x33, 0xFF, 0xCC, 0xFF,
  1397. 0x66, 0xFF, 0xCC, 0xFF,
  1398. 0x99, 0xFF, 0xCC, 0xFF,
  1399. 0xCC, 0xFF, 0xCC, 0xFF,
  1400. 0xFF, 0xFF, 0xCC, 0xFF,
  1401. 0x33, 0x00, 0xFF, 0xFF,
  1402. 0x66, 0x00, 0xFF, 0xFF,
  1403. 0x99, 0x00, 0xFF, 0xFF,
  1404. 0xCC, 0x00, 0xFF, 0xFF,
  1405. 0x00, 0x33, 0xFF, 0xFF,
  1406. 0x33, 0x33, 0xFF, 0xFF,
  1407. 0x66, 0x33, 0xFF, 0xFF,
  1408. 0x99, 0x33, 0xFF, 0xFF,
  1409. 0xCC, 0x33, 0xFF, 0xFF,
  1410. 0xFF, 0x33, 0xFF, 0xFF,
  1411. 0x00, 0x66, 0xFF, 0xFF,
  1412. 0x33, 0x66, 0xFF, 0xFF,
  1413. 0x66, 0x66, 0xFF, 0xFF,
  1414. 0x99, 0x66, 0xFF, 0xFF,
  1415. 0xCC, 0x66, 0xFF, 0xFF,
  1416. 0xFF, 0x66, 0xFF, 0xFF,
  1417. 0x00, 0x99, 0xFF, 0xFF,
  1418. 0x33, 0x99, 0xFF, 0xFF,
  1419. 0x66, 0x99, 0xFF, 0xFF,
  1420. 0x99, 0x99, 0xFF, 0xFF,
  1421. 0xCC, 0x99, 0xFF, 0xFF,
  1422. 0xFF, 0x99, 0xFF, 0xFF,
  1423. 0x00, 0xCC, 0xFF, 0xFF,
  1424. 0x33, 0xCC, 0xFF, 0xFF,
  1425. 0x66, 0xCC, 0xFF, 0xFF,
  1426. 0x99, 0xCC, 0xFF, 0xFF,
  1427. 0xCC, 0xCC, 0xFF, 0xFF,
  1428. 0xFF, 0xCC, 0xFF, 0xFF,
  1429. 0x33, 0xFF, 0xFF, 0xFF,
  1430. 0x66, 0xFF, 0xFF, 0xFF,
  1431. 0x99, 0xFF, 0xFF, 0xFF,
  1432. 0xCC, 0xFF, 0xFF, 0xFF,
  1433. };
  1434. ARGB
  1435. GpGraphics::GetNearestColor(
  1436. ARGB argb
  1437. )
  1438. {
  1439. HalftoneType halftoneType = this->GetHalftoneType();
  1440. // See if we are doing any halftoning
  1441. if (halftoneType < HalftoneType16Color)
  1442. {
  1443. return argb;
  1444. }
  1445. INT r = GpColor::GetRedARGB(argb);
  1446. INT g = GpColor::GetGreenARGB(argb);
  1447. INT b = GpColor::GetBlueARGB(argb);
  1448. // Handle 15 and 16 bpp halftoning:
  1449. if (halftoneType == HalftoneType15Bpp)
  1450. {
  1451. if (!Globals::IsNt)
  1452. {
  1453. // Subtract the bias, saturated to 0:
  1454. r = (r < 4) ? 0 : (r - 4);
  1455. g = (g < 4) ? 0 : (g - 4);
  1456. b = (b < 4) ? 0 : (b - 4);
  1457. }
  1458. // Clear low 3 bits of each for a solid color:
  1459. r &= 248;
  1460. g &= 248;
  1461. b &= 248;
  1462. return GpColor((BYTE) r, (BYTE) g, (BYTE) b).GetValue();
  1463. }
  1464. else if (halftoneType == HalftoneType16Bpp)
  1465. {
  1466. if (!Globals::IsNt)
  1467. {
  1468. // Subtract the bias, saturated to 0:
  1469. r = (r < 4) ? 0 : (r - 4);
  1470. g = (g < 2) ? 0 : (g - 2);
  1471. b = (b < 4) ? 0 : (b - 4);
  1472. }
  1473. // Clear low n bits of each for a solid color:
  1474. r &= 248; // 5, n = 3
  1475. g &= 252; // 6, n = 2
  1476. b &= 248; // 5, n = 3
  1477. return GpColor((BYTE) r, (BYTE) g, (BYTE) b).GetValue();
  1478. }
  1479. // Handle remaining cases, 4 bpp and 8 bpp halftoning:
  1480. ASSERT((halftoneType == HalftoneType16Color) ||
  1481. (halftoneType == HalftoneType216Color));
  1482. INT i;
  1483. INT deltaR;
  1484. INT deltaG;
  1485. INT deltaB;
  1486. INT curError;
  1487. INT minError = (255 * 255) + (255 * 255) + (255 * 255) + 1;
  1488. ARGB nearestColor;
  1489. INT max = (halftoneType == HalftoneType216Color) ? 224 * 4 : 16 * 4;
  1490. i = 0;
  1491. do
  1492. {
  1493. deltaR = GdipSolidColors216[i+2] - r;
  1494. deltaG = GdipSolidColors216[i+1] - g;
  1495. deltaB = GdipSolidColors216[i+0] - b;
  1496. curError = (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB);
  1497. if (curError < minError)
  1498. {
  1499. nearestColor = *((ARGB *)(GdipSolidColors216 + i));
  1500. if (curError == 0)
  1501. {
  1502. goto Found;
  1503. }
  1504. minError = curError;
  1505. }
  1506. i += 4;
  1507. } while (i < max);
  1508. // Check to see if it is one of the four system colors.
  1509. // Only return a system color if it is an exact match.
  1510. COLORREF rgb;
  1511. rgb = RGB(r,g,b);
  1512. if ((rgb == Globals::SystemColors[16]) ||
  1513. (rgb == Globals::SystemColors[17]) ||
  1514. (rgb == Globals::SystemColors[18]) ||
  1515. (rgb == Globals::SystemColors[19]))
  1516. {
  1517. return argb;
  1518. }
  1519. Found:
  1520. // return the same alpha value
  1521. INT a = argb & Color::AlphaMask;
  1522. if (a != Color::AlphaMask)
  1523. {
  1524. nearestColor = (nearestColor & (~Color::AlphaMask)) | a;
  1525. }
  1526. return nearestColor;
  1527. }