// External API public void RenderImage(ImageProxy image, Rect dest, Geometry clip, Matrix trans, string desp) { if (image == null) { return; } Geometry bounds; bool clipToBounds; if (clip == null) { // no clipping needed, draw everything bounds = Utility.TransformGeometry(new RectangleGeometry(dest), trans); clipToBounds = false; } else { // clip to provided geometry. it's already in world space bounds = clip; clipToBounds = true; } RenderImage(image, dest, bounds, clipToBounds, 0, trans, desp); }
void IProxyDrawingContext.DrawImage(ImageProxy image, Rect dest, Geometry clip, Matrix trans) { bool empty; clip = Utility.Intersect(_clip, Utility.TransformGeometry(clip, _transform), Matrix.Identity, out empty); if (empty) { return; } ImagePrimitive ip = new ImagePrimitive(); // Fix bug 1460208: Give each ImagePrimitive its own ImageProxy, since rendering may alter // the images. ip.Image = image.Clone(); ip.DstRect = dest; ip.Clip = clip; ip.Transform = trans * _transform; ip.PushOpacity(_opacity, _opacityMask); _flattener.AddPrimitive(ip); }
void IProxyDrawingContext.DrawImage(ImageProxy image, Rect dest, Geometry clip, Matrix trans) { if (_costing) { _cost += image.PixelWidth * image.PixelHeight * 3; return; } // Sometimes clip selects only a small portion of the image. Clip image to reduce amount // of data sent to GDI. if (clip != null) { if (!Utility.IsRenderVisible(clip.Bounds)) { // completely clipped away return; } // transform clip to image space, taking into account image DPI Matrix imageTransform = new Matrix(); imageTransform.Scale(dest.Width / image.Image.Width, dest.Height / image.Image.Height); imageTransform.Translate(dest.X, dest.Y); imageTransform.Append(trans); imageTransform.Invert(); Geometry imageClip = Utility.TransformGeometry(clip, imageTransform); // Clip the image to clip bounds. ImageProxy.GetClippedImage has no effect if clipping // bounds are almost image size. Rect clippedImageBounds; BitmapSource clippedImageSource = image.GetClippedImage(imageClip.Bounds, out clippedImageBounds); if (clippedImageSource == null) { // image has been clipped away return; } ImageProxy clippedImage = new ImageProxy(clippedImageSource); // adjust destination rectangle to new clipped image bounds double scaleX = dest.Width / image.Image.Width; double scaleY = dest.Height / image.Image.Height; dest = new Rect( clippedImageBounds.X * scaleX + dest.X, clippedImageBounds.Y * scaleY + dest.Y, clippedImageBounds.Width * scaleX, clippedImageBounds.Height * scaleY ); image = clippedImage; } image.BlendOverColor(Colors.White, 1.0, false); // BitmapSource img = image.GetImage(); if (clip != null) { _dc.PushClip(clip); } if (!trans.IsIdentity) { _dc.PushTransform(trans); } #if DEBUG _seq++; _dc.Comment("-> DrawImage " + _seq); #endif _dc.DrawImage(image.Image, image.Buffer, dest); #if DEBUG _dc.Comment("<- DrawImage " + _seq); if (Configuration.Verbose >= 2) { Console.WriteLine(" DrawImage(" + _comment + ")"); } #endif if (!trans.IsIdentity) { _dc.PopTransform(); } if (clip != null) { _dc.PopClip(); } }
// Recursive // _brush must be in world space private void FillGeometry( PrimitiveInfo topPI, Geometry cur, string desp, Geometry curAlt, string despAlt, int start, Geometry inter, Geometry topBounds ) { Primitive p = topPI.primitive; Geometry diff = Utility.Exclude(cur, topBounds, Matrix.Identity); if (diff != null) { // Render cur [- topBounds] using original brush if (_disjoint) { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), null, null, start + 1); #else FillGeometry(diff, null, null, null, start + 1); #endif } else { // Only diff = cur - topBounds need to be rendered. But it may generate more // complicated path and gaps between objects if (curAlt != null) { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), curAlt, despAlt, start + 1); #else FillGeometry(diff, null, curAlt, despAlt, start + 1); #endif } else { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), cur, desp, start + 1); #else FillGeometry(diff, null, cur, desp, start + 1); #endif } } } //if (_disjoint || ! p.IsOpaque) { if (topPI.primitive is ImagePrimitive) { // If primitve on the top is ImagePrimitive, change it to DrawImage with blended image. // An alternative will be generating an image brush ImagePrimitive ip = topPI.primitive as ImagePrimitive; bool empty; double imageWidth = ip.Image.Image.Width; double imageHeight = ip.Image.Image.Height; // Get clip in world space. Geometry clip = Utility.Intersect(inter, Utility.TransformGeometry(new RectangleGeometry(ip.DstRect), ip.Transform), ip.Transform, out empty); if (!empty) { // Get clip bounds in image space. Geometry clipImageSpace = Utility.TransformGeometry(clip, ReverseMap(ip.Transform, ip.DstRect, imageWidth, imageHeight)); Rect drawBounds = clipImageSpace.Bounds; // Clip image data to the intersection. Resulting draw bounds are in image space. BitmapSource clippedImage = ip.Image.GetClippedImage(drawBounds, out drawBounds); if (clippedImage != null) { // Transform draw bounds back to world space. drawBounds.Scale(ip.DstRect.Width / imageWidth, ip.DstRect.Height / imageHeight); drawBounds.Offset(ip.DstRect.Left, ip.DstRect.Top); ImageProxy image = new ImageProxy(clippedImage); // Blend image with other brush, then render composited image. image.BlendOverBrush(false, _brush, ReverseMap(ip.Transform, drawBounds, image.PixelWidth, image.PixelHeight)); #if DEBUG RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, Oper(desp, '*', topPI.id)); #else RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, null); #endif } } } else { // -- If top primitive opaque, skip the intersection // -- If current primitive is completely covered by an opaque object, skip the intersection if (p.IsOpaque) // && Utility.Covers(topBounds, cur)) { cur = null; } else { // Render the intersection using blended brush BrushProxy oldbrush = _brush; _brush = p.BlendBrush(_brush); #if DEBUG FillGeometry(inter, Oper(desp, '*', topPI.id), null, null, start + 1); #else FillGeometry(inter, null, null, null, start + 1); #endif _brush = oldbrush; } } if (cur != null) { bool empty; Geometry geo = Utility.Intersect(cur, _clip, Matrix.Identity, out empty); if (geo != null) { topPI.primitive.Exclude(geo); // exclude cur & _clip #if DEBUG topPI.id = Oper(topPI.id, '-', Oper(desp, '*', Oper(desp, '.', "c"))); #endif } } } }
private void RenderImage( ImageProxy image, Rect dest, Geometry bounds, bool clipToBounds, int start, Matrix trans, string desp ) { PrimitiveInfo topPI; Geometry topBounds; Geometry inter; if (FindIntersection(bounds, ref start, out topPI, out topBounds, out inter)) { Primitive p = topPI.primitive; Geometry diff = Utility.Exclude(bounds, topBounds, trans); // DrawImage may modify image ImageProxy imageBlend = new ImageProxy(image.GetImage()); if (diff != null) { // Render cur - top #if DEBUG RenderImage(image, dest, diff, true, start + 1, trans, Oper(desp, '-', topPI.id)); #else RenderImage(image, dest, diff, true, start + 1, trans, null); #endif } if (!p.IsTransparent) { #if DEBUG topPI.id = Oper(topPI.id, '-', Oper(desp, '.', "bounds")); #endif // Render the intersection using blended image p.BlendOverImage(imageBlend, ReverseMap(trans, dest, imageBlend.PixelWidth, imageBlend.PixelHeight)); #if DEBUG RenderImage(imageBlend, dest, inter, true, start + 1, trans, Oper(desp, '*', topPI.id)); #else RenderImage(imageBlend, dest, inter, true, start + 1, trans, null); #endif } p.Exclude(bounds); } else { Geometry clip = _clip; bool empty = false; if (clipToBounds) { clip = Utility.Intersect(clip, bounds, Matrix.Identity, out empty); } if (!empty) { _dc.Comment(desp); _dc.DrawImage(image, dest, clip, trans); } } }