public void Round() { Assert.AreEqual(rectI, rectD.Round()); Assert.AreEqual(rectI, new RectD(0.6, 1.6, 3.6, 4.6).Round()); Assert.AreEqual(rectI, new RectD(1.4, 2.4, 4.4, 5.4).Round()); Assert.AreEqual(rectI, rectF.Round()); Assert.AreEqual(rectI, new RectF(0.6f, 1.6f, 3.6f, 4.6f).Round()); Assert.AreEqual(rectI, new RectF(1.4f, 2.4f, 4.4f, 5.4f).Round()); }
/// <summary> /// Draws an image frame that is centered within the specified <see cref="RectD"/>. /// </summary> /// <param name="targetBitmap"> /// The <see cref="WriteableBitmap"/> for the drawing, assuming that <paramref /// name="targetContext"/> is a null reference.</param> /// <param name="targetContext"> /// The <see cref="DrawingContext"/> for the drawing, assuming that <paramref /// name="targetBitmap"/> is a null reference.</param> /// <param name="target"> /// The region within <paramref name="targetContext"/> on which the copied image frame is /// centered.</param> /// <param name="sourceBitmap"> /// A <see cref="WriteableBitmap"/> containing the image frame to copy.</param> /// <param name="source"> /// The region within <paramref name="sourceBitmap"/> that covers the image frame to copy. /// </param> /// <param name="scalingX"> /// An <see cref="ImageScaling"/> value indicating the horizontal scaling of the <paramref /// name="source"/> region to fit the specified <paramref name="target"/> region.</param> /// <param name="scalingY"> /// An <see cref="ImageScaling"/> value indicating the vertical scaling of the <paramref /// name="source"/> region to fit the specified <paramref name="target"/> region.</param> /// <param name="colorShift"> /// An optional <see cref="ColorVector"/> applied to all pixels within the drawing. Specify /// <see cref="ColorVector.Empty"/> if colors should remain unchanged.</param> /// <param name="offset"> /// An optional pixel offset that is added to the centered location within the <paramref /// name="target"/> region.</param> /// <param name="scalingVector"> /// An optional scaling vector for the drawing. Specify <see cref="PointI.Empty"/> if no /// scaling vector should be applied.</param> /// <exception cref="ArgumentException"> /// <paramref name="targetBitmap"/> and <paramref name="targetContext"/> are both valid or /// both null references.</exception> /// <exception cref="ArgumentNullException"> /// <paramref name="sourceBitmap"/> is a null reference.</exception> /// <remarks><para> /// <b>DrawFrame</b> expects that the specified <paramref name="target"/> region equals the /// <see cref="RegularPolygon.Bounds"/> of the desired <see cref="RegularPolygon"/> shape. /// <b>DrawFrame</b> does not apply a mask or draw an outline around the frame. /// </para><para> /// Either the specified <paramref name="targetBitmap"/> or the specified <paramref /// name="targetContext"/> must be valid, but not both. <b>DrawFrame</b> internally draws to /// a <see cref="WriteableBitmap"/> whenever possible to preserve visual quality, then /// copies the result to the specified drawing target if different. Alpha blending is /// performed only when drawing to a valid <paramref name="targetContext"/>. /// </para><para> /// If <paramref name="targetBitmap"/> is valid, it must be locked before <b>DrawFrame</b> /// is called. If <paramref name="targetContext"/> is valid, the specified <paramref /// name="scalingVector"/> is applied to its transformation matrix; otherwise, negative /// components indicate mirroring along the corresponding axis of the <paramref /// name="targetBitmap"/>.</para></remarks> internal static void DrawFrame(WriteableBitmap targetBitmap, DrawingContext targetContext, RectD target, WriteableBitmap sourceBitmap, RectI source, ImageScaling scalingX, ImageScaling scalingY, ColorVector colorShift, PointI offset, PointI scalingVector) { // exactly one drawing target must be valid if ((targetContext == null && targetBitmap == null) || (targetContext != null && targetBitmap != null)) { ThrowHelper.ThrowArgumentExceptionWithFormat( "targetBitmap", Tektosyne.Strings.ArgumentConflict, targetContext); } if (sourceBitmap == null) { ThrowHelper.ThrowArgumentNullException("sourceBitmap"); } // copy source tile to buffer bitmap var frameBitmap = new WriteableBitmap( source.Width, source.Height, 96, 96, PixelFormats.Pbgra32, null); frameBitmap.Lock(); frameBitmap.Read(0, 0, sourceBitmap, source); // shift color channels if desired if (!colorShift.IsEmpty) { frameBitmap.Shift(colorShift.R, colorShift.G, colorShift.B); } frameBitmap.Unlock(); // round target coordinates for bitmaps RectI targetI = target.Round(); // use WPF drawing for Stretch scaling, else bitmap copying if (scalingX == ImageScaling.Stretch || scalingY == ImageScaling.Stretch) { // create intermediate context if necessary DrawingVisual visual = null; if (targetContext == null) { visual = new DrawingVisual(); targetContext = visual.RenderOpen(); } // draw frame to target or intermediate context DrawFrameCore(targetContext, target, frameBitmap, scalingX, scalingY, offset, scalingVector); // copy intermediate context to target bitmap if (visual != null) { targetContext.Close(); var bitmap = new RenderTargetBitmap( targetI.Right, targetI.Bottom, 96, 96, PixelFormats.Pbgra32); bitmap.Render(visual); targetBitmap.Read(targetI.X, targetI.Y, bitmap, targetI); } } else { // create intermediate bitmap if necessary if (targetContext != null) { Debug.Assert(targetBitmap == null); targetBitmap = new WriteableBitmap( targetI.Right, targetI.Bottom, 96, 96, PixelFormats.Pbgra32, null); targetBitmap.Lock(); } // draw frame to target or intermediate bitmap DrawFrameCore(targetBitmap, targetI, frameBitmap, scalingX, scalingY, offset, scalingVector); // copy intermediate bitmap to target context if (targetContext != null) { targetBitmap.Unlock(); targetContext.DrawImage(targetBitmap, new Rect(0, 0, targetBitmap.Width, targetBitmap.Height)); } } }