Best approach to download image - 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;
}

Related

Save image locally and then save file path as a string into a database in Xamarin Forms

How do i after i take a picture/ select an image (either will overwrite the same image variable regardless), save the image locally and then save the file path as a string into a variable to be inserted into an existing SQLite db.
I had the same exact issue-
Here's how I got it to work
First, in your model where you've created the columns for your tables, make sure there is a property for the string that will be the imagepath
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Image { get; set; }
Then we need a method to upload and save your Image locally and another to get the file path and set it to a string. Assuming this will be in your code-behind, first add these:
public static string photofilename;
public static string imagePath;
static SQLiteConnection db;
YourModel yourmodel = new YourModel();
Then the LoadPhoto method
async void LoadPhotoAsync(FileResult photo)
{
// canceled
string PhotoPath;
if (photo == null)
{
PhotoPath = null;
return;
}
// save the file into local storage
var newFile = Path.Combine(FileSystem.AppDataDirectory, photo.FileName);
using (var stream = await photo.OpenReadAsync())
using (var newStream = File.OpenWrite(newFile))
await stream.CopyToAsync(newStream);
PhotoPath = newFile;
}
Then a method to upload/save the photo (In this case I'm having the user upload from the device) which I have attached to an Upload Image button. In this method, I display the image to the Image in my XAML called ImageViewer, but this might not be necessary for you.
async void Image_ClickedAsync(System.Object sender, System.EventArgs e)
{
try
{
var photo = await MediaPicker.PickPhotoAsync();
LoadPhotoAsync(photo);
photofilename = photo.FileName;
imagePath = Path.Combine(FileSystem.AppDataDirectory, photofilename);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature is not supported on the device
}
catch (PermissionException pEx)
{
// Permissions not granted
}
catch (Exception ex)
{
Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
}
ImageViewer.Source = imagePath;
ImageViewer.IsVisible = true;
}
What this has done is open up MediaPicker, Allow the user to choose an Image and set the Image Path to the string imagePath. In my case here, I also have "ImageViewer" which is an Image in my XAML used to display the image, but we're not done yet- we haven't yet saved it to your SQLite db. Here's the method I used attached to a "Save" button-
private void SaveEvent(object sender, EventArgs e)
{
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "yourdb.db");
db = new SQLiteConnection(databasePath);
yourmodel.Image = imagePath;
db.Insert(yourmodel);
}
Then, assuming your using ListView or something bound to the Tables in the db, you'll have an image in your XAML like so
<Image HeightRequest="340" WidthRequest="550" x:Name="Image" Source="{Binding Image}"/>
and that should do the trick- Let me know if this works for you!

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

Xamarin Forms - Image to String and reverse

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

How to convert image to base64 string in Windows Phone?

I am developing a windows phone application in which I have to convert image to base64 string and I have to pass that string through Web Service. So I tried many Ways, but I cant able to send it as everytime I am getting error as "Target Invocation error". With this code I can choose the image from library but I cant send through web service.
I used the following code to covert the image:
private void photoChooserTask_Completed(object sender, PhotoResult e)
{
BitmapImage image = new BitmapImage();
image.SetSource(e.ChosenPhoto);
this.imageTribute.Source = image;
byte[] bytearray = null;
using (MemoryStream ms = new MemoryStream())
{
if (imageTribute.Source == null)
{
}
else
{
WriteableBitmap wbitmp = new WriteableBitmap((BitmapImage)imageTribute.Source);
wbitmp.SaveJpeg(ms, 40, 40, 0, 82);
bytearray = ms.ToArray();
}
}
strimage = Convert.ToBase64String(bytearray);
}
So please if anyone knows about that, help me out. Thanx in advance.
EDIT
void uploadphoto()
{
WebClient webClient1 = new WebClient();
webClient1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient1_DownloadStringCompleted);
webClient1.DownloadStringAsync(new Uri("Web Service"));
}
void webClient1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var rootobject1 = JsonConvert.DeserializeObject<RootObject1>(e.Result);
int error = rootobject1.response.errorFlag;
string message = rootobject1.response.msg;
if (error == 0)
{
MessageBox.Show(message);
}
else
{
MessageBox.Show(message);
}
}
public class Response1
{
public int errorFlag { get; set; }
public string msg { get; set; }
public List<string> uploadedImageNames { get; set; }
}
public class RootObject1
{
public Response1 response { get; set; }
}
private void ImageUpload(object sender, RoutedEventArgs e)
{
//MessageBoxResult mb = MessageBox.Show("Select the mode of uploading the picture", "", MessageBoxButton.OKCancel);
Popup popup = new Popup();
photoSelection photo = new photoSelection();
popup.Child = photo;
popup.IsOpen = true;
photo.camera.Click += (s, args) =>
{
photoCameraCapture.Show();
popup.IsOpen = false;
};
photo.library.Click += (s, args) =>
{
photoChooserTask.Show();
popup.IsOpen = false;
};
}
EDIT
Here I uploaded the stack trace of my error. So please check and reply me.
A Target Invocation Exception error tells you that the application crashed while invoking a method which could be many things. The real error is in the InnerException.
Look at the InnerException property of the TargetInvocationException object. This will show you the stack trace and the actual error thrown.
Get your file into stream either from resource or from isolatedStorage
//getting file from resource
var resource = Application.GetResourceStream(new Uri("image.jpg", UriKind.Relative));
//get Stream Data
StreamReader streamReader = new StreamReader(resource.Stream);
//initializing bytearray to stream length
byte[] imageData = new byte[streamReader.Length];
//wriing from stream to imagdata
streamReader.Read(imageData, 0, imageData.Length);
streamReader.Close();
Use isolatedStorageFile to read from isolated storage
now you have your image data in imageData and to convert it into base64 use:
var baseString = Convert.ToBase64String(imageData);

Resources