Xamarin Forms - Image to String and reverse - image

I saw so much of post on google and I couldn't make it works.
However, it seems so easy and logic to get an Xamarin.Forms.Image into a String but I'm not able to realize it. I tried from stream, from platform renderer, still doesn't work.
I want it to work on every platform, can you help me?
Thank !

If what you want is a string representation of a Image then first you need to get the bytes from this image and then convert it into a string format like Base64
But first we need to get the byte from the image, Xamarin.Forms's Image is a View which contains a Source
public class Image : View, IImageController, IElementConfiguration<Image>
{
public ImageSource Source { get; set; }
}
That source is used to load the image that will be shown, we have a some kinds of ImageSource (FileImageSource, StreamImageSource, UriImageSource) but if I'm not mistaken currently no way to transform ImageSource to bytes in Xamarin.Forms, but we can use native code for such
Android
In Android we can use IImageSourceHandler to transform an ImageSource to Bitmap and form the Bitmap to bytes
[assembly: Dependency(typeof(ImageLoader))]
public class ImageLoader : IImageLoader
{
public async Task<byte[]> LoadImageAsync(ImageSource source)
{
IImageSourceHandler handler = GetHandlerFor(source);
var bmp = await handler.LoadImageAsync(source, Forms.Context);
byte[] result;
using (Stream ms = new MemoryStream())
{
await bmp.CompressAsync(Android.Graphics.Bitmap.CompressFormat.Jpeg, 95, ms);
result = new byte[ms.Length];
ms.Position = 0;
await ms.ReadAsync(result, 0, (int)ms.Length);
}
return result;
}
private IImageSourceHandler GetHandlerFor(ImageSource source)
{
IImageSourceHandler result;
if (source is FileImageSource) result = new FileImageSourceHandler();
else if (source is StreamImageSource) result = new StreamImagesourceHandler();
else result = new ImageLoaderSourceHandler();
return result;
}
}
iOS
Same as Android we can use IImageSourceHandler to transform into UIImage and then get the bytes from it
[assembly: Dependency(typeof(ImageLoader))]
public class ImageLoader : IImageLoader
{
public async Task<byte[]> LoadImageAsync(ImageSource source)
{
IImageSourceHandler handler = GetHandlerFor(source);
UIImage image = await handler.LoadImageAsync(source);
using (NSData imageData = image.AsPNG())
{
return imageData.ToArray();
}
}
private IImageSourceHandler GetHandlerFor(ImageSource source)
{
IImageSourceHandler result;
if (source is FileImageSource) result = new FileImageSourceHandler();
else if (source is StreamImageSource) result = new StreamImagesourceHandler();
else result = new ImageLoaderSourceHandler();
return result;
}
}
#Forms
Note that I inserted [assembly: Dependecy(typeof(ImageLoader))] so we can use the Xamarin Forms to recognize and bring the correct ImageLoader from each Platform so we use it like this
byte[] bytes = await DependencyService.Get<IImageLoader>().LoadImageAsync(imgSource);
string base64String = Convert.ToBase64String(bytes) //convert the binary to a string representation in base64
#note
IImageLoaderis a simple interface like the following
public interface IImageLoader
{
Task<byte[]> LoadImageAsync(ImageSource source);
}

Related

How can I save an image in sqliteconnection xamarin forms [duplicate]

I have the following two methods that handles taking photos from a camera and picking photos from a library. They're both similar methods as at the end of each method, I get an ImageSource back from the Stream and I pass it onto another page which has an ImageSource binding ready to be set. These two method work perfectly. The next step now is to save the Image in SQLite so I can show the images in a ListView later on. My question for the XamGods (Xamarin Pros =), what is the best way to save image in SQLite in 2019? I have been in the forums for hours and I still don't have a tunnel vision on what I want to do. I can either
Convert Stream into an array of bytes to save in Sqlite.
Convert ImageSource into an array of bytes (messy/buggy).
Somehow retrieve the actual Image selected/taken and convert that into an array of bytes into SQLite
I'm sorry if my question is general, but Xamarin does not provide a clear-cut solution on how to save images in SQLite and you can only find bits and pieces of solutions throughout the forums listed below.
How to save and retrieve Image from Sqlite
Load Image from byte[] array.
Creating a byte array from a stream
Thank you in advance!
private async Task OnAddPhotoFromCameraSelected()
{
Console.WriteLine("OnAddPhotoFromCameraSelected");
var photo = await Plugin.Media.CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions() { });
var stream = photo.GetStream();
photo.Dispose();
if (stream != null)
{
ImageSource cameraPhotoImage = ImageSource.FromStream(() => stream);
var parms = new NavigationParameters();
parms.Add("image", cameraPhotoImage);
var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);
if (!result.Success)
{
throw result.Exception;
}
}
}
private async Task OnAddPhotoFromLibrarySelected()
{
Console.WriteLine("OnAddPhotoFromLibrarySelected");
Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
if (stream != null)
{
ImageSource selectedImage = ImageSource.FromStream(() => stream);
var parms = new NavigationParameters();
parms.Add("image", selectedImage);
parms.Add("stream", stream);
var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);
if (!result.Success)
{
throw result.Exception;
}
}
}
As Jason said that you can save image path into sqlite database, but if you still want to save byte[] into sqlite database, you need to convert stream into byte[] firstly:
private byte[] GetImageBytes(Stream stream)
{
byte[] ImageBytes;
using (var memoryStream = new System.IO.MemoryStream())
{
stream.CopyTo(memoryStream);
ImageBytes = memoryStream.ToArray();
}
return ImageBytes;
}
Then load byte[] from sqlite, converting into stream.
public Stream BytesToStream(byte[] bytes)
{
Stream stream = new MemoryStream(bytes);
return stream;
}
For simple sample, you can take a look:
Insert byte[] in sqlite:
private void insertdata()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
using (var con = new SQLiteConnection(path))
{
Image image = new Image();
image.Content = ConvertStreamtoByte();
var result = con.Insert(image);
sl.Children.Add(new Label() { Text = result > 0 ? "insert successful insert" : "fail insert" });
}
}
Loading image from sqlite:
private void getdata()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
using (var con = new SQLiteConnection(path))
{
var image= con.Query<Image>("SELECT content FROM Image ;").FirstOrDefault();
if(image!=null)
{
byte[] b = image.Content;
Stream ms = new MemoryStream(b);
image1.Source = ImageSource.FromStream(() => ms);
}
}
}
Model:
public class Image
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string FileName { get; set; }
public byte[] Content { get; set; }
}

How to get Image from directory path in xamarin forms

I want to retrieve image which i have it's path in phone
filepath = "/storage/emulated/0/Android/data/com.CommunicatorEye/files/Pictures/EmployeesCards/IMG_20190131_143513.jpg";
var image = DependencyService.Get<IDependency().RetriveImageFromLocation(filepath);
IDependency.cs
public interface IDependency
{
Task<Image> RetriveImageFromLocation(string location);
}
Android
DependencyImplementation.cs
public async Task<Image> RetriveImageFromLocation(string location)
{
Image image = new Image();
var memoryStream = new MemoryStream();
using (var source = System.IO.File.OpenRead(location))
{
await source.CopyToAsync(memoryStream);
}
image.Source = ImageSource.FromStream(() => memoryStream);
return image;
}
but it doesn't work for me , any sample ?
If that file is within your app's sandbox, there is no reason to use DI/DependencyService/etc... to obtain a stream to populate an ImageSource and then add that to an Image.
Use an FileImageSource (static ImageSource.FromFile) and supply it the path:
var image = new Image
{
Source = ImageSource.FromFile(filePath)
};
This is how you can get path of resources. keys should be declared in App.xaml file
public static String GetImagePath(string AppResourceName)
{
return (Application.Current.Resources[AppResourceName] as FileImageSource).File;
}
public static Color GetColor(string AppResourceName)
{
return (Color)Application.Current.Resources[AppResourceName];
}

how to save byte[] image in custom folder in webapi?

i have one model contain image ,i send model from angularjs and get model in webapi ,my method in web api
public IHttpActionResult Post([FromBody]Game model)
{
Image img = LoadImage(model.Image);
Game game = model;
_repository.Add<Game>(game);
return Ok();
}
public Image LoadImage(string imageName)
{
string[] str = imageName.Split(',');
byte[] bytes = Convert.FromBase64String(str[1]);
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
return image;
}
but this code just return base64 to image,i want save jpg on custom folder in project
this code solve your problem
public IHttpActionResult Post([FromBody]Game model)
{
var image = SaveImage(model.Image, Guid.NewGuid().ToString());
model.Image = image; // set image name in model
_repository.Add<Game>(model);
return Ok();
}
public string SaveImage(string ImgStr, string ImgName)
{
String path = HttpContext.Current.Server.MapPath("~/images/Games"); //Path
//Check if directory exist
if (!System.IO.Directory.Exists(path))
{
System.IO.Directory.CreateDirectory(path); //Create directory if it doesn't exist
}
string imageName = ImgName + ".jpg";
//set the image path
string imgPath = Path.Combine(path, imageName);
string[] str = ImgStr.Split(',');
byte[] bytes = Convert.FromBase64String(str[1]);
File.WriteAllBytes(imgPath, bytes);
return imageName;
}

Best approach to download image

I have a simple site (WebAPI) that returns a bunch of albums in the get method. Each album has attributes such as title, artist and so on. The attribute under here is the image (album photo) attribute. Each album has an image, what is the best way to send the image back to client. Should it be sent as binary data as part of the album object for example like
Public Class Album
{
string title;
byte[] image;
}
Or should I send the path to the image in the Album object and have the client download the image separately?
Like
Public Class Album
{
string title;
string imagePath;
}
You can see this post The downloaded file as stream in controller (ASP.NET MVC 3) will automatically disposed? as reference.
You can use FileStream.
protected override void WriteFile(HttpResponseBase response) {
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream) {
byte[] buffer = new byte[_bufferSize];
while (true) {
int bytesRead = FileStream.Read(buffer, 0, _bufferSize);
if (bytesRead == 0) {
// no more data
break;
}
outputStream.Write(buffer, 0, bytesRead);
}
}
}
Instead of passing
Public class Album
{
string title;
byte[] image;
}
back to the client, I would change image to a int imageId:
Public class Album
{
string Title{get;set};
int ImageId{get;set};
}
Then create a WebApi controller that handles images with a method written like this:
public async Task<HttpResponseMessage> Get(HttpRequestMessage request, int imageId)
{
byte[] img = await _myRepo.GetImgAsync(imageId);
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(img)
};
msg.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return msg;
}

How to Convert byte array to ImageSource for Windows 8.0 store application

I am working on Windows 8 store application. I am new at it.
I am receiving an image in the form of byte array (byte []).
I have to convert this back to Image and display it in Image Control.
so far I have button and Image control on Screen. When I click button, I call following function
private async Task LoadImageAsync()
{
byte[] code = //call to third party API for byte array
System.IO.MemoryStream ms = new MemoryStream(code);
var bitmapImg = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
Windows.Storage.Streams.InMemoryRandomAccessStream imras = new Windows.Storage.Streams.InMemoryRandomAccessStream();
Windows.Storage.Streams.DataWriter write = new Windows.Storage.Streams.DataWriter(imras.GetOutputStreamAt(0));
write.WriteBytes(code);
await write.StoreAsync();
bitmapImg.SetSourceAsync(imras);
pictureBox1.Source = bitmapImg;
}
This is not working properly. any idea?
When I debug, I can see the byte array in ms. but it is not getting converted to bitmapImg.
I found the following on Codeproject
public class ByteImageConverter
{
public static ImageSource ByteToImage(byte[] imageData)
{
BitmapImage biImg = new BitmapImage();
MemoryStream ms = new MemoryStream(imageData);
biImg.BeginInit();
biImg.StreamSource = ms;
biImg.EndInit();
ImageSource imgSrc = biImg as ImageSource;
return imgSrc;
}
}
This code should work for you.
You can try something like that:
public object Convert(object value, Type targetType, object parameter, string language)
{
byte[] rawImage = value as byte[];
using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
{
writer.WriteBytes((byte[])rawImage);
// The GetResults here forces to wait until the operation completes
// (i.e., it is executed synchronously), so this call can block the UI.
writer.StoreAsync().GetResults();
}
BitmapImage image = new BitmapImage();
image.SetSource(ms);
return image;
}
}
I found the following answer in another thread (Image to byte[], Convert and ConvertBack). I used this solution in a Windows Phone 8.1 project, not sure about Windows Store apps, but I believe it will work.
public object Convert(object value, Type targetType, object parameter, string culture)
{
// Whatever byte[] you're trying to convert.
byte[] imageBytes = (value as FileAttachment).ContentBytes;
BitmapImage image = new BitmapImage();
InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream();
ms.AsStreamForWrite().Write(imageBytes, 0, imageBytes.Length);
ms.Seek(0);
image.SetSource(ms);
ImageSource src = image;
return src;
}

Resources