Problems selecting a photo or image from the cell phone - c#

I have a problem with views, when I open the camera and take the photo it sends me directly to the home screen, the same happens with an image of the gallery, this only happens with ios, since Android works without any problem. I would like to know what is happening because I have not found the error.
public async Task TakePicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Error", "No se encontro una cámara disponible.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
SaveToAlbum = false,
CompressionQuality = 30,
PhotoSize = PhotoSize.Small
});
if (file == null)
{
return;
}
byte[] array;
using (var memoryStream = new MemoryStream())
{
int count = 0;
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
while (count < 10)
{
if (array.Count() == 0)
{
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
await Task.Delay(1000);
}
count++;
}
}
Stream stream = new MemoryStream(array);
var image = ImageSource.FromStream(() => stream);
FotoPerfil = image;
User.Foto = array;
}
This part is to take the photo directly from the cell phone, I have no problem opening the camera, the error comes when I choose that photo sends me to another screen, I do not know if it is closing and reopening the application but I do not know what happens.
public async Task PickPicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Error",
"No se otorgaron permisos para accesar a las fotos.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
PhotoSize = PhotoSize.Medium,
CompressionQuality = 30,
});
if (file == null)
{
return;
}
byte[] array;
using (var memoryStream = new MemoryStream())
{
int count = 0;
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
while (count < 10)
{
if (array.Count() == 0)
{
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
await Task.Delay(1000);
}
count++;
}
}
await Application.Current.MainPage.DisplayAlert("Error", array.ToString(), "OK");
User.Foto = array;
Stream stream = new MemoryStream(array);
var image = ImageSource.FromStream(() => stream);
FotoPerfil = image;
}
The latter is to select any image from the gallery, and exactly the same happens.

Related

Xamarin forms display an image issue

I use a photo picker to let the user choose a profile pic and then I want to display the pic inside of an Image view. the following code works fine for me but then I would like to convert the image to a byte array, once I call the method to convert it the image doesn't display after the user picks it. I also tried to call the method outside the try and catch but no luck.
the image is getting selected (it's getting saved in local storage) so the only issue is that for some reason it doesn't display it in the view.
async void showMediaPicker()
{
var res = await MediaPicker.PickPhotoAsync();
try
{
var stream = await res.OpenReadAsync();
var finalImage = ImageSource.FromStream(() => stream);
myImage.Source = finalImage;
imgBytes = ImageSourceToBytes(finalImage);
}
catch (Exception e)
{
Console.Write("error" + e.Message) ;
}
}
If you want to convert the photo to Byte array , you could use the plugin Media.Plugin from Nuget to pick or take photo . Don't forget to add the relevant permissions on android and iOS platform .
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = "test.jpg"
});
if (file == null)
return;
Then convert it to Stream firstly before convert it to byte array .
Stream stream = file.GetStream();
public byte[] GetImageStreamAsBytes(Stream input)
{
var buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Now you can get the byte array like following
var imgDate = GetImageStreamAsBytes(stream);

Convert imageSource coming from Xam.Plugin.Media 5.0.1 to byte array in Xamarinforms?

if (!CrossMedia.Current.IsPickPhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Photos Not Supported", ":( Permission not granted to photos.", "OK");
return;
}
var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
});
if (file == null)
return;
var tmpSrc = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
ImageSource toBeConverted = tmpSrc;
I want the variable toBeConverted to be converted into Byte[] so
that I can send it to my webapi ...
ImageSource is a way to provide a source image for Xamarin.Forms.Image to show some content. If you're already showing something on the screen your Image view was populated with data that came from elsewhere, such as a file or resource or stored in an array in memory... or however else you got that in the first place. Instead of trying to get that data back from ImageSource you can keep a reference to it and upload it as needed.
So you could get the byte array from the file after you pick the photo.
var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
});
if (file == null)
return;
var bytes = File.ReadAllBytes(file.Path); // you could get the byte[] here from the file path.
This code also worked for me ...
private async void Capture()
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Test",
SaveToAlbum = true,
CompressionQuality = 75,
CustomPhotoSize = 50,
PhotoSize = PhotoSize.Medium,
DefaultCamera = CameraDevice.Front
});
if (file == null)
return;
var stream = file.GetStream();
if (stream != null)
{
var StreamByte = ReadAllBytes(stream);
var NewStream = new MemoryStream(StreamByte);
// stream = mystream;
Device.BeginInvokeOnMainThread(() => {
ImageSource = ImageSource.FromStream(() => NewStream);
});
student.ProfilePicture = StreamByte;
}
}
public byte[] ReadAllBytes(Stream instream)
{
if (instream is MemoryStream)
return ((MemoryStream)instream).ToArray();
using (var memoryStream = new MemoryStream())
{
instream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}

How to integrate Xamarin.Plugin.ImageEdit with user interface?

I'm trying to add an image cropper to my app and have found Xamarin.Plugin.ImageEdit, that seems to be a good way to start on it, but the problem is that I couldn't find any example of how to show the image and the square over it to cut the image, in other words, integrate it with UI. Does anyone here have used ImageEdit and can tell me how to do it?
What I have so far:
async void Init()
{
MediaFile a = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
CompressionQuality = 80,
RotateImage = true
});
byte[] imageArray = await Task.Run(()=>ImagePath2ByteArray(a));
using (var image = await CrossImageEdit.Current.CreateImageAsync(imageArray))
{
var croped = await Task.Run(() =>
image.Crop(10, 20, 250, 100)
.Rotate(180)
.Resize(100, 0)
.ToPng()
);
}
}
async Task<byte[]> ImagePath2ByteArray(MediaFile a)
{
byte[] imageArray = null;
if (a != null)
{
using (MemoryStream ms = new MemoryStream())
{
var stream = a.GetStream();
stream.CopyTo(ms);
imageArray = ms.ToArray();
}
}
return imageArray;
}
It seems to work fine but doesn't have UI.

Xamarin Forms saving image in sqlite database

How do I save an image I captured directly to sqlite(sqlite-net-pcl) database?
Here's my code but it can only save in "Internal Storage" of the phone.
private async void TakePhotoButton_Clicked(object sender, EventArgs e)
{
try
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", "No Camera Available", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions
{
SaveToAlbum = true,
//Directory = "Sample",
//Name = "Test.jpg"
});
if (file == null)
return;
PathLabel.Text = file.AlbumPath;
MainImage.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
catch (Exception ex)
{
await DisplayAlert("error", ex.ToString(), "OK");
}
}
You should convert the stream to Byte array so that you save them to sqlite.
public byte[] GetImageStreamAsBytes(Stream input)
{
var buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
var imgDate = GetImageStreamAsBytes(file.GetStream());
Concerning the SaveToAlbum option
This will restult in 2 photos being saved for the photo. One in your private folder and one in a public directory that is shown. The value will be returned at AlbumPath. (Source)
Unless you really need the photo in the camera roll, there is no need to use SaveToAlbum.
Anyway, the file is still saved to your apps sandbox (the part of the devices storage that is reserved exclusively for your app) and you can retrieve the path with file.Path.
Having said that, it's easy to obtain the binary data representing your image
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", "No Camera Available", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions());
if (file == null)
return;
var imageData = File.ReadAllBytes(file.Path);
Obviously (see here and here) it's possibly to store binary data (BLOBs) in an SQLite database. The simplest conceivable model to store an image in the database would be something like
class Image
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public byte[] Data { get; set; }
}
Assuming that _imageRepository is your repository abstraction you are saving the images in, the data could be saved as
// ...
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions());
if (file == null)
return;
var imageData = File.ReadAllBytes(file.Path);
_imageRepository.Add(new Image()
{
Data = imageData
});
Later on, to display the image, you can get the Image from the repository and use the Data property, e.g. by passing it to a MemoryStream (if you need a stream)
// example: Loading by ID, loading all images is conceivable, too
var image = _imageRepository.LoadImage(id);
ImageControl.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.Data));

Images in Windows Phone 8.1 livetiles aren't sharp

I create livetiles with the following code:
// wide 310x150
var tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150PeekImage03);
tileXml.GetElementsByTagName(textElementName).LastOrDefault().InnerText = string.Format(artist + " - " + trackname);
var image = tileXml.GetElementsByTagName(imageElementName).FirstOrDefault();
if (image != null)
{
var src = tileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_wide.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
// square 150x150
var squaredTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150PeekImageAndText01);
squaredTileXml.GetElementsByTagName(textElementName).FirstOrDefault().InnerText = string.Format(artist + " - " + trackname);
image = squaredTileXml.GetElementsByTagName(imageElementName).LastOrDefault();
if (image != null)
{
var src = squaredTileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_square.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
updater.Update(new TileNotification(tileXml));
updater.Update(new TileNotification(squaredTileXml));
The problem I face is that the images shown on the livetile aren't sharp (in the app they are). I think this is because of the 310x150 pixels size of the template. I looked at the templates, there aren't any higher resolution ones. Is there a way to make the images sharper?
I noticed that providing an image with a resolution of exactly 744x360 pixels solves the problem. So I wrote this function to resize my albumarts (maybe it will come in handy for someone);
private async static Task<string> CropAndSaveImage(string filePath)
{
const string croppedimage = "cropped_albumart.jpg";
// read file
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return String.Empty;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
using (InMemoryRandomAccessStream writeStream = new InMemoryRandomAccessStream())
{
// create encoder
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(writeStream, decoder);
enc.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
// convert the entire bitmap to a 744px by 744px bitmap
enc.BitmapTransform.ScaledHeight = 744;
enc.BitmapTransform.ScaledWidth = 744;
enc.BitmapTransform.Bounds = new BitmapBounds()
{
Height = 360,
Width = 744,
X = 0,
Y = 192
};
await enc.FlushAsync();
StorageFile albumartfile = await ApplicationData.Current.LocalFolder.CreateFileAsync(croppedimage, CreationCollisionOption.ReplaceExisting);
using (var stream = await albumartfile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(writeStream.GetInputStreamAt(0), stream.GetOutputStreamAt(0));
}
// return image path
return albumartfile.Path;
}
}

Categories