Convert IRandomAccessStreamWithContentType to Byte[] - c#

In my application, I allow users to add people from contact using the ContactPicker.
I try to convert IRandomAccessStreamWithContentType to Byte[]
IRandomAccessStreamWithContentType stream = await contactInformation.GetThumbnailAsync();
if (stream != null && stream.Size > 0)
{
Byte[] bytes = new Byte[stream.Size];
await stream.ReadAsync(bytes.AsBuffer(), (uint)stream.Size, Windows.Storage.Streams.InputStreamOptions.None);
My Byte[] is not empty (approximately 10000 bytes)
But when I use my Converter Byte[] to ImageSource, the BitmapImage has 0 for width and heigth.
I use this converter for another application and it work great...
public object Convert(object value, Type targetType, object parameter, string language)
{
try
{
Byte[] bytes = (Byte[])value;
if (bytes == null)
return (new BitmapImage(new Uri((String)parameter)));
BitmapImage bitmapImage = new BitmapImage();
IRandomAccessStream stream = this.ConvertToRandomAccessStream(new MemoryStream(bytes));
bitmapImage.SetSource(stream);
return (bitmapImage);
}
catch
{
return (new BitmapImage(new Uri((String)parameter)));
}
}
private IRandomAccessStream ConvertToRandomAccessStream(MemoryStream memoryStream)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
outputStream.AsStreamForWrite().Write(memoryStream.ToArray(), 0, (Int32)memoryStream.Length);
return randomAccessStream;
}
If anybody know what is the problem...
Thanks in advance.
NeoKript
Edit : I already use my converter with another project and it works great.
The main difference is that the stream has not the same origine:
var reader = await file.OpenReadAsync();
using (DataReader dataReader = new DataReader(reader))
{
var bytes = new byte[reader.Size];
await dataReader.LoadAsync((uint)reader.Size);
dataReader.ReadBytes(bytes);
// Use of bytes
}

I'm pretty sure bytes in your case contains only zeros. You should modify your reading code:
var buffer = await stream.ReadAsync(bytes.AsBuffer(), (uint)stream.Size, InputStreamOptions.None);
bytes = buffer.ToArray();
Or even better, avoid IBuffer alltogether:
await stream.AsStream().ReadAsync(bytes, 0, bytes.Length);
In both cases the byte array will now contain actual values. I still couldn't get your converter to work and I don't have the time to troubleshoot it further now. Maybe somebody else will help you with that.
EDIT:
I'm not really sure you're using the converter in another project but I couldn't get it to work without using async methods which makes it impossible to use inside IValueConverter. After I changed ConvertToRandomAccessStream the bitmap was created as expected without any other modifications (except for the required await):
private async Task<IRandomAccessStream> ConvertToRandomAccessStream(byte[] bytes)
{
var randomAccessStream = new InMemoryRandomAccessStream();
using (var writer = new DataWriter(randomAccessStream))
{
writer.WriteBytes(bytes);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
}
randomAccessStream.Seek(0);
return randomAccessStream;
}
Instead of using a converter I put an additional property in my view model returning the bitmap. Inside the bytes property I called the async method for creating the bitmap:
public Byte[] ImageBytes
{
get { return _imageBytes; }
set
{
if (Equals(value, _imageBytes)) return;
_imageBytes = value;
OnPropertyChanged();
CreateBitmap();
}
}
public BitmapSource Image
{
get { return _image; }
set
{
if (Equals(value, _image)) return;
_image = value;
OnPropertyChanged();
}
}
private async Task CreateBitmap()
{
try
{
BitmapImage bitmapImage = new BitmapImage();
IRandomAccessStream stream = await this.ConvertToRandomAccessStream(ImageBytes);
bitmapImage.SetSource(stream);
Image = bitmapImage;
}
catch
{
Image = null;
}
}

Related

Cannot convert bitmap to byte[]

So I'm making a Xamarin.Forms app. I have a StackLayout, of which I'm taking a snapshot(only the element, not the whole screen.)
This is the interface:
public interface IViewSnapShot
{
Task<byte[]> CaptureAsync(Xamarin.Forms.View view);
}
this is the event:
private async Task SavePic_ClickedAsync(object sender, EventArgs e)
{
var imageByte = await DependencyService.Get<IViewSnapShot>().CaptureAsync(BlueprintSnapshot);
}
and this is Android platform specific:
public class MakeViewSnapshot : IViewSnapShot
{
Task<byte[]> IViewSnapShot.CaptureAsync(Xamarin.Forms.View view)
{
var nativeView = view.GetRenderer().View;
var wasDrawingCacheEnabled = nativeView.DrawingCacheEnabled;
nativeView.DrawingCacheEnabled = true;
nativeView.BuildDrawingCache(false);
Bitmap bitmap = nativeView.GetDrawingCache(false);
// TODO: Save bitmap and return filepath
nativeView.DrawingCacheEnabled = wasDrawingCacheEnabled;
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
The problem is bitmapData gives error
Cannot implicitly convert type 'byte[]' to 'System.Threading.Tasks.Task'
I have search internet, and every post says that this is the way to convert bitmap to byte[] array. Any idea how to fix this error?
Later I'll want to upload the byte[] array to web api.
Instead of returning a byte[], you can use the Task.FromResult() to wrap a result into a Task:
return Task.FromResult(bitmapData);
Your code might looks like this:
public class MakeViewSnapshot : IViewSnapShot
{
Task<byte[]> IViewSnapShot.CaptureAsync(Xamarin.Forms.View view)
{
var nativeView = view.GetRenderer().View;
var wasDrawingCacheEnabled = nativeView.DrawingCacheEnabled;
nativeView.DrawingCacheEnabled = true;
nativeView.BuildDrawingCache(false);
Bitmap bitmap = nativeView.GetDrawingCache(false);
// TODO: Save bitmap and return filepath
nativeView.DrawingCacheEnabled = wasDrawingCacheEnabled;
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return Task.FromResult(bitmapData);
}
}
And then later when you want to get the byte[] returned by CaptureAsync() you just need to call:
byte[] result = CaptureAsync(<Your_parameters>).Result;

BitMapImage to byte and reverse

Since two days I try to manage my images in a WPF application but I have errors and errors errors, ...
The image is show in a System.Windows.Control.Image.
For this reason I try to work with variable BitMapImage.
Now I have the error : "Impossible to access close stream" and I can not find a solution.
I have created two function for convert :
public static BitmapImage ConvertToBitMapImage(byte[] bytes)
{
if (bytes == null || bytes.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(bytes))
{
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;
}
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;
}
In my object I have a property :
public BitmapImage MiniatureApp
{
get
{
if (IMAGES != null)
_MiniatureApp = Tools.BinaryImageConverter.ConvertToBitMapImage(IMAGES.IMAGE);
return _MiniatureApp;
}
set
{
if (this.IMAGES != null)
this.IMAGES.IMAGE = Tools.BinaryImageConverter.ImageToByte((BitmapImage)value);
else
{
IMAGES img = new IMAGES();
img.NOM = "";
img.IMAGE = Tools.BinaryImageConverter.ImageToByte((BitmapImage)value);
this.IMAGES = img;
}
NotifyPropertyChanged();
}
}
And in my main I do this :
FileStream fs = new FileStream(pathImage, FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
VMAppareil.VMApp.CurrentAppareil.MiniatureApp = Tools.BinaryImageConverter.ConvertToBitMapImage(data);
Exist a solution for my problem or exist a best way to do this ?
Gobelet.
You can fix your solution replacing the ImageToByte method with the following (borrowed from https://stackoverflow.com/a/6597746/5574010)
public static byte[] ImageToByte(BitmapImage imageSource)
{
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(imageSource));
using (var ms = new MemoryStream())
{
encoder.Save(ms);
return ms.ToArray();
}
}
Your previous solution did not work because the ConvertToBitMapImage method close the stream that you assign to image.StreamSource as soon as your code exit the unit statement. When you call the ImageToByte method as part of the MiniatureApp setter the StreamSource will be close and you get an error.
I'm not really sure what you're doing with the getter-setter.
For getting a byte array from a file, I would have this:
public static byte[] FileToByteArray(string fileName)
{
byte[] fileData = null;
using (FileStream fs = new File.OpenRead(fileName))
{
var binaryReader = new BinaryReader(fs);
fileData = binaryReader.ReadBytes((int)fs.Length);
}
return fileData;
}
And once you have the bytes from that function, you can use ConvertToBitMapImage() and assign that to the Image.Source, like this:
byte[] bytes = FileToByteArray(fileName);
YourImage.Source = ConvertToBitMapImage(bytes);
I'm not sure why you would need to convert a BitmapImage into bytes, but you should be able to call your function directly for that:
BitmapImage bImg = new BitmapImage();
bImg.Source = ConvertToBitMapImage(bytes);
byte[] bytes = ImageToByte(bImg); // these should be the same bytes as went in
Set it up like this and step through the code to see where it snags. It's possible the bytes might need encoding when you grab it in ImageToByte().
But also, you don't just then set the byte[] directly to the IMAGES or this.IMAGES.IMAGE, because that isn't an Image object, it's a byte[]. Without knowing what your IMAGES model construct looks like with its property types, it's a little vague to know what is being set to what and why, but this seems like a bad idea to over-complicate what you should just do with function calls as it is needed, without a getter-setter and an IMAGES model in the way.

Convert Image into byte array in Xamarin.Forms

I need to pass an image (Image _thresholdedImage) like byte array... I don't know how I can do this. Any idea? Thank you!
_thresholdedImage.Source = ImageSource.FromStream (() => photo.Source);
var tessResult = await _tesseractApi.SetImage(imageBytes);
I was unable to convert it in X.Forms, instead I use the following code with a dependency service. Thank you to all.
public async Task<byte[]> GetBytesFromImage(string filePath)
{
ConvertImageToBW(filePath);
// Create another bitmap that will hold the results of the filter.
Bitmap thresholdedBitmap = Bitmap.CreateBitmap (BitmapFactory.DecodeFile(filePath));
thresholdedBitmap = BitmapFactory.DecodeFile (thresholdedImagePath);
byte[] bitmapData;
using (var stream = new MemoryStream())
{
thresholdedBitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
Have you tried using converters?
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ImageSource retSource = null;
if (value != null)
{
byte[] imageAsBytes = (byte[])value;
retSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
}
return retSource;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
It turns out that you can convert the MediaFile object to a byte array. So no need to convert the file to ImageSource or Image.
var photo = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions() { });
byte[] imageArray = null;
using (MemoryStream memory = new MemoryStream()) {
Stream stream = photo.GetStream();
stream.CopyTo(memory);
imageArray = memory.ToArray();
}
Source: https://forums.xamarin.com/discussion/156236/how-to-get-the-bytes-from-the-imagesource-in-xamarin-forms
Shoutout to user "ajaxer" in the Xamarin forums whose solution saved me after spending 3 days on this issue. 😁
You could be using the following function:
public async Task<byte[]> Download(string url)
{
using (HttpClient client = new HttpClient())
{
byte[] fileArray = await client.GetByteArrayAsync(url);
return fileArray;
}
}
By Using Java.Io in xamairn forms we can get byte array from imagePath.
It will work for all platforms.
private static byte[] GetBytesFromImage(string imagePath)
{
var imgFile = new File(imagePath);
var stream = new FileInputStream(imgFile);
var bytes = new byte[imgFile.Length()];
stream.Read(bytes);
return bytes;
}
byte[] bitmapData;
using (var stm = new MemoryStream())
{
snapshot.Compress(Bitmap.CompressFormat.Png, 0, stm);
bitmapData = stm.ToArray();
}
Following code can use to convert image into byte array.Here CrossMedia plugin is used to capture image from camera.
public byte[] imageByte;
Stream imageStream = null;
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{ Name = "pic.jpg"});
if (file == null) return;
imageStream = file.GetStream();
BinaryReader br = new BinaryReader(imageStream);
imageByte = br.ReadBytes((int)imageStream.Length);

Get Imagesource from Memorystream in c# wpf

How can I get ImageSource from MemoryStream in WPF using c# ? or convert MemoryStream to ImageSource to display it as image in wpf ?
using (MemoryStream memoryStream = ...)
{
var imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = memoryStream;
imageSource.EndInit();
// Assign the Source property of your image
image.Source = imageSource;
}
Additional to #Darin Dimitrov answer if you disposed the stream before assigning to Image.Source nothing will show, so be careful
For example, the Next method will not work, From one of my projects using LiteDB
public async Task<BitmapImage> DownloadImage(string id)
{
using (var stream = new MemoryStream())
{
var f = _appDbManager.DataStorage.FindById(id);
f.CopyTo(stream);
var imageSource = new BitmapImage {CacheOption = BitmapCacheOption.OnLoad};
imageSource.BeginInit();
imageSource.StreamSource = stream;
imageSource.EndInit();
return imageSource;
}
}
you can not use returned imageSource from the last function
But this implementation will work
public async Task<BitmapImage> DownloadImage(string id)
{
// TODO: [Note] Bug due to memory leaks, if we used Using( var stream = new MemoryStream()), we will lost the stream, and nothing will shown
var stream = new MemoryStream();
var f = _appDbManager.DataStorage.FindById(id);
f.CopyTo(stream);
var imageSource = new BitmapImage {CacheOption = BitmapCacheOption.OnLoad};
imageSource.BeginInit();
imageSource.StreamSource = stream;
imageSource.EndInit();
return imageSource;
}

Saving a TransformedBitmap Object to disk.

Working in WPF and C#, I have a TransformedBitmap object that I either:
Need to save to disk as a bitmap type of file (ideally, I'll allow users to choose whether it's saved as a BMP, JPG, TIF, etc, though, I'm not to that stage yet...)
Need to convert to a BitmapImage object as I know how to get a byte[] from a BitmapImage object.
Unfortunately, at this point I'm really struggling to get either one of those two things done.
Can anyone offer any help or point out any methods I might be missing?
All of your encoders are using BitmapFrame class for creating frames that will be added to Frames collection property of encoder. BitmapFrame.Create method has variety of overloads and one of them accepts parameter of BitmapSource type. So as we know that TransformedBitmap inherits from BitmapSource we can pass it as a parameter to BitmapFrame.Create method. Here are the methods which works as you have described:
public bool WriteTransformedBitmapToFile<T>(BitmapSource bitmapSource, string fileName) where T : BitmapEncoder, new()
{
if (string.IsNullOrEmpty(fileName) || bitmapSource == null)
return false;
//creating frame and putting it to Frames collection of selected encoder
var frame = BitmapFrame.Create(bitmapSource);
var encoder = new T();
encoder.Frames.Add(frame);
try
{
using (var fs = new FileStream(fileName, FileMode.Create))
{
encoder.Save(fs);
}
}
catch (Exception e)
{
return false;
}
return true;
}
private BitmapImage GetBitmapImage<T>(BitmapSource bitmapSource) where T : BitmapEncoder, new()
{
var frame = BitmapFrame.Create(bitmapSource);
var encoder = new T();
encoder.Frames.Add(frame);
var bitmapImage = new BitmapImage();
bool isCreated;
try
{
using (var ms = new MemoryStream())
{
encoder.Save(ms);
ms.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = ms;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
isCreated = true;
}
}
catch
{
isCreated = false;
}
return isCreated ? bitmapImage : null;
}
They accept any BitmapSource as the first parameter and any BitmapEncoder as a generic type parameter.
Hope this helps.

Categories