I want to set a background image for my form/window like this guy but instead of an image file on disk I've got a System.Drawing.Bitmap in memory.
I need to do something like this:
this.Background = new ImageBrush(new BitmapImage(bmp));
Except BitmapImage won't take a Bitmap, nor will ImageBrush and I'm not sure if any of the others will. There's one called BitmapCacheBrush but I don't know what that does.
Nevermind, I figured it out.
public static Brush CreateBrushFromBitmap(Bitmap bmp)
{
return new ImageBrush(Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()));
}
credit
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;
I'm using a thread to get an image from a website and shoot it back to the parent form (WPF) to display. I ran into an issue and have managed to debug it to this example:
public void Watch()
{
while (true)
{
Bitmap bmp = new Bitmap(1, 1);
BitmapImage bmpImg = new BitmapImage();
this.SetImage(bmp, bmpImg);
}
}
public delegate void SetImageCallback(Bitmap bmp, BitmapImage bmpImg);
private void SetImage(Bitmap bmp, BitmapImage bmpImg)
{
if (!this.imgVideo.Dispatcher.CheckAccess())
{
SetImageCallback del = new SetImageCallback(SetImage);
this.Dispatcher.Invoke(del, bmp, bmpImg);
}
else
{
Bitmap bitmap = bmp;
BitmapImage bitmapImage = bmpImg;
}
}
Keep in mind that Watch() runs on its own thread. If I use the bitmap object (which I can use with PictureBox in Window Forms) everything works great. That is, debugging this code, when I get to the line
Bitmap bitmap = bmp;
And inspect the variable bmp, everything is great and works as expected. HOWEVER, when I get to the next line
BitmapImage bitmapImage = bmpImg;
And inpsect the variable bmpImage, I get a ton of System.InvalidOperationException's. When this is in practice and gets assigned to a WPF Image object, it says that "The calling thread cannot access this object because a different thread owns it." Why am I running into this issue with WPF BitmapImages (which are required to set an ImageSource) but NOT in Windows Forms Bitmap objects (which can be used to set a PictureBox)? How do I fix this in WPF?
Most objects in WPF are of this category: they cannot be shared between different threads. However certain low-level resources such as brushes and bitmaps are derived from a special class called Freezable that if frozen can be shared between different threads. Of course once an object is frozen is can no longer be modified in any way. To freeze a freezable object simply call Freeze and this will prevent cross-thread exceptions.
Instead of
if (!this.imgVideo.Dispatcher.CheckAccess())
{
SetImageCallback del = new SetImageCallback(SetImage);
this.Dispatcher.Invoke(del, bmp, bmpImg);
}
try using :
if (!App.Current.Dispatcher.CheckAccess())
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action<CustomObject>(SetImage),CustomeObjectInstance );
Here Cutom object will be a wrapper class wrapping
Bitmap bmp, BitmapImage bmpImg
Obviously, your SetImage signature will change to
SetImage(CutomObject custObj)
I have not tested the code but this may solve the issue.
Let us know if this works so that some poor soul can be benefitted from this post.
All the best!
Sid
I write a method which reduce the color depth (GIF convertion) and set the resolution to 600pixel from a Bitmap.
The color depth convertion works fine but the resolution set is not working.
<script runat="server" language="C#">
public static void Convert(Bitmap oldbmp, String path)
{
System.Drawing.Bitmap bm8Bit;
using (MemoryStream ms = new MemoryStream())
{
oldbmp.Save(ms, ImageFormat.Gif);
ms.Position = 0;
bm8Bit = (System.Drawing.Bitmap) System.Drawing.Image.FromStream(ms);
bm8Bit.SetResolution(600, 600);
bm8Bit.Save(path, System.Drawing.Imaging.ImageFormat.Bmp);
return;
}
}
</script>
I think you can set resolution only on new Bitmap, that wan't saved before, so if you have exiting bitmap, you need to copy it to new Bitmap instance:
Bitmap imgCopy = new Bitmap(img);
imgCopy.SetResolution(600.0f,600.0f);
Read here: http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.setresolution.aspx
Use this method to set the desired resolution on a newly created bitmap. Changing the resolution of the image does not change its physical size.
Hey its always good to try to write our own solution but their is a library available which is easy to implement and works really great
you might want to use it, you can download it from here and it have very good documentation too.
http://imageresizing.net/download
i want to change in runtime the Background property and i have to set an ImageBrush for it.
I have added some images as Resources on my project, and now i can use them as System.Drawing.Bitmap.
How can i convert System.Drawing.Bitmap into ImageBrush ?
If you are using the codebehind to set it, you can do it like this:
BitmapImage img;
// get bitmapimage from resources and assign to img
ImageBrush brush = new ImageBrush();
brush.ImageSource = img;
myControl.Background = brush;
If you are using databinding you'd need to implement a ValueConverter
From How to create ImageBrush from System.Drawing.Image in WPF?:
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
bitmap.Dispose();
var brush = new ImageBrush(bitmapSource);
"This solution, however, doesnt free the memory of the handle. For information on how to remove the memory leak see WPF CreateBitmapSourceFromHBitmap() memory leak"
I have a Graphics object that I've drawn on the screen and I need to save it to a png or bmp file. Graphics doesn't seem to support that directly, but it must be possible somehow.
What are the steps?
Here is the code:
Bitmap bitmap = new Bitmap(Convert.ToInt32(1024), Convert.ToInt32(1024), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bitmap);
// Add drawing commands here
g.Clear(Color.Green);
bitmap.Save(#"C:\Users\johndoe\test.png", ImageFormat.Png);
If your Graphics is on a form, you can use this:
private void DrawImagePointF(PaintEventArgs e)
{
... Above code goes here ...
e.Graphics.DrawImage(bitmap, 0, 0);
}
In addition, to save on a web page, you could use this:
MemoryStream memoryStream = new MemoryStream();
bitmap.Save(memoryStream, ImageFormat.Png);
var pngData = memoryStream.ToArray();
<img src="data:image/png;base64,#(Convert.ToBase64String(pngData))"/>
Graphics objects are a GDI+ drawing surface. They must have an attached device context to draw on ie either a form or an image.
Copy it to a Bitmap and then call the bitmap's Save method.
Note that if you're literally drawing to the screen (by grabbing the screen's device context), then the only way to save what you just drew to the screen is to reverse the process by drawing from the screen to a Bitmap. This is possible, but it would obviously be a lot easier to just draw directly to a Bitmap (using the same code you use to draw to the screen).
Try this, works fine for me...
private void SaveControlImage(Control ctr)
{
try
{
var imagePath = #"C:\Image.png";
Image bmp = new Bitmap(ctr.Width, ctr.Height);
var gg = Graphics.FromImage(bmp);
var rect = ctr.RectangleToScreen(ctr.ClientRectangle);
gg.CopyFromScreen(rect.Location, Point.Empty, ctr.Size);
bmp.Save(imagePath);
Process.Start(imagePath);
}
catch (Exception)
{
//
}
}
Graphics graph = CreateGraphics();
Bitmap bmpPicture = new Bitmap("filename.bmp");
graph.DrawImage(bmpPicture, width, height);
You are likely drawing either to an image or on a control. If on image use
Image.Save("myfile.png",ImageFormat.Png)
If drawing on control use Control.DrawToBitmap() and then save the returned image as above.
Thanks for the correction - I wasn't aware you can draw directly to the screen.