I have a button and an image named as image1 in my wpf app. I want add image source of the image1 from a file icon of a location or file path. Here is my code:
using System.Windows;
using System.Windows.Media.Imaging;
using System.IO;
using System.Drawing;
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Icon ico = System.Drawing.Icon.ExtractAssociatedIcon(#"C:\WINDOWS\system32\notepad.exe");
image1.Source = ico.ToBitmap();
}
}
}
And the error is saying
Cannot implicitly convert type 'System.Drawing.Bitmap' to
'System.Windows.Media.ImageSource'
How to solve this problem?
The solution suggested by Farhan Anam will work, but it's not ideal: the icon is loaded from a file, converted to a bitmap, saved to a stream and reloaded from the stream. That's quite inefficient.
Another approach is to use the System.Windows.Interop.Imaging class and its CreateBitmapSourceFromHIcon method:
private ImageSource IconToImageSource(System.Drawing.Icon icon)
{
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
new Int32Rect(0, 0, icon.Width, icon.Height),
BitmapSizeOptions.FromEmptyOptions());
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
using (var ico = System.Drawing.Icon.ExtractAssociatedIcon(#"C:\WINDOWS\system32\notepad.exe"))
{
image1.Source = IconToImageSource(ico);
}
}
Note the using block to dispose the original icon after you converted it. Not doing this will cause handle leaks.
The error you get is because you try to assign a bitmap as the source of an image. To rectify that, use this function:
BitmapImage BitmapToImageSource(Bitmap bitmap)
{
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
return bitmapimage;
}
}
like this:
image1.Source = BitmapToImageSource(ico.ToBitmap());
Related
I'm c# begginer.I used wpf image control to show image from my camera. It's work normally in winform pictureBox but not in WPF image control. It's all blank! And I'm sure the data stream exist.
The icImagingControl1 is the control of my camera SDK.
It's can return image data in many forms. Like Intptr,Byte,Bitmap.
I want load data in image control from memory.
And the function would be triggered everytime the camera snap.
Here is my code.
private void icImagingControl1_ImageAvailable(object sender, XXX.Imaging.ICImagingControl.ImageAvailableEventArgs e)
{
XXX.Imaging.ImageBuffer CurrentBuffer = null;
CurrentBuffer = icImagingControl1.ImageBuffers[e.bufferIndex];
try
{
using (MemoryStream memory = new MemoryStream())
{
CurrentBuffer.Bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
image1.Source = bitmapImage;
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
Hope anyone could help me.
I'm pretty new to displaying images in WPF forms, and i'm having trouble when it comes to converting and assigning an Image source for my GUI.
System.Drawing.Image testImg = ImageServer.DownloadCharacterImage(charID, ImageServer.ImageSize.Size128px);
byte[] barr = imgToByteArray(testImg);
CharImage.Source = ByteToImage(barr);
public byte[] imgToByteArray(System.Drawing.Image testImg)
{
using (MemoryStream ms = new MemoryStream())
{
testImg.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
}
public System.Drawing.Image ByteToImage(byte[] barr)
{
MemoryStream ms = new MemoryStream(barr);
System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms);
return returnImage;
}
So i take in an image (JPEG) from the EVE Online C# API Library and then try to convert it to a byte array and back to a proper image. However i always get this error: "Cannot Implicitly convert type 'System.Drawing.Image' to 'System.Windows.Media.ImageSource'" I'm completely dumbfounded on how to solve this.
One possible solution is to save the image files (for example, .jpg) as WPF embedded resource and then use the following code snippet to get BitmapImage:
Listing 1. Get BitmapImage from EmbeddedResource
private string GetAssemblyName()
{
try { return Assembly.GetExecutingAssembly().FullName.Split(',')[0]; }
catch { throw; }
}
private BitmapImage GetEmbeddedBitmapImage(string pathImageFileEmbedded)
{
try
{
// compose full path to embedded resource file
string _fullPath = String.Concat(String.Concat(GetAssemblyName(), "."), pathImageFileEmbedded);
BitmapImage _bmpImage = new BitmapImage();
_bmpImage.BeginInit();
_bmpImage.StreamSource = Assembly.GetExecutingAssembly().GetManifestResourceStream(_fullPath);
_bmpImage.EndInit();
return _bmpImage;
}
catch { throw; }
finally { }
}
Correspondingly, set the Source property of the WPF Image control (for example, Image1) to that BitmapImage returned by function:
Image1.Source = GetEmbeddedBitmapImage(_strEmbeddedPath);
Note: you should reference the following:
using System.Windows.Media.Imaging;
using System.Reflection;
Another possible solution is to get the BitmapImage from image file using Uri object as shown in the following code snippet (Listing 2):
Listing 2. Get BitmapImage from File (use Uri)
private BitmapImage GetBitmapImageFromFile(string ImagePath)
{
Uri BitmapUri;
StreamResourceInfo BitmapStreamSourceInfo;
try
{
// Convert stream to Image.
BitmapImage bi = new BitmapImage();
BitmapUri = new Uri(ImagePath, UriKind.Relative);
BitmapStreamSourceInfo = Application.GetResourceStream(BitmapUri);
bi.BeginInit();
bi.StreamSource = BitmapStreamSourceInfo.Stream;
bi.EndInit();
return bi;
}
catch { throw; }
}
Hope this may help.
System.Drawing.Image is WinForms, not WPF. Your ByteToImage method should return BitmapSource instead.
The probably easiest way to create a BitmapSource from a byte array is BitmapFrame.Create:
public BitmapSource ByteArrayToImage(byte[] buffer)
{
using (var stream = new MemoryStream(buffer))
{
return BitmapFrame.Create(stream,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
You would assign the return value of the above method to the Source property of an Image control:
image.Source = ByteArrayToImage(barr);
Ik in windows forms I could add images in resources and then change the images as users click on an event handler not sure whats changed in Xaml but I cant figure it out.
private void guessClick(object sender, RoutedEventArgs e)
{
wrongGuesses++;
hangmanPicture.Image = hangmanImage[wrongGuesses];
}
if I just put hangmanPicture = hangmanImage[wrongGuesses];
I get can not convert. I don't understand why its trying to convert anything.
if your hangmanImage array is an array of ImageSource or BitmapImage, you can use it like this:
private void guessClick(object sender, RoutedEventArgs e)
{
wrongGuesses++;
hangmanPicture.Source = hangmanImage[wrongGuesses];
}
Otherwise, you have to convert anything in hangmanImage into ImageSource or BitmapImage.
If it's Bitmap you can use below converter before that code:
public static BitmapImage ConvertToBitmapImageFromBitmap(Bitmap bitmap)
{
using(var memory = new MemoryStream())
{
BitmapImage bitmapImage;
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
return bitmapImage;
}
}
So, then it will be like this:
hangmanPicture.Source = ConvertToBitmapImageFromBitmap(hangmanImage[wrongGuesses]);
The complete code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Display byte array as image
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
Image img = ByteArrayToImage(File.ReadAllBytes("")); //fill with path info
pictureBox1.Image = (Image)img.Clone();
}
//Convert to image from bytes
public Image ByteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
ms.Position = 0;
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}
//Open Image for conversion
private void loadImage_Click(object sender, EventArgs e)
{
OpenFileDialog opf = new OpenFileDialog();
DialogResult dr = new DialogResult();
dr = opf.ShowDialog();
if (dr == DialogResult.OK)
{
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = Image.FromFile(opf.FileName);
}
}
private void convertImage_Click(object sender, EventArgs e)
{
//Choose Path to Save To
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Title = "Choose Directory and File Name";
saveDialog.Filter = "Canga Comix *.CCMX|*.CCMX";
DialogResult dr = saveDialog.ShowDialog();
if (dr == DialogResult.OK)
{
byte[] array;
//Save Image
using (MemoryStream ms = new MemoryStream())
{
Image img = pictureBox1.Image;
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
array = ms.ToArray();
}
using(FileStream fs = new FileStream(saveDialog.FileName, FileMode.Create))
{
fs.Write(array, 0, array.Length);
}
}
}
//clear image
private void clearImage_Click(object sender, EventArgs e)
{
pictureBox1.Image = null;
}
}
}
These are pretty standard. I have a test program that uses these methods. It opens an image in a pictureBox and then converts it to byte[] and clears the pictureBox Image. Then you can hit Load byte[] and it will display the picture properly as it runs the ByteArrayToImage method.
Then if I save out a picture from my other program and try to open it in the test program it gives me the unholy "Parameter is not valid" error. Even though both text documents are exactly the same as far as I can tell.
This code contains a common problem. Here you create an Image bound to a stream containing your bitmap...
public Image ByteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
ms.Position = 0;
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}
... and the using block disposes the MemoryStream instance on the way out, which makes the Image rather useless.
You can get an Image that manages its own memory instead of expecting your stream to stick around by calling Clone():
public Image ByteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
using (Image returnImage = Image.FromStream(ms))
{
return returnImage.Clone();
}
}
The clone isn't bound to the original stream.
I'm not quite sure what's happening, so I apologize if the title isn't specific. I've provided the code and xaml below which demonstrates my problem. I have the static methods that I call to convert bitmap to byte [] and vice versa. These methods work fine when used to bind source to image control. However, when I use them to assign a source to images which are children of BlockUIContainer as the code demostrates... I get the same image as the previous on my second call to ByteArrayToBitmapSource.
I'm clueless. What is obvious to me, however, is that the second image has the properties of the image that I expect it display, but is apparently the wrong image.
C# MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing;
using System.Windows.Xps.Packaging;
using System.Windows.Xps;
namespace FlowDocumentTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, IDisposable
{
private XpsDocument xpsDocument;
private String randomFileName;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
FlowDocument doc = new FlowDocument();
doc.Blocks.Add(new Paragraph(new Run("Test")));
Section section1 = new Section();
BlockUIContainer blockUIContainer1 = new BlockUIContainer();
blockUIContainer1.Child = new System.Windows.Controls.Image { Source = Source1 };
Section section2 = new Section();
BlockUIContainer blockUIContainer2 = new BlockUIContainer();
blockUIContainer2.Child = new System.Windows.Controls.Image { Source = Source2 };
doc.Blocks.Add(blockUIContainer1);
doc.Blocks.Add(blockUIContainer2);
randomFileName = System.IO.Path.GetRandomFileName();
this.xpsDocument = new XpsDocument(randomFileName, System.IO.FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(((IDocumentPaginatorSource)doc).DocumentPaginator);
this.Viewer.Document = xpsDocument.GetFixedDocumentSequence();
}
public BitmapSource Source1
{
get
{
byte[] tmp = BitmapSourceToByteArray(GetBitmapImage(new Bitmap(#"source1.jpg")));
return ByteArrayToBitmapSource(tmp);
}
}
public BitmapSource Source2
{
get
{
byte[] tmp = BitmapSourceToByteArray(GetBitmapImage(new Bitmap(#"source2.bmp")));
return ByteArrayToBitmapSource(tmp);
}
}
public static BitmapImage GetBitmapImage(Bitmap bitmap)
{
BitmapImage bitmapImage = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
return bitmapImage;
}
public static byte[] BitmapSourceToByteArray(BitmapSource bitmapSource)
{
byte[] data;
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
public static BitmapSource ByteArrayToBitmapSource(byte[] data)
{
BitmapSource result;
using (MemoryStream ms = new MemoryStream(data))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
result = decoder.Frames[0];
}
return result;
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
base.OnClosing(e);
this.Dispose();
}
public void Dispose()
{
this.xpsDocument.Close();
if (System.IO.File.Exists(randomFileName))
System.IO.File.Delete(randomFileName);
}
}
}
XAML MainWindow.xaml
<Window x:Class="FlowDocumentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DocumentViewer Name="Viewer" />
</Grid>
</Window>
I guess it has to do with returning a BitmapSource as oppose to a discreet BitmapImage. Created this method and called this method instead, and it works as I expect.
Still don't know whether this is FlowDocument or XPSDocument related issue.
public static BitmapSource GetBitmapImage(Bitmap bitmap)
{
BitmapImage bitmapImage = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
return bitmapImage;
}