Convert RenderTargetBitmap into System.Drawing.Image - c#

I have 3D WPF visual that I want to pass into an Excel cell (via clipboard buffer).
With "normal" BMP images it works but I do not know how to convert a RenderTargetBitmap.
My code looks like this:
System.Windows.Media.Imaging.RenderTargetBitmap renderTarget = myParent.GetViewPortAsImage(DiagramSizeX, DiagramSizeY);
System.Windows.Controls.Image myImage = new System.Windows.Controls.Image();
myImage.Source = renderTarget;
System.Drawing.Bitmap pg = new System.Drawing.Bitmap(DiagramSizeX, DiagramSizeY);
System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(pg);
gr.DrawImage(myImage, 0, 0);
System.Windows.Forms.Clipboard.SetDataObject(pg, true);
sheet.Paste(range);
My problem is that gr.DrawImage does not accept a System.Windows.Controls.Image or a System.Windows.Media.Imaging.RenderTargetBitmap; only a System.Drawing.Image.
How do I convert the Controls.Image.Imaging.RenderTargetBitmap into an Image, or are there any easier ways?

You can copy the pixels from the RenderTargetBitmap directly into the pixel buffer of a new Bitmap. Note that I've assumed that your RenderTargetBitmap uses PixelFormats.Pbrga32, as use of any other pixel format will throw an exception from the constructor of RenderTargetBitmap.
var bitmap = new Bitmap(renderTarget.PixelWidth, renderTarget.PixelHeight,
PixelFormat.Format32bppPArgb);
var bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
renderTarget.CopyPixels(Int32Rect.Empty, bitmapData.Scan0,
bitmapData.Stride*bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);

This was the solution I came up with
System.Windows.Media.Imaging.RenderTargetBitmap renderTarget = myParent.GetViewPortAsImage(DiagramSizeX, DiagramSizeY);
System.Windows.Media.Imaging.BitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
MemoryStream myStream = new MemoryStream();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(renderTarget));
encoder.Save(myStream);
//
System.Drawing.Bitmap pg = new System.Drawing.Bitmap(DiagramSizeX, DiagramSizeY);
System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(pg);
//
// Background
//
gr.FillRectangle(new System.Drawing.SolidBrush(BKGC), 0, 0, DiagramSizeX, DiagramSizeY);
//
gr.DrawImage(System.Drawing.Bitmap.FromStream(myStream), 0, 0);
System.Windows.Forms.Clipboard.SetDataObject(pg, true);
sheet.Paste(range);

Maybe I don't understand the question right, but you want to copy a RenderTargetBitmap to the clipboard, couldn't you just call SetImage ?:
Dim iRT As RenderTargetBitmap = makeImage() //this is what you do to get the rendertargetbitmap
If iRT Is Nothing Then Exit Sub
Clipboard.SetImage(iRT)

Related

How to convert a System.Drawing.Bitmap to a UnityEngine.Texture?

Texture2D tex = new Texture2D(200, 300, TextureFormat.RGB24, false);
Rectangle screenSize = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
Bitmap target = new Bitmap(screenSize.Width, screenSize.Height);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(target))
{
g.CopyFromScreen(0, 0, 0, 0, new Size(screenSize.Width, screenSize.Height));
}
m_Renderer.enabled = true;
m_Renderer.material.SetTexture("_MainTex", target);
I'm trying to set a bitmap as a texture in Unity, but I get the error
cannot convert from 'System.Drawing.Bitmap' to 'UnityEngine.Texture'
Any ideas how I can convert the bitmap to a texture?
You could try converting Bitmap to byte[] (as shown here). After that you can call Texture2D.LoadRawTextureData(byte[]) or Texture2D.LoadImage(byte[]).

C# - picturebox, graphics.DrawImage and picturebox.Image = null, why?

I'm trying to crop and resize an image in PictureBox1. My code:
//original image for eventually undo
undoImage = pictureBox1.BackgroundImage.Clone() as Image;
Bitmap sourceBitmap = new Bitmap(pictureBox1.BackgroundImage, pictureBox1.Width, pictureBox1.Height);
Graphics g = pictureBox2.CreateGraphics();
g.DrawImage(sourceBitmap, new Rectangle(0, 0, pictureBox2.Width, pictureBox2.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
And it working properly on two PictureBoxes.
But PictureBox2.Image,PictureBox2.BackgroundImage (and any other including ErrorImage...) = null.
I tried PictureBox.DrawToBitmap, and other, like g.GetHdc() found on google, but unsuccessful.
My question:
How do I properly copy the edited image from PictureBox2 to PictureBox1?
Trivial solution:
undoImage = pictureBox1.BackgroundImage.Clone() as Image;
Bitmap sourceBitmap = new Bitmap(pictureBox1.BackgroundImage, pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(sourceBitmap))
{
g.DrawImage(sourceBitmap, new Rectangle(0, 0, pictureBox2.Width,pictureBox2.Height), rectCropArea, GraphicsUnit.Pixel);
}
pictureBox1.BackgroundImage = sourceBitmap;

Large image update in WPF is delayed for real time monitoring

I am getting Sequence of images from USB and with each image grabbed I convert grabbed result to System.Drawing.Bitmap and after that I convert it to System.Windows.Mesia.Imging.BitmapImage to be able to assign it to Imagesource and finally update UI in dispatcher thread, all this process takes time and it doesn't go live, the sample codes of the camera company (Basler) has used C# and directly assigns System.Drawing.Bitmap to picture box and can show live view without delay.
What is the best solution to handle it ? it worth mentioning that with 2048*2000 pixel size the frame rate is almost 50 fps
PixelDataConverter converter = new PixelDataConverter();
Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr ptrBmp = bmpData.Scan0;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
bitmap.UnlockBits(bmpData);
BitmapImage bitmapimage = new BitmapImage();
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
}
Dispatcher.Invoke(new Action(() =>
{
imgMain.Source = bitmapimage;
}));
And this is the sample code for c# by company :
Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
// Lock the bits of the bitmap.
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
// Place the pointer to the buffer of the bitmap.
converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr ptrBmp = bmpData.Scan0;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult); //Exception handling TODO
bitmap.UnlockBits(bmpData);
// Assign a temporary variable to dispose the bitmap after assigning the new bitmap to the display control.
Bitmap bitmapOld = pictureBox.Image as Bitmap;
// Provide the display control with the new bitmap. This action automatically updates the display.
pictureBox.Image = bitmap;
if (bitmapOld != null)
{
// Dispose the bitmap.
bitmapOld.Dispose();
}
}
enter code here
Use Dispatcher.BeginInvoke instead of Dispatcher.Invoke(...to set the image asynchronous.
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
imgMain.Source = bitmapimage;
}));

How to properly use Image as ToolTip?

I have a BitmapSource 1690x214 (taken from an EMF file using this code), and I want to use this image as ToolTip. This is the image displayed using Paint:
So i wrote this code:
BitmapSource bmp = myBitmapSource; // "Dk01Light.EMF"
Image img = new Image()
{
Source = bmp,
Width = bmp.Width,
Height = bmp.Height,
Stretch = Stretch.Uniform,
};
myTooltip = img;
And this is the result:
As you can see, the right and bottom margin are completly different. Why? How can i fix this problem?
It seems like a DPI issue. First try removing the Width and Height from your Image initializer. It should also-size to fit its content.
You can also try replacing the code you linked to with the following to make sure the image is being produced properly:
using (System.Drawing.Imaging.Metafile emf = new System.Drawing.Imaging.Metafile(path))
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(emf.Width, emf.Height))
{
bmp.SetResolution(emf.HorizontalResolution, emf.VerticalResolution);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
{
g.DrawImage(emf,
new Rectangle(0, 0, emf.Width, emf.Height),
new Rectangle(0, 0, emf.Width, emf.Height),
GraphicsUnit.Pixel
);
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
}

Get BitmapSource From Image Control

why the following code is returning null for btmSrc ?
DrawingImage drawingElement =(DrawingImage)System.Windows.Application.Current.TryFindResource(name);
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = drawingElement as ImageSource;
BitmapSource btmSrc = image.Source as BitmapSource;
Simplifying your code :
DrawingImage drawingElement = (DrawingImage)System.Windows.Application.Current.TryFindResource(name);
BitmapSource btmSrc = drawingElement as BitmapSource;
As DrawingImage doesn't inherit from BitmapSource, the result will be null.
I don't have a DrawingImage to test (so take this as a pseudocode not as a copy-paste solution) but the conversion code should look something like this :
// Create a visual from a drawing
DrawingVisual drawingVisual = new DrawingVisual();
drawingVisual.Drawing.Children.Add(drawingImage.Drawing);
// Render it to a WPF bitmap
var renderTargetBitmap = new RenderTargetBitmap(
drawingVisual.Drawing.Bounds.Right,
drawingVisual.Drawing.Bounds.Bottom, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
// Create a bitmap with the correct size
Bitmap bmp = new Bitmap(renderTargetBitmap.PixelWidth,
renderTargetBitmap.PixelHeight, PixelFormat.Format32bppPArgb);
BitmapData data = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size),
ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
renderTargetBitmap.CopyPixels(Int32Rect.Empty, data.Scan0,
data.Height * data.Stride, data.Stride);
bmp.UnlockBits(data);
The last part being taken from Is there a good way to convert between BitmapSource and Bitmap?

Categories