I want to save my canvas to image. It works but background color is black. How I must add to change the color?
I use this code:
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d,
PixelFormats.Pbgra32);
renderBitmap.Render(surface);
// Create a file stream for saving image
using (FileStream outStream = new FileStream(filename, FileMode.Create))
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
}
Try this
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
// Create a render bitmap and push the surface to it
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d,
PixelFormats.Pbgra32);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
VisualBrush visualBrush = new VisualBrush(surface);
drawingContext.DrawRectangle(visualBrush, null,
new Rect(new Point(), new Size(size.Width, size.Height)));
}
renderBitmap.Render(drawingVisual);
// Create a file stream for saving image
using (FileStream outStream = new FileStream(filename, FileMode.Create))
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
}
Try PixelFormats.Default or PixelFormats.Bgra32 or PixelFormats.Rgb24 instead of PixelFormats.Pbgra32.
The P stands for pre-multiplied - the assumption is that each channel is pre-multiplied by alpha.
MSDN reference
Related
I am saving the rendered image using render target bitmap, and it is saved properly in the given size, but when I set background to the grid in which image is placed, I am getting different output. Can any one explain this behavior?
<Grid x:Name="grid1" Grid.Row="0" Background="Red">
<Image x:Name="image1" Source="Images/butterfly.jpg" >
</Image>
</Grid>
Code behind
RenderTargetBitmap result = GetImage(this.grid1);
Stream imageStream = new MemoryStream();
SaveAsPng(result, imageStream);
public static RenderTargetBitmap GetImage(Grid view)
{
Size size = new Size(1122, 750);
if (size.IsEmpty)
return null;
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(view), null, new Rect(new Point(), size));
context.Close();
}
result.Render(drawingvisual);
return result;
}
public static void SaveAsPng(RenderTargetBitmap src, Stream outputStream)
{
var saveFileDialog = new SaveFileDialog()
{
Filter = "Image Files (*.bmp, *.png, *.jpg)|*.bmp;*.png;*.jpg"
};
if (saveFileDialog.ShowDialog() == true)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
using (FileStream stream = new FileStream(saveFileDialog.FileName, FileMode.Create))
encoder.Save(stream);
}
}
Without Background
With Background
In order to retain the original element dimensions in the DrawingVisual, you should set the VisualBrush's Stretch to None. If necessary, you can also get precise control of the placement of the visual by setting the VisualBrush's Viewport, Viewbox, AlignmentX and AlignmentY properties.
Also consider passing the result size as an argument to your GetImage method, and use the most general type for the view argument:
public static BitmapSource GetImage(Visual view, Size size)
{
var bitmap = new RenderTargetBitmap(
(int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
var visualBrush = new VisualBrush
{
Visual = view,
Stretch = Stretch.None
};
var drawingvisual = new DrawingVisual();
using (var context = drawingvisual.RenderOpen())
{
context.DrawRectangle(visualBrush, null, new Rect(size));
}
bitmap.Render(drawingvisual);
return bitmap;
}
Also make the SaveAsPng method more flexible by changing the argument type. The outputStream argument isn't used at all, so remove it.
public static void SaveAsPng(BitmapSource src)
Then call both methods like this:
var result = GetImage(grid1, new Size(1122, 750));
SaveAsPng(result);
I have a WPF application using InkCanvas. When I render the bitmap, save to a memory stream, write the resulting bytes to a file, and then open that file in paint, the image is mangled. Any idea what I may be doing wrong here? Tried several solutions found here on SO and also on codeproject. It's pretty clear that it's capturing part of the InkCanvas but the majority of it is black (I assume null bytes).
EDIT: also tried with/without margin. Here are the other links I've tried:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ef71237c-5dfb-4d6c-a402-e8cb02b74e99/how-to-convert-inkcanvas-strokes-to-a-bitmap-or-byte-array?forum=wpf
Converting InkCanvas Strokes to a Byte Array and back again
InkCanvas Load/Save operations
http://www.centrolutions.com/Blog/post/2008/12/09/Convert-WPF-InkCanvas-to-Bitmap.aspx
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ba4dc89f-0169-43a9-8374-68e1fb34a222/saving-inkcanvas-as-image?forum=wpf
I need the resultant file to be a bitmap/PNG so it can be viewed on another machine.
private byte[] ConvertInkCanvasToByteArray()
{
int margin = (int)this.icSignature.Margin.Left;
int width = (int)this.icSignature.ActualWidth - margin;
int height = (int)this.icSignature.ActualHeight - margin;
RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Default);
rtb.Render(icSignature);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
byte[] bitmapBytes;
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
ms.Position = 0;
bitmapBytes = ms.ToArray();
}
return bitmapBytes;
}
From the InkCanvas:
And then mangled:
To avoid any problem with the InkCanvas' Margin, you could draw it into an intermediate DrawingVisual:
private byte[] ConvertInkCanvasToByteArray()
{
var rect = new Rect(icSignature.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(icSignature), null, rect);
}
var rtb = new RenderTargetBitmap(
(int)rect.Width, (int)rect.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(visual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
return stream.ToArray();
}
}
I want to save an Image as an Jpeg with JpegBitmapEncoder but setting the QualityLevel has no effect? The resulting jpeg is always the same size (~4mb for 2200x1500px).
RenderTargetBitmap rtb = new RenderTargetBitmap(collage.Breite, collage.Hoehe, dpi, dpi, System.Windows.Media.PixelFormats.Default);
canvas.UpdateLayout();
rtb.Render(canvas);
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.QualityLevel = 35; // no effect, Image to big
jpgEncoder.Frames.Add(BitmapFrame.Create(rtb));
using (var fs = System.IO.File.OpenWrite(myfilename, variables)))
{
jpgEncoder.Save(fs);
fs.Close();
fs.Dispose();
}
I changed it to:
var fs = new FileStream(myfilename, variables), FileMode.Create);
jpgEncoder.Save(fs);
fs.Close();
I'm using Xceed WPF Toolkit (Community Edition) DataGridControl, and I would like to create a bitmap from the control (either to put on the clipboard or save to a png).
I have tried using a RenderBitmapTarget, but it will only copy the control as it is rendered on the screen (my grid is bigger than the screen).
My RenderBitmapTarget code looks like this:
RenderTargetBitmap rtb = new RenderTargetBitmap((int)control.ActualWidth, (int)control.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(control);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream stream = new MemoryStream();
png.Save(stream);
Image image = Image.FromStream(stream);
I've tried specifying a larger size (both in the RenderTargetBitmap constructor, and specifying new width/height for the control, but both just yielded the same image on a larger canvas.
Any thoughts?
Ok, I figured it out....
The final key was to disable delayed loading on the DataGridControl.View...here is my final code:
XAML:
<xcdg:DataGridControl x:Name="CEGrid">
<xcdg:DataGridControl.View>
<xcdg:TableflowView IsDeferredLoadingEnabled="False"/>
</xcdg:DataGridControl.View>
</xcdg:DataGridControl>
C# code-behind:
double tempWidth = CEGrid.ActualWidth;
double tempHeight = CEGrid.ActualHeight;
CEGrid.Width = double.NaN;
CEGrid.Height = double.NaN;
CEGrid.UpdateLayout();
RenderTargetBitmap rtb = new RenderTargetBitmap((int)CEGrid.ActualWidth, (int)CEGrid.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(CEGrid);
PngBitmapEncoder pbe = new PngBitmapEncoder();
pbe.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream stream = new MemoryStream();
pbe.Save(stream);
System.Drawing.Bitmap image = (System.Drawing.Bitmap)System.Drawing.Image.FromStream(stream);
CEGrid.Width = tempWidth;
CEGrid.Height = tempHeight;
I have a UniformGrid containing all my video thumbnails taken (they are all System.Windows.Control.Image). My goal here is to save a jpg of all the thumbnails after I click a button. Is there a way to grab a bitmap image or something from a UbiformGrid?
I am using C# with WPF.
Edit: like a screenshot. But I don't want to window border, only the grid content.
Edit2: I finally found a solution. Thanks for the help.
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)ThumbnailPanel.Width,
(int)ThumbnailPanel.Height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(ThumbnailPanel);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(ThumbnailPanel.Width, ThumbnailPanel.Height)));
}
renderTarget.Render(drawingVisual);
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.QualityLevel = 80;
jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
Byte[] _imageArray;
using (MemoryStream outputStream = new MemoryStream())
{
jpgEncoder.Save(outputStream);
_imageArray = outputStream.ToArray();
}
FileStream fileStream = new FileStream(#"myThumbnails.jpg", FileMode.Create, FileAccess.ReadWrite);
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
binaryWriter.Write(_imageArray);
binaryWriter.Close();
Sure, just iterate through your collection of images with for or foreach and use the Image.GetThumbnailImage method from the System.Drawing namespace to create thumbnails... it's that simple.
For example:
foreach (var img in myImages)
{
var thumb = image.GetThumbnailImage(thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero);
//Do something with the thumbnail
thumb.Save(output)
}