Maybe it's a stupid question, but I have some problems with finding the proper answer:S
How to get frames as Bitmap's or Image's (or something similar) from DrawingGroup? I don't actually know how to bite it. I tried to look for it in the Internet, but had problems with finding something useful.
If you need an image to be used as the Source of an Image control, you could simply put the drawing into a DrawingImage:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
image.Source = drawingImage;
If the question is about creating a BitmapSource (i.e. something that can be encoded by a BitmapEncoder via a BitmapFrame), there is no direct conversion. You have to put the image into an intermediate Image control and render that control into a RenderTargetBitmap, which is a BitmapSource:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
var image = new Image { Source = drawingImage };
var bitmap = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
bitmap.Render(image);
Related
I am new to C# and to WPF, and I could be looking at this completely wrong. I have a JPEG byte array as a source. I cannot change this. I need to get the array, perform some calculations and draw rectangles in areas of the JPEG. I then write it to an Image XAML control.
I get the JPEG and I can convert it into an ImageSource and display it to an ImageControl. I can't find a way to get the drawing context from the ImageSource. I use ImageSourceConverter to read in the JPEG array and this class returns an ImageSource instance, duh!.
ImageSource mImage = (ImageSource)mConverter.ConvertFrom(mImageBuffer);
ImageSource does not have a drawing context property.
What it seems like I need is a DrawingImage, it is derived from ImageSource and has a drawing context property.
How can I use a DrawingImage instead of the ImageSource.
I looked at the ImageDrawing class, it has an ImageSource property. This class doesn't have a drawing context.
I am currently looking into the Visual class, and help where to look would be appreciated.
Edit:
Thanks #nefarious for pointing me in the right direction. I ended with the following:
ImageSource mImage = (ImageSource)mConverter.ConvertFrom(mImageBuffer);
BitmapSource bImage = mImage as BitmapSource;
// Draw a Rectangle
DrawingVisual dVisual = new DrawingVisual();
using (DrawingContext dc = dVisual.RenderOpen())
{
dc.DrawImage(bImage, new Rect(0, 0, bImage.PixelWidth, bImage.PixelHeight));
dc.DrawRectangle(Brushes.Green, null, new Rect(20, 20, 150, 100));
}
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(640,480,96,96, PixelFormats.Default);
targetBitmap.Render(dVisual);
WriteableBitmap wBitmap = new WriteableBitmap(targetBitmap);
image.Source = wBitmap;
Have you looked at using Visuals, I don't know how efficient they are but it seems that you will be unable to copy the source into an ImageSource and draw directly into it.
Create a DrawingVisual and draw the ImageSource and the Rectangles into the drawing context of the drawing visual.
Then use WriteableBitmap to show it in the image;
Ok so here's how this works:
camera sends me an image as a writeable bitmap
client.WhenMasterFrameCaptured().ObserveOn(SynchronizationContext.Current).Subscribe(frame => UpdateMasterCameraPreview(frame));
I set that pointer to an image source(wpf Image control) in the method that this is subscribed to
if (cameraOneBitmap != null)
{
frame.Image.CopyTo(cameraOneBitmap);
}
else
{
cameraOneBitmap = frame.Image.ToWriteableBitmap();
}
cameraOneBitmap.Lock();
cameraOneBitmap.AddDirtyRect(new Int32Rect(0, 0, cameraOneBitmap.PixelWidth, cameraOneBitmap.PixelHeight));
cameraOneBitmap.Unlock();
cameraOneImage.Source = cameraOneBitmap;
The Problem: The method feeds me a bitmap that isn't the correct angle and i have no way of changing that. I must rotate it. I'm currently using a render transform in xaml. the problem is it shapes the image all weird in certain window sizes it hangs over the grid into the bottom of the window so i don't want to use that. I've tried using writeablebitmapex library but it creates a new bitmap and that gives me an out of memory exception in about 10 seconds... Is there a way to rotate this bitmap with out have to make a new one every time? Somehow the render transform does it without giving me problems. I was doing this to set the source but it still gives me an exception because it makes a new one.
public static RenderTargetBitmap RotateImage(double angle, WriteableBitmap sourceBitmap)
{
TransformedBitmap tb = new TransformedBitmap(sourceBitmap, new RotateTransform(angle));
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(tb, new Rect(0, 0, tb.PixelWidth, tb.PixelHeight));
//drawingContext.PushTransform(new RotateTransform(270, .5, .5));
drawingContext.Close();
System.Windows.Media.Imaging.RenderTargetBitmap bmp = new System.Windows.Media.Imaging.RenderTargetBitmap(tb.PixelWidth, tb.PixelHeight, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
return bmp;
}
I am currently converting a Silverlight application into WPF. In my silverlight application I have the code
WriteableBitmap sceneBitmap = new WriteableBitmap(scene, new TranslateTransform() { Y = 10 });
WriteableBitmap newone = TimelineMainHelper.CropImage(sceneBitmap, 0, 0, sceneBitmap.PixelWidth, sceneBitmap.PixelHeight - 25);
newone.Invalidate();
img.Source = newone;
Where scene is a control.
When putting this into WPF there are no overloads for the writeablebitmap class which take UIElement and Transform as the parameters. Firstly I was wondering why this is? and secondly I was wondering if there was a way getting a control to a writeablebitmap
Instead you will want to use RenderTargetBitmap and CroppedBitmap I believe:
RenderTargetBitmap rtb = new RenderTargetBitmap((int)scene.ActualWidth, (int)scene.ActualHeight, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
rtb.Render(this.sceneBitmap);
CroppedBitmap crop = new CroppedBitmap(sceneBitmap, new Int32Rect(0, 0, (int)sceneBitmap.ActualWidth, (int)sceneBitmap.ActualHeight));
Then you can do something like:
System.Windows.Controls.Image img = new Image();
img.Source = crop;
And go from there.
Disclaimer:
You may need to use different overloads and what not to do exactly what you wish. I just took a shot guessing what parameters to pass given your snippet.
This thing has been driving me crazy.
I have a Visiblox chart. which I'm currently exporting as a PNG using the following code:
var chart = this.CalibrationChartVisibility == Visibility.Visible ? this.calibrationChart : this.residualChart;
var transform = chart.LayoutTransform;
chart.LayoutTransform = null;
var width = (int)chart.ActualWidth;
var height = (int)chart.ActualHeight;
var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
rtb.Render(chart);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
var stream = new MemoryStream();
encoder.Save(stream);
stream.Position = 0;
chart.LayoutTransform = transform;
return stream.ToArray();
and I get something like this:
But now I need to also need to export it as a JPEG. I thought it would be simple, just change the encoder but this is what I get:
I've tried this:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/31ac62d4-399b-4f2e-a9b9-749efe7528b6/rendertargetbitmap-to-file-problem?forum=wpf
and this:
http://www.grumpydev.com/2009/01/03/taking-wpf-screenshots/
and this:
Get a bitmap image from a Control view
and ervey sugestion on this post:
How to save image using JpegBitmapEncoder
or this one:
saving WPF InkCanvas to a JPG - image is getting cropped
and everything else which crossed my mind, but the outcome is still the same.
There must be something I'm overlooking but I have no idea what it is.
To sum up comments this seems to be a background issue as PNG, attached to this question, has everything transparent apart from chart lines and since JPEG does not support transparency all that is transparent will be black.
Simpliest solution would be to set background of chart to some color
Disclaimer: I provided this answer for the System.Drawing.Image from ImageSource in Resources question and was going to vote to close this question as a duplicate of the other, but couldn't because the question author didn't accept the answer.
In WPF, every UI element extends the Visual Class which Provides rendering support in WPF. There is also a RenderTargetBitmap Class that has a Render Method that takes a Visual object as an input parameter. So you could set your ImageSource as the Source property of an Image and simply render the Image to a Bitmap image:
Image yourImageObject = new Image();
yourImageObject.Source = yourImageSource;
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render(yourImageObject);
// Save to .png file
PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream stream = File.Create(filepath))
{
pngBitmapEncoder.Save(stream);
}
As this is well documented on the internet, I won't bother to repeat the whole story here. To find out the full story, please see the How to Render Bitmap or to Print a Visual in WPF page from the Dot NET Tricks website, which will also help you with your printing requirement.
UPDATE >>>
Ok, so most of this applies to you in just the same way, except that you'd want to use a JpegBitmapEncoder object instead. This example from the linked page shows another way to save a JPEG image:
int width = 128;
int height = width;
int stride = width / 8;
byte[] pixels = new byte[height * stride];
// Define the image palette
BitmapPalette myPalette = BitmapPalettes.Halftone256;
// Creates a new empty image with the pre-defined palette
BitmapSource image = BitmapSource.Create(
width,
height,
96,
96,
PixelFormats.Indexed1,
myPalette,
pixels,
stride);
FileStream stream = new FileStream("new.jpg", FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();
encoder.FlipHorizontal = true;
encoder.FlipVertical = false;
encoder.QualityLevel = 30;
encoder.Rotation = Rotation.Rotate90;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);
Please let me know if you have any problems.
I'm writing an application for the surface that requires displaying data in a table (i.e. DataGrid). This is great, except the table captures the touch interactions for the ScatterViewItem control (basically a panel that can be spun, shrunk, and moved by the user). This prevents the user from easily manipulating the ScatterViewItem.
To solve this problem, I thought it would be easy to draw the control to an image and just put that up. It seems I was wrong. Here are all my attempts:
http://pastie.org/private/gfkkv9f6apgrqi1ucspwpa (no need to read this, unless you think it will be useful. That's why it's in pastie and not on here)
I'm putting the DataGrid inside of another Grid, because otherwise it won't measure properly:
Grid g = new Grid();
g.Children.Add(dataTable);
SurfaceScrollViewer viewer = new SurfaceScrollViewer();
viewer.Content = Utility.SaveWPFControlAsImage(g);
If we change that last line to
viewer.Content = g;
We get a good table:
If we don't, we get:
SaveWPFControlAsImage is as follows:
public static System.Windows.Controls.Image SaveWPFControlAsImage(FrameworkElement e)
{
e.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
RenderTargetBitmap targetBitmap =
new RenderTargetBitmap((int)e.DesiredSize.Width,
(int)e.DesiredSize.Height,
96d, 96d,
PixelFormats.Default);
targetBitmap.Render(e);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
MemoryStream stream = new MemoryStream();
encoder.Save(stream);
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(stream.ToArray());
bmp.EndInit();
return new System.Windows.Controls.Image()
{
Source = bmp,
};
}
So maybe I'm just not rendering it right, or, maybe, I'm just going about this at the wrong angle...
In WPF you have a VisualBrush which allows you to capture a live preview of a given control. Also if you don't want any input of a given control, you can always set IsHitTestVisible="False".