ESRI Symbology library is slow and sometimes take longer time than expected.
I wish to serialize a selected range of ImageSource to a cache, string in the memory or file.
I have searched the web but not much on ImageSource.
An interesting thing I have found is "ImageSourceValueSerializer".
Being a 3 months old baby in WPF, I am not so sure how to go about this.
here's how I got the ImageSource:
MultilayerPointSymbol multiLayerSym = await result.GetSymbolAsync() as MultilayerPointSymbol;
RuntimeImage swatch = await multiLayerSym.CreateSwatchAsync();
ImageSource symbolImage = await swatch.ToImageSourceAsync();
Tested Clemen's, the routine:
MultilayerPointSymbol multiLayerSym = await result.GetSymbolAsync() as MultilayerPointSymbol;
RuntimeImage swatch = await multiLayerSym.CreateSwatchAsync();
ImageSource symbolImage = await swatch.ToImageSourceAsync();
byte[] b = ImageSourceBinary(symbolImage);
ImageSource test = BinaryImageSource(b);
In the class:
private byte[] ImageSourceBinary(ImageSource imageSrc)
{
if (imageSrc is BitmapSource bitmapSource)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (MemoryStream stream = new MemoryStream())
{
encoder.Save(stream);
return stream.ToArray();
}
}
return null;
}
private ImageSource BinaryImageSource(byte[] bytes)
{
using (MemoryStream stream = new MemoryStream(bytes))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.Default);
BitmapFrame bf = decoder.Frames[0];
if (bf is ImageSource imagesource)
return imagesource;
return null;
}
}
The outcome, no image! :(
Check if the ImageSource is a BitmapSource and encode the BitmapSource by one of the BitmapEncoders. Encode into a MemoryStream or a FileStream.
private byte[] ImageSourceToByteArray(ImageSource imageSrc)
{
if (symbolImage is BitmapSource bitmapSource)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
return stream.ToArray();
}
}
return null;
}
In order to decode an image from a byte array, do not explictly use a specific BitmapDecoder. Better rely on automatic decoder selection, like shown below. It is also important to set BitmapCacheOption.OnLoad when the stream is closed right after decoding.
private ImageSource ByteArrayToImageSource(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
{
return BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
Related
I need to convert a BitmapImage in a byte[] but I don't find how to do it in C# web.
I found examples but none of them work (JpegBitmapEncoder doesn't exist, BitmapImageObject.StreamSource doesn't exist, there isn't WriteableBitmap constructor with BitmapImage as parameter, Extensions.SaveJpeg(parameters) doesn't exist ...).
Examples I found:
Constructor new WriteableBitmap(bitmapImage) doesn't exist.
public static byte[] ConvertToBytes(this BitmapImage bitmapImage)
{
byte[] data;
// Get an Image Stream
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap btmMap = new WriteableBitmap(bitmapImage);
// write an image into the stream
Extensions.SaveJpeg(btmMap, ms,
bitmapImage.PixelWidth, bitmapImage.PixelHeight, 0, 100);
// reset the stream pointer to the beginning
ms.Seek(0, 0);
//read the stream into a byte array
data = new byte[ms.Length];
ms.Read(data, 0, data.Length);
}
//data now holds the bytes of the image
return data;
}
new WriteableBitmap(img), System.Windows.Media.Imaging.Extensions.SaveJpeg don't exist.
public static byte[] ImageToBytes(BitmapImage img)
{
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap btmMap = new WriteableBitmap(img);
System.Windows.Media.Imaging.Extensions.SaveJpeg(btmMap, ms, img.PixelWidth, img.PixelHeight, 0, 100);
img = null;
return ms.ToArray();
}
}
imageSource.StreamSource doesn't exist.
public static byte[] ImageToByte(BitmapImage imageSource)
{
Stream stream = imageSource.StreamSource;
Byte[] buffer = null;
if (stream != null && stream.Length > 0)
{
using (BinaryReader br = new BinaryReader(stream))
{
buffer = br.ReadBytes((Int32)stream.Length);
}
}
return buffer;
}
JpegBitmapEncoder doesn't exist.
byte[] data;
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
using(MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
Try with the using statement to a namespace in the beginning of your code.
Otherwise there should be some Nuget packages which you could install to achieve your goal.
using System.Drawing;
In Main method
Image img = Image.FromFile("path to the file");
var byteArray = ImageToByte(img);
public static byte[] ImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
Try this
I think this will help...
public byte[] ConvertBitMapToByteArray(Bitmap bitmap)
{
byte[] result = null;
if (bitmap != null)
{
MemoryStream stream = new MemoryStream();
bitmap.Save(stream, bitmap.RawFormat);
result = stream.ToArray();
}
return result;
}
byte[] foo = System.IO.File.ReadAllBytes("bitmap path");
Or
byte[] foo;
Object obj = YourBitmap;
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, obj);
foo = ms.ToArray();
}
Or
ImageConverter foocon = new ImageConverter();
byte[] foo = (byte[])foocon.ConvertTo(YourBitmap, typeof(byte[]));
Or
MemoryStream ms = new MemoryStream();
Bitmap.Save(ms, YourBitmap.RawFormat);
byte[] foo = ms.ToArray();
Finally, it seems that, obviously, it missed some libraries but we are limited with our application, so we decided to recover our pictures by another way. Anyway, thank you all.
Who can help me. I don't understand how i can convert BitmapImage or IRandomAccessStream to byte array.
I try:
foreach (StorageFile file in files)
{
BitmapImage src = new BitmapImage();
using (IRandomAccessStream stream = await file.OpenReadAsync())
{
await src.SetSourceAsync(stream);
WriteableBitmap bitMap = new WriteableBitmap(src.PixelWidth, src.PixelHeight);
await bitMap.SetSourceAsync(stream);
}
}
then i have WriteableBitmap and try this:
private byte[] ImageToByeArray(WriteableBitmap wbm)
{
using (Stream stream = wbm.PixelBuffer.AsStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
but it's don't work for me ;(
This should do it:
async Task<byte[]> Convert(IRandomAccessStream s)
{
var dr = new DataReader(s.GetInputStreamAt(0));
var bytes = new byte[s.Size];
await dr.LoadAsync((uint)s.Size);
dr.ReadBytes(bytes);
return bytes;
}
I used this solution in my WPF applications to save images in database as byte[]. It should also work in your case.
public static byte[] ImageToString(System.Windows.Media.Imaging.BitmapImage img) {
System.IO.MemoryStream stream = new System.IO.MemoryStream();
System.Windows.Media.Imaging.BmpBitmapEncoder encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)img));
encoder.Save(stream);
stream.Flush();
return stream.ToArray();
}
I cannot decode images back from their encoded form as a (Jpeg) byte array retrieved from my database to be used as image sources for my WPF application.
The code I am using to encode them as a Jpeg byte array is as follows:
public byte[] bytesFromBitmap(BitmapImage bit)
{
byte[] data;
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bit));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
This is taking my Image taken directly from a webpage and assigned to an Image control like so:
var img = new BitmapImage(new Uri(entity.Image.ImageSrc)); //the entity has been saved in my DB, having been parsed from html
pbImage.Source = img;
This works just fine, I encode the BitmapImage and it saves just fine. But when I retrieve it from the DB and try to display it in another window, I cannot get it to work after trying every example I can see online - all either render nothing, or a black box or a visual mess not at all similar to the image I encoded.
Neither of the following have worked for me:
public BitmapSource GetBMImage(byte[] data)
{
using (var ms = new MemoryStream(data))
{
JpegBitmapDecoder decoder = new JpegBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource frame = decoder.Frames[0];
return frame;
}
}
public static BitmapImage ImageFromBytes(byte[] imageData)
{
if (imageData == null)
{
return null;
}
else
{
var image = new BitmapImage();
using (var mem = new MemoryStream())
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
} //this throws a 'No imaging component suitable to complete this operation was found' exception
Among other uses of memory streams and decoders I just can't get this to work - can anyone help?
I have jpeg.
I convert it to a BitmapImage.
I then reduce the quality (compression).
I then covert to byte array.
I have found the memory escalates very quickly in task manager.
I am certain I am disposing all that I can.
This is my code:
//I am calling this from within a timer set 500ms
byte[] datatest = JpegXr.SaveJpegXrToBytes((Bitmap)frame.Clone(), 40f);
frame.Dispose();
public static class JpegXr
{
public static Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
// BitmapImage bitmapImage = new BitmapImage(new Uri("../Images/test.png", UriKind.Relative));
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
// return bitmap; <-- leads to problems, stream is closed/closing ...
return new Bitmap(bitmap);
}
}
public static byte[] SaveJpegXrToBytes(Bitmap bitmap, float quality)
{
byte[] data = null;
var stream = new MemoryStream();
SaveJpegXr(bitmap, quality, stream);
stream.Seek(0, SeekOrigin.Begin);
data= stream.ToArray();
stream.Close();
bitmap.Dispose();
return data;
}
private static BitmapImage Bitmap2BitmapImage(Bitmap bitmap)
{
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero, System.Windows.Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
//BitmapSource bitmapSource = Clipboard.GetImage();
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
MemoryStream memoryStream = new MemoryStream();
BitmapImage bImg = new BitmapImage();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(memoryStream);
bImg.BeginInit();
bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
bImg.EndInit();
memoryStream.Close();
bitmap.Dispose();
return bImg;
//return (BitmapImage)i;
//return i;
}
private static void SaveJpegXr(Bitmap bitmap, float quality, Stream output)
{
BitmapImage bitmapSource = Bitmap2BitmapImage((Bitmap)bitmap.Clone());
//var bitmapSource = bitmap.ToWpfBitmap();
var bitmapFrame = BitmapFrame.Create(bitmapSource);
var jpegXrEncoder = new WmpBitmapEncoder();
jpegXrEncoder.Frames.Add(bitmapFrame);
jpegXrEncoder.ImageQualityLevel = quality / 100f;
jpegXrEncoder.Save(output);
bitmap.Dispose();
}
}
Is it just the case that doing these conversions is memory consuming by its very nature and as such calling it frequently from within a timer does not give the garbage collector time to dispose objects correctly?
Appreciate peoples wisdom on this...
i am trying to convert a bitmap to a base64 string.i can convert to from string to bitmap...but it seems like there is a problem when converting from bitmap to string.I was hoping you guys could give me a hand
public static string BitmapToString(BitmapImage image)
{
Stream stream = image.StreamSource ;
Byte[] buffer = null;
if (stream != null && stream.Length > 0)
{
using (BinaryReader br = new BinaryReader(stream))
{
buffer = br.ReadBytes((Int32)stream.Length);
}
}
return Convert.ToBase64String(buffer);
}
it gets a ArgumentNullException was unhandled
Value cannot be null.
Parameter name: inArray
when returning Convert.ToBase64String(buffer)
Help?
Try this alternative:
public string BitmapToBase64(BitmapImage bi)
{
MemoryStream ms = new MemoryStream();
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bi));
encoder.Save(ms);
byte[] bitmapdata = ms.ToArray();
return Convert.ToBase64String(bitmapdata);
}
In your solution, it is not necessary that StreamSource will always have value if it is loaded using a Uri.
First of all, it is necessary to save BitmapImage data into memory using some bitmap encoder (PngBitmapEncoder for example).
public static byte[] EncodeImage(BitmapImage bitmapImage)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
encoder.Save(memoryStream);
return memoryStream.ToArray();
}
}
Then just encode the binary data with Base64-encoding.
const string filePath = #"...";
const string outFilePath = #"...";
const string outBase64FilePath = #"...";
// Constuct test BitmapImage instance.
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = File.OpenRead(filePath);
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
// Convert BitmapImage to byte array.
byte[] imageData = EncodeImage(bitmapImage);
File.WriteAllBytes(outFilePath, imageData);
// Encode with Base64.
string base64String = Convert.ToBase64String(imageData);
// Write to file (for example).
File.WriteAllText(outBase64FilePath, base64String);