Convert Image into byte array in Xamarin.Forms - c#

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);

Related

Converting ImageSource to Object Throws Binary stream error

I'm trying to convert/cast an image source to an object. I tried to convert to a byte prior to object.
ImageSource oImageSelectedByUser = (from ii in mySource where ii.PhotoImgStream != null select ii.PhotoImgStream).FirstOrDefault();
var oImageAsByte = await ConvertStreamtoByteAsync(oImageSelectedByUser);
var oImageAsObject = FromByteArray<object>(oImageAsByte);
private static async Task<byte[]> ConvertStreamtoByteAsync(ImageSource imageSource)
{
byte[] buffer = new byte[16 * 1024];
try
{
if (imageSource is FileImageSource)
{
FileImageSource objFileImageSource = (FileImageSource)imageSource;
string strFileName = objFileImageSource.File;
var webClient = new WebClient();
buffer = await webClient.DownloadDataTaskAsync(new Uri(strFileName));
return buffer;
}
}
catch (Exception ex)
{
buffer = null;
}
return buffer;
}
public T FromByteArray<T>(byte[] data)
{
if (data == null)
return default(T);
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
object obj = bf.Deserialize(ms);
return (T)obj;
}
}
When trying to convert to object, the error I get is:
Binary stream '0' does not contain a valid BinaryHeader. Possible
causes are invalid stream or object version change between
serialization and deserialization.
I wanted to ask is there a better way to do this?
Any direction/pointers appreciated.
You could modify the code like following
public T FromByteArray<T>(byte[] data)
{
if (data == null)
return default(T);
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
ms.Seek(0, SeekOrigin.Begin); // /rewinded the stream to the begining.
object obj = bf.Deserialize(ms);
return (T)obj;
}
}

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 IRandomAccessStreamWithContentType to Byte[]

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;
}
}

Load bitmapImage from base64String

How can I load a bitmapImage from base64String in windows 8?
I tried this but I am not successful. It used to work on windows phone. What is different?
Looks like I have to use the function setsourceasync. When I use that, then I am required to pass the parameter as IRandomMemory which I am unable to do. How to do this?
public static BitmapImage Base64ToImage(string base64String)
{
var bitmapImage = new BitmapImage();
try
{
if (!String.IsNullOrEmpty(base64String))
{
var imageBytes = Convert.FromBase64String(base64String);
using (var ms = new MemoryStream(imageBytes, 0, imageBytes.Length))
{
bitmapImage.SetSourcec(ms);
return bitmapImage;
}
}
}
catch (Exception e)
{
}
return null;
}
To create an IRandomAccessStream object for the SetSource method, you need to use a DataWriter. Take a look to this code:
public async Task<BitmapImage> GetImage(string value)
{
if (value == null)
return null;
var buffer = System.Convert.FromBase64String(value);
using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
{
writer.WriteBytes(buffer);
await writer.StoreAsync();
}
var image = new BitmapImage();
image.SetSource(ms);
return image;
}
}
Here conversion methods for both System.Drawing.Bitmap and System.Windows.Media.BitmapSource.
Enjoy
Remark: Not tested on Win8 but there is not reason why it should not work.
string ToBase64(Bitmap bitmap)
{
if (bitmap == null)
throw new ArgumentNullException("bitmap");
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
return Convert.ToBase64String(stream.ToArray());
}
}
string ToBase64(BitmapSource bitmapSource)
{
using (var stream = new MemoryStream())
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(stream);
return Convert.ToBase64String(stream.ToArray());
}
}
Bitmap FromBase64(string value)
{
if (value == null)
throw new ArgumentNullException("value");
using (var stream = new MemoryStream(Convert.FromBase64String(value)))
{
return (Bitmap)Image.FromStream(stream);
}
}
BitmapSource BitmapSourceFromBase64(string value)
{
if (value == null)
throw new ArgumentNullException("value");
using (var stream = new MemoryStream(Convert.FromBase64String(value)))
{
var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
BitmapSource result = decoder.Frames[0];
result.Freeze();
return result;
}
}

Categories