WPF Rect Transform - wpf

I am trying to apply RotateTransform to a Rect object with the following code.
Rect transformed = this.Rectangle;
transformed.Transform(this.rotateTransform.Value);
DrawingVisual visual = new DrawingVisual();
DrawingContext context = visual.RenderOpen();
context.DrawRectangle(null, new Pen(Brushes.Blue, 2), transformed);
context.Close();
canvas.Children.Add(visual);
but the rectangle is not rotated. However when I push the transformation to the DrawingContext, as in the following code, rectangle is transformed correctly.
Rect transformed = this.Rectangle;
DrawingVisual visual = new DrawingVisual();
DrawingContext context = visual.RenderOpen();
context.PushTransform(this.rotateTransform);
context.DrawRectangle(null, new Pen(Brushes.Blue, 2), transformed);
context.Pop();
context.Close();
canvas.Children.Add(visual);
Is there a way to transform a Rect as in the first code fragment with Rect.Transform(Matrix) function?

Prabably because your rotation is not multiple of 90deg. Transform on Rect results in rect that it parallel to x & y axis!
First case renders modified rectangle that is not rotated a syou desire - seems to be bouding box after rotation
Second case doest what you wish - it first "rotate content", then draws rectangle

Related

WPF Saving image from Canvas using RenderTargetBitmap [duplicate]

I have Grid with three columns and layout is like
radio button | Canvas Control | radio button
For some feature of my application I need to take a screenshot of current view of canvas feature and save into a file.
I am using following method to save canvas to bmp,where I measure and arrange canvas.My problem is after image is saved ,canvas position in original grid is shifted to left,how can I re position my canvas back in grid as it was earlier.
private void SaveCanvasContentToImage(string path, Canvas canvasControl)
{
if (path == null && canvasControl != null) return;
// Save current canvas transform
Transform transform = canvasControl.LayoutTransform;
// reset current transform (in case it is scaled or rotated)
canvasControl.LayoutTransform = null;
// Get the size of canvas
Size size = new Size(canvasControl.Width, canvasControl.Height);
// Measure and arrange the canvas
canvasControl.Measure(size);
canvasControl.Arrange(new Rect(size));
// Create a render bitmap and push the canvas to it
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(canvasControl);
// Create a file stream for saving image
using (FileStream outStream = new FileStream(path, FileMode.CreateNew,FileAccess.ReadWrite))
{
// Use bitmap encoder for our data
BitmapEncoder encoder = new BmpBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
outStream.Close();
outStream.Dispose();
}
// Restore previously saved layout
canvasControl.LayoutTransform = transform;
}
You may avoid the layout problem by using an intermediate DrawingVisual:
var renderTargetBitmap = new RenderTargetBitmap(
(int)canvasControl.ActualWidth, (int)canvasControl.ActualHeight,
96, 96, PixelFormats.Default);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(
new VisualBrush(canvasControl),
null,
new Rect(0, 0, canvasControl.ActualWidth, canvasControl.ActualHeight));
}
renderTargetBitmap.Render(visual);

Imagebrush resolution to render a MeshGeometry3D in WPF

I am visualizing some spatial data using a MeshGeometry3D in WPF. I noticed that passing an ImageBrush to the constructor of DiffuseMaterial makes 3D visualization and manipulation fast and efficient (than say using a VisualBrush). My solution is in the following code block where this.dataMeshModel is a GeometryModel3D that includes the mesh. The problem is that I have to give very high resolutions (1000) to the Bitmap image source to make the grid look nice and distinguishable. Choosing this high dpi seems odd and easily raises memory exceptions. Any suggestion? The data model looks like this for 1000 dpi and this for 4000 dpi. THANKS!
private void assignTexture(Geometry gridGeom, double textureDPI, double gridThickness)
{
// rendering the grid on a DrawingVisual
DrawingVisual dv = new DrawingVisual();
using (var dvc = dv.RenderOpen())
{
dvc.DrawRectangle(Brushes.Tomato, null, gridGeom.Bounds);
dvc.DrawGeometry(null, new Pen(Brushes.Black, gridThickness), gridGeom);
}
if (dv.Drawing.CanFreeze)
{
dv.Drawing.Freeze();
}
//rendering the DrawingVisual to an image
Rect bounds = dv.ContentBounds;
RenderTargetBitmap renderedBitmap = new RenderTargetBitmap(
(int)(bounds.Width * this.textureDPI / 96),
(int)(bounds.Height * this.textureDPI / 96),
this.textureDPI,
this.textureDPI,
PixelFormats.Pbgra32);
renderedBitmap.Render(dv);
// adding the rendered image to create an imagebrush
ImageBrush imBrush = new ImageBrush(renderedBitmap);
//creating the material
DiffuseMaterial dataMeshMaterial = new DiffuseMaterial(imBrush);
this.dataMeshModel.Material = this.dataMeshMaterial;
}

WPF Clear Region on a Drawing Context?

So I am producing a transparent PNG using a DrawingContext and DrawingVisual.
Inside the DrawingContext, I drew a rectange.
I would now like to "cut out" a circle inside of the rectangle. How do I do this? I did not find any functions in drawing context to clear a region.
You can try using CombinedGeometry to combine 2 geometries (each time). It has GeometryCombineMode allowing you to specify some logic combination. In this case what you need is GeometryCombineMode.Xor. The intersection of the Rect and the Ellipse (cirlce) will be cut out. Here is the simple code demonstrating it:
DrawingVisual dv = new DrawingVisual();
using (var dc = dv.RenderOpen()) {
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
dc.DrawGeometry(Brushes.Blue, null, cb);
}
I hope you know how to render the DrawingVisual. You can use some RenderTargetBitmap to capture it into some kind of BitmapSource and then you have many ways to show this bitmap.
Here is the screenshot:
The Black region means the color is transparent.
In case you want to cut out some complex image (such as drawn text or image). You can turn the CombinedGeometry into some kind of OpacityMask (type of Brush). We can turn it into a DrawingBrush and this brush can be used as OpacityMask which can be passed into DrawingContext.PushOpacityMask method:
DrawingVisual dv = new DrawingVisual();
using (var dc = dv.RenderOpen()) {
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
var mask = new DrawingBrush(new GeometryDrawing(Brushes.Blue, null, cb));
dc.PushOpacityMask(mask);
dc.DrawImage(someImage, rect);
dc.DrawText(new FormattedText("Windows Presentation Foundation",
System.Globalization.CultureInfo.CurrentCulture,
System.Windows.FlowDirection.LeftToRight,
new Typeface("Lucida Bright"), 30, Brushes.Red){
MaxTextWidth = rect.Width,
MaxTextHeight = rect.Height,
TextAlignment = TextAlignment.Center
}, new Point());
}
Note that the rect should have the size of your whole drawing. Then positioning the hole and other drawn stuff will be exact as what you want.
Finally the DrawingVisual also has a useful property called Clip which is a Geometry. So you can prepare some CombinedGeometry and assign it to DrawingVisual.Clip property.
Suppose you already have your DrawingVisual (with some drawn stuff including text, images, ...). The following code will punch a hole through it:
//prepare the geometry, which can be considered as the puncher.
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
//punch the DrawingVisual
yourDrawingVisual.Clip = cb;

Silverlight Image Cropping

Does anybody knows how to image cropping in silverlight without any library.
I have Child window and inside the child window I havev a image and this image center one rectange is there so I can panning the image to the around the rectange and selecet the perticular part of the image and this selected part I want to crop.
Also I am using WriteableBitmap and try to Crop, this will not work if correct me if I am wrong.
sheetRectangle.Children is the Image.
foreach (ucPicRect item in sheetRectangle.Children)
{
WriteableBitmap obj = new WriteableBitmap(item.imgCell.Source as BitmapSource);
obj.Crop(0,0,400,400);
obj.Invalidate();
item.imgCell.Effect = dlgcwEditPhoto.imgEdit.Effect;
item.imgCell.Source = obj;// dlgcwEditPhoto.imgEdit.Source;
}
Thanks...!!!
you can use this utility function to crop your image
public static WriteableBitmap cropImage(Image image, double[] coordonnee)
{
Image cloneImage = new Image();
cloneImage.Source = image.Source;
RectangleGeometry myRec = new RectangleGeometry();
myRec.Rect = new Rect(coordonnee[0], coordonnee[1], coordonnee[2], coordonnee[3]);
cloneImage.Clip = myRec;
TranslateTransform t = new TranslateTransform();
t.X = -coordonnee[0];
t.Y = -coordonnee[1];
WriteableBitmap wb = new WriteableBitmap(cloneImage, t);
wb.Invalidate();
return wb;
}
good luck !!

Getting a DrawingContext for a wpf WriteableBitmap

Is there a way to get a DrawingContext (or something similar) for a WriteableBitmap? I.e. something to allow you to call simple DrawLine/DrawRectangle/etc kinds of methods, rather than manipulate the raw pixels directly.
I found sixlettervariables' solution the most workable one. However, there's a "drawingContext.Close()" missing. According to MSDN, "A DrawingContext must be closed before its content can be rendered".
The result is the following utility function:
public static BitmapSource CreateBitmap(
int width, int height, double dpi, Action<DrawingContext> render)
{
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
render(drawingContext);
}
RenderTargetBitmap bitmap = new RenderTargetBitmap(
width, height, dpi, dpi, PixelFormats.Default);
bitmap.Render(drawingVisual);
return bitmap;
}
This can then easily be used like this:
BitmapSource image = ImageTools.CreateBitmap(
320, 240, 96,
drawingContext =>
{
drawingContext.DrawRectangle(
Brushes.Green, null, new Rect(50, 50, 200, 100));
drawingContext.DrawLine(
new Pen(Brushes.White, 2), new Point(0, 0), new Point(320, 240));
});
If you don't mind using System.Drawing you could do something like:
var wb = new WriteableBitmap( width, height, dpi, dpi,
PixelFormats.Pbgra32, null );
wb.Lock();
var bmp = new System.Drawing.Bitmap( wb.PixelWidth, wb.PixelHeight,
wb.BackBufferStride,
PixelFormat.Format32bppPArgb,
wb.BackBuffer );
Graphics g = System.Drawing.Graphics.FromImage( bmp ); // Good old Graphics
g.DrawLine( ... ); // etc...
// ...and finally:
g.Dispose();
bmp.Dispose();
wb.AddDirtyRect( ... );
wb.Unlock();
I'm wondering the same thing, as currently I do something like:
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
//
// ... draw on the drawingContext
//
RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, dpi, dpi, PixelFormats.Default);
bmp.Render(drawingVisual);
image.Source = bmp;
}
I'm trying to use the WriteableBitmap to allow multithreaded access to the pixel buffer, which is currently not allowed with neither a DrawingContext nor a RenderTargetBitmap. Maybe some sort of WritePixels routine based off of what you've retrieved from the RenderTargetBitmap would work?
It appears the word is no.
For future reference, we plan to use a port of the Writeable Bitmap Extensions for WPF.
For a solution using purely existing code, any of the other suggestions mentioned below will work.
A different way to solve this problem is to use a RenderTargetBitmap as a backing store, just like in the WriteableBitmap example. Then you can create and issue WPF drawing commands to it whenever you want. For example:
// create the backing store in a constructor
var backingStore =
new RenderTargetBitmap(200,200,97,97,PixelFormats.Pbgra32);
myImage.Source = backingStore;
// whenever you want to update the bitmap, do:
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
{
// your drawing commands go here
drawingContext.DrawRectangle(
Brushes.Red, new Pen(),
new Rect(this.RenderSize));
}
Render(drawingContext);
drawingContext.Close();
backingStore.Render(drawingVisual);
If you want to redraw this RenderTargetBitmap every frame, you can catch the CompositionTarget.Rendering event, like this:
CompositionTarget.Rendering += MyRenderingHandler;

Resources