How can I convert a System.Windows.Media.ImageSource to a System.Drawing.Bitmap in C#?
its older OP, but still it can come handy for some other people, as it took some time to find cleaner solution without dll interop or clipboard hacks.
this worked for me, you can use pngencoder to cut the image size before saving to file or rtf stream
private System.Drawing.Image ImageWpfToGDI(System.Windows.Media.ImageSource image) {
MemoryStream ms = new MemoryStream();
var encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(image as System.Windows.Media.Imaging.BitmapSource));
encoder.Save(ms);
ms.Flush();
return System.Drawing.Image.FromStream(ms);
}
Please see HOW TO USE IMAGESOURCE (NO HANDLER) IN WINFORMS AS SYSTEM.DRAWING.BITMAP (HBITMAP):
How to easily convert WinForms
System.Drawing.Bitmap into WPF
ImageSource you learned from this
article. Today, I'll explain how to do
it contrary. Actually, all he have to
do is to extract handler from
BitmapSource, however, such approach
is not supported, thus the only thing
we can do is just copy pixels of
BitmapSource (or BitmapFrame) into
byte array and then copy them into the
pointer of HBitmap.
Related
I have here existing code that I need to fix because for unknown reasons, our .dll files were probably replaced.
I am having problems on using the image for OCR (Python Tesseract). Below is the how the code works:
ImageConverter ic = new ImageConverter();
byte[] imgArray = (byte[])ic.ConvertTo(image, typeof(byte[]));
I am passing the image to make it into byte[] then pass it on the API. Then the API converts the array to image:
public Bitmap ConvertToImage(byte[] arr)
{
using (var ms = new MemoryStream(arr))
{
return new Bitmap(ms);
}
}
As an example, when I use Bitmap img2 = ConvertToImage(imgArray);, it gives me the error
I only get the GDI error when I try to use the image from the converted array. But when I use the straight image file (open file dialog) there seems to be no problem.
I can't really change the code, so can anyone suggest a solution? Or what's the problem when I used the array to image file?
We have a system that provides images in 8-bit grayscale either tiff or jpg formats. However, the component we have to process the images expects image to be in 8-bit jpg format.
When I use .Net to save the tiff images as jpg it convets it to 24-bit image.
Is there a way, hopefully simple and fast, to convert 8-bit grayscale tiff images to equivalent jpg?
I tried and tried just to conclude that I'm sorry: .Net library's Bitmap class DOES NOT save JPEG as 8bpp even when explicitly stated and data is in grayscale.
(note: although stated in some places, JPEG format DOES support 8bpp).
At Convert an image to grayscale you may find code snipet to convert to grayscale any Image.
Using that code, I was able to save a 8bpp grayscale Image instance with '.jpeg' extension, but stating ImageFormat.Gif... that's a cheat...
My findings show as solution an entirely different approach.
The FreeImage library offers powerful APIs, including the feature needed to solve your problem.
It's home page is at http://freeimage.sourceforge.net/faq.html
But, I could not easily compile it in my Win2008 + VS 2010 machine.
One ought to sweat a lot to make it run on modern environments.
Some hints on how to accomplish that are found at http://www.sambeauvois.be/blog/2010/05/freeimage-and-x64-projects-yes-you-can/
Good luck!
Image img = Image.FromFile(filePathOriginal);
Bitmap bmp = ConvertTo8bpp(img);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
bmp.Save(filePathNew, jpgCodec, parameters);
bmp.Dispose();
img.Dispose();
...
private static Bitmap ConvertTo8bpp(Image img) {
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
}
return bmp;
}
In my code, I'm receiving WriteableBitmaps from a byte array (in turn from a Kinect) and I'd like to turn them into bitmaps for use with EmguCV. Currently this is the code I have:
// Copy the pixel data from the image to a temporary array
colorFrame.CopyPixelDataTo(this.colorPixels);
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * colorFrame.BytesPerPixel,
0);
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(colorBitmap));
MemoryStream ms = new MemoryStream();
encoder.Save(ms);
Bitmap b=new Bitmap(ms);
Image<Gray, Byte> img = new Image<Gray, Byte>(b);
img = img.ThresholdBinary(new Gray(200), new Gray(255));
I got the bottom half of the code from here.The code compiles and everything, but hangs when I'm trying to run the program (it's supposed to perform some operations on the image and then convert it back to a format that can be presented as an image.) Pausing my code and then using IntelliTrace in VS 2013, I get the following Exception at Image<Gray, Byte> img = new Image<Gray, Byte>(b); "A System.ArgumentException was thrown: URI formats are not supported." Using alternate code, from where I go directly from byte to bitmap gives me the same error. (Code can be found here.)
Anyone got tips on how to resolve this error, or alternate ways of casting to bitmap? I'm a newbie with C# & EmguCV and I'd greatly appreciate it.
Turns out all the code is fine. I'm not too sure on the technical details of the error, but the error is received when trying to write a Gray16 image in the WriteableBitmap (which is to be transformed into a Emgu Image.) Bgr565 or other formats are supported and I believe Gray16 wasn't fully implemented by MS. If doing a WinForms application, Format16bppGray will also give the same error.
I resolved to using a Gray Emgu image while writing the Bitmap as a Bgr555, which is a lot more noisy, but better than nothing.
I had the same issue. The exception with "URI formats are not supported" had nothing to do with the bitmap but with loading needed opencv dlls. I just copied the x86 and x64 folders including opencv_core290.dll and others to my executable directory.
I have a Bitmap with 16bpp. I want to convert that image in my ASP.NET side in a 8bpp image.
I tried a lot of options which I found in the internet but nothing works for me.
I also tried that way: C# Converting 32bpp image to 8bpp
But if I want to save the file, I get the following error:
Exception Details: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
Line 278: System.Drawing.Image img2 = Convert(bm_resize);//byteArrayToImage(gray);
Line 279:
Line 280: img2.Save(helper+"grey2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
Line 281: }
Line 282:
Is there any correct way for my problem?
Full Code:
System.Drawing.Image img2 = Convert(bm_resize);
img2.Save(path+"test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
public static System.Drawing.Image Convert(Bitmap oldbmp)
{
using (MemoryStream ms = new MemoryStream())
{
oldbmp.Save(ms, ImageFormat.Gif);
ms.Position = 0;
return System.Drawing.Image.FromStream(ms);
}
}
The problem is caused by disposing the memory stream before the image is saved.
I believe GDI+ requires the memory stream to persist while you are still working with an Image created from the memory stream.
See the Microsoft Support article.
I use a little helper function to create 1 bpp monochrome bitmaps in .NET. Check out this link, it also works great for 8 bpp
http://www.wischik.com/lu/programmer/1bpp.html
hope this could help!
AForge.Net has a good collection of free (under Lesser GPL License) routines for such changes and a lot more. Conversion of 16bpp to 8bpp is as simple as this.
I am binding an Image.Source property to the result of the property shown below.
public BitmapSource MyImageSource
{
get
{
BitmapSource source = null;
PngBitmapDecoder decoder;
using (var stream = new FileStream(#"C:\Temp\logo.png", FileMode.Open, FileAccess.Read, FileShare.Read))
{
decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
if (decoder.Frames != null && decoder.Frames.Count > 0)
source = decoder.Frames[0];
}
return source;
}
}
For some reason this is failing during the rendering of the image (Deep in the PresentationCore assembly). I am certain the image is not corrupt as I can successfully show the same image w/o the binding
<Image Name="FooImage" Source="/logo.png" />
I have to bind the image source in code because I will eventually be creating the image stream from a base64 string.
Anyone know if this is a bug w/ WPF? or am I doing something incorrectly?
The problem was the BitmapCacheOption option, changing to BitmapCacheOption.OnLoad works.
With BitmapCacheOption.None the BitmapSource isn’t decoded until the image is rendered, but the stream with the png in it is already disposed at that point. If you cache OnLoad, it’ll decode right away and cache the results, rather than trying to decode later when the stream no longer exists.
Also, have you tried just using a BitmapImage to load the image? It works fine with PNG, BMP, and JPEG.
It's also a specialized type of BitmapSource, so you could just replace your code in your property with this:
BitmapImage img = new BitmapImage(new Uri(#"C:\Temp\logo.png"));
return img;
Are you positive it's a PNG and not just a renamed Bitmap or Jpeg? If you create a new Bitmap image and then just rename it and change the file extension, this error is reproducible.
If I use a known PNG with your code, I don't get your issue, but a COM exception is thrown:
The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))
Can you try it out with a random PNG off the web and see if you get the same result?