I'm re-writing a app of mine, where I create a barcode image using the Barcode Image Generation Libary by Brad Barnhill (http://www.codeproject.com/Articles/20823/Barcode-Image-Generation-Library).
In this article everything is explaned how to do it in Windows Forms. But now - using Wpf - there are some errors. E.g.: The result of the function Encode returns a System.Drawing.Image but when I want to display this Image in a Wpf Image Control the Source property wants a System.Windows.Media.ImageSource.
So I did some reserach of how to convert a Drawing.Image in a Media.ImageSource. I found some snippets but they don't work as expected.
Currently I use this code:
// Import:
using Media = System.Windows.Media;
using Forms = System.Windows.Forms;
// Setting some porperties of the barcode-object
this.barcode.RotateFlipType = this.bcvm.Rotation.Rotation;
this.barcode.Alignment = this.bcvm.Ausrichtung.Alignment;
this.barcode.LabelPosition = this.bcvm.Position.Position;
// this.bcvm is my BarcodeViewModel for MVVM
var img = this.barcode.Encode(
this.bcvm.Encoding.Encoding,
this.bcvm.EingabeWert,
this.bcvm.ForeColor.ToDrawingColor(),
this.bcvm.BackColor.ToDrawingColor(),
(int)this.bcvm.Breite,
(int)this.bcvm.Hoehe
);
this.imgBarcode.Source = img.DrawingImageToWpfImage();
this.imgBarcode.Width = img.Width;
this.imgBarcode.Height = img.Height;
// My conversion methode. It takes a Drawing.Image and returns a Media.ImageSource
public static Media.ImageSource ToImageSource(this Drawing.Image drawingImage)
{
Media.ImageSource imgSrc = new Media.Imaging.BitmapImage();
using (MemoryStream ms = new MemoryStream())
{
drawingImage.Save(ms, Drawing.Imaging.ImageFormat.Png);
(imgSrc as Media.Imaging.BitmapImage).BeginInit();
(imgSrc as Media.Imaging.BitmapImage).StreamSource = new MemoryStream(ms.ToArray());
(imgSrc as Media.Imaging.BitmapImage).EndInit();
}
return imgSrc;
}
When running this code an converting the image (and assigning it to the Image control) there is nothing displayed
This conversion method should work:
public static ImageSource ToImageSource(this System.Drawing.Image image)
{
var bitmap = new BitmapImage();
using (var stream = new MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
return bitmap;
}
In case the System.Drawing.Image is actually a System.Drawing.Bitmap you may also use some other conversion methods, as shown here: fast converting Bitmap to BitmapSource wpf
Related
I have a function in my code behind that does what I want. What I like about this is no matter how the user expand his drawing out of the InkCanvas boundries, the image will be resized when saved.
private void exportCanvasToBitmap(object sender, EventArgs e) {
RenderTargetBitmap rtb = new
RenderTargetBitmap((int)signatureCanvas.ActualWidth,
(int)signatureCanvas.ActualHeight, 96, 96, PixelFormats.Default);
rtb.Render(signatureCanvas);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
FileStream fs = File.Open(#".\images\"+ signatureFileName + ".jpg", FileMode.Create);
encoder.Save(fs);
fs.Close();
(sourceWindow as MainWindow).updateSignatureImage(signatureType, signatureFileName);
}
I wanted to move this to the ViewModel and I didn't know how to make it does the same as the one I have before. I don't want to usertb.Render(inkCanvas) in the ViewModel. After some search I binded a StrokeCollection to my view and used this function.
public void convertStrokestoImage() {
StrokeCollection sc = strokes;
byte[] inkData = null;
using (MemoryStream inkMemStream = new MemoryStream())
{
sc.Save(inkMemStream);
inkData = inkMemStream.ToArray();
}
byte[] gifData = null;
using (Microsoft.Ink.Ink ink2 = new Microsoft.Ink.Ink())
{
ink2.Load(inkData);
gifData = ink2.Save(Microsoft.Ink.PersistenceFormat.Gif);
}
File.WriteAllBytes("./Src/strokes.png", gifData);
}
The problem with this is that if the user draws out of the InkCanvas' boundaries, the image scales " which I don't want". I am not really sure how to do that since both of the function I found online as solutions in other questions.
My initial thought is that I have to do something similar for what I had before where I had a RenderTargetBitmap that has the actual width and height of my InkCanvas. The issue is I don't know how to obtain this without using InkCanvas object itself.
any tips?
I solved the issue like this.
First I converted the byte[] to an Image and then I used a helper function to resize the image.
public void convertStrokestoImage()
{
StrokeCollection sc = strokes;
byte[] inkData = null;
using (MemoryStream inkMemStream = new MemoryStream())
{
sc.Save(inkMemStream);
inkData = inkMemStream.ToArray();
}
byte[] gifData = null;
using (Microsoft.Ink.Ink ink2 = new Microsoft.Ink.Ink())
{
ink2.Load(inkData);
gifData = ink2.Save(Microsoft.Ink.PersistenceFormat.Gif);
}
MemoryStream ms = new MemoryStream(gifData);
Image image = Image.FromStream(ms);
image = resizeImage(image, 100, 150);
image.Save("./Src/strokes.png");
}
You can find alot of functions to resize images in the following question.
Resize an Image C#
What I don't like about this is the image file size become bigger!
For example what was 5kb became 30kb.
I have saved images in our database by using the following method to convert them to byte arrays in different ImageFormats:
public byte[] foo()
{
Image img = Image.FromFile(path);
var tmpStream = new MemoryStream();
ImageFormat format = img.RawFormat;
img.Save(tmpStream, format);
tmpStream.Seek(0, SeekOrigin.Begin);
var imgBytes = new byte[MAX_IMG_SIZE];
tmpStream.Read(imgBytes, 0, MAX_IMG_SIZE);
return imgBytes;
}
Now I need to read them out and convert them back into the BitmapImage type so I can display them to the user. I was thinking about using the Image.FromStream(Stream) method but that doesn't seem to take into account the different ImageFormats... Anyone know what to do? Thanks in advance.
You shouldn't use classes from the WinForms System.Drawing namespace in a WPF application (like you do with Image.FromFile).
WPF provides its own set of classes to load and save bitmaps from Streams and URIs, and has built-in support for automatically detecting the format of a bitmap frame buffer.
Just create a BitmapImage or a BitmapFrame directly from a Stream:
public static BitmapSource BitmaSourceFromByteArray(byte[] buffer)
{
var bitmap = new BitmapImage();
using (var stream = new MemoryStream(buffer))
{
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze(); // optionally make it cross-thread accessible
return bitmap;
}
or
public static BitmapSource BitmaSourceFromByteArray(byte[] buffer)
{
using (var stream = new MemoryStream(buffer))
{
return BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
Either method returns a BitmapSource, which is the base class of BitmapImage and BitmapFrame, and should be sufficient to deal with bitmaps in the rest of your application. E.g. the Source property of an Image control uses another base class, ImageSource, as property type.
Note also that when you load a BitmapSource from a Stream that is to be closed after loading, you have to set BitmapCacheOption.OnLoad. Otherwise the Stream must be kept open until the bitmap is eventually shown.
For encoding a BitmapSource you should be using a method like this:
public static byte[] BitmapSourceToByteArray(BitmapSource bitmap)
{
var encoder = new PngBitmapEncoder(); // or any other BitmapEncoder
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
return stream.ToArray();
}
}
I have to convert BitmapImage (JPEG inside) to byte[] and then back.
Here is my code:
using System.IO;
using System.Windows.Media.Imaging;
public class CImageConverter
{
//
public BitmapImage ByteArray_To_BitmapImage(byte[] _binaryData)
{
BitmapImage _bitmapImage = new BitmapImage();
//
_bitmapImage.BeginInit();
_bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
_bitmapImage.StreamSource = new MemoryStream(_binaryData);
_bitmapImage.EndInit();
//
return _bitmapImage;
}
//
public byte[] BitmapImage_To_ByteArray(BitmapImage _bitmapImage)
{
byte[] bytes;
//
using(MemoryStream ms = new MemoryStream())
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(_bitmapImage));
encoder.Save(ms);
bytes = ms.ToArray();
}
//
return bytes;
}
}
It seems that BitmapImage_To_ByteArray working properly.
But ByteArray_To_BitmapImage throwing NotSupportedException in EndInit() method.
The message is (translated with web-translator):
Could not locate the image processing component which is suitable to
complete this operation.
I found similar questions on the internet, but the answers do not work. The usual answer is "I tried your code - I have everything working fine."
I also found this suggestion, but did not understood, how to use it.
Thanks for your help!
public BitmapImage ToImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad; // here
image.StreamSource = ms;
image.EndInit();
return image;
}
}
Have you tried this?
I'm trying to set a Grid's backgroud through code.
The Grid has 1000 x 1000 size, the same size of the loaded PNG.
I load this PNG into a Stream, then execute the following code:
using (StreamWrapper wrapper = new StreamWrapper(streamImg))
using (BinaryReader reader = new BinaryReader(wrapper))
{
originalImage = new BitmapImage();
originalImage.BeginInit();
originalImage.CacheOption = BitmapCacheOption.OnLoad;
originalImage.StreamSource = reader.BaseStream;
originalImage.EndInit();
originalImage.Freeze();
}
ib = new ImageBrush() { ImageSource = ConvertToGrayScale(ref originalImage) };
grdQuebraCabeƧa.Background = ib;
private FormatConvertedBitmap ConvertToGrayScale(ref BitmapImage image)
{
FormatConvertedBitmap grayImage = new FormatConvertedBitmap();
grayImage.BeginInit();
grayImage.Source = image;
grayImage.DestinationFormat = PixelFormats.Gray32Float;
grayImage.EndInit();
return grayImage;
}
The following screenshot is the result:
You can see black blocks on lower and right sides.
I want to center the image in the grid.
Is that possible? How can I achieve this result?
I'm making a player and I'm stuck in a apparently simple problem.
I need to make the cover art of the song to be displayed in one Image box.
I found these two solutions:
This:
var file = TagLib.File.Create(filename);
if (file.Tag.Pictures.Length >= 1)
{
var bin = (byte[])(file.Tag.Pictures[0].Data.Data);
PreviewPictureBox.Image = Image.FromStream(new MemoryStream(bin)).GetThumbnailImage(100, 100, null, IntPtr.Zero);
}
and this:
System.Drawing.Image currentImage = null;
// In method onclick of the listbox showing all mp3's
TagLib.File f = new TagLib.Mpeg.AudioFile(file);
if (f.Tag.Pictures.Length > 0)
{
TagLib.IPicture pic = f.Tag.Pictures[0];
MemoryStream ms = new MemoryStream(pic.Data.Data);
if (ms != null && ms.Length > 4096)
{
currentImage = System.Drawing.Image.FromStream(ms);
// Load thumbnail into PictureBox
AlbumArt.Image = currentImage.GetThumbnailImage(100,100, null, System.IntPtr.Zero);
}
ms.Close();
}
But both are to Windows Forms, I suppose, because I have problems with them.
I'm not sure which solution makes the most sense. Could anyone give me some pointers?
Use System.Windows.Controls.Image to display your images on UI. You must set it's Source property in order to provide image data to render on UI.
// Load you image data in MemoryStream
TagLib.IPicture pic = f.Tag.Pictures[0];
MemoryStream ms = new MemoryStream(pic.Data.Data);
ms.Seek(0, SeekOrigin.Begin);
// ImageSource for System.Windows.Controls.Image
BitmapImage bitmap= new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();
// Create a System.Windows.Controls.Image control
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Source = bitmap;
Then you can add/place this Image control to UI.