Adding a MediaPicker image to ListView causes System.ObjectDisposedException - image

I have a form to fill in with data including an image which then goes into a listview. When I click on a button to get an image it works and it goes into the form, however when I click on another button to add it to the listview, the error [System.ObjectDisposedException: 'Cannot access a disposed object.
Object name: 'Stream has been closed'] appears.
Thanks for your help
When I press the add image button :
var ActionPhoto = await DisplayActionSheet("Ajouter une pièce-jointe depuis:", "Annuler", null, "Galerie", "Caméra");
switch (ActionPhoto)
{
case "Galerie":
var Galerie = await MediaPicker.PickPhotoAsync(new MediaPickerOptions { Title = "Choisir une image" });
if (Galerie != null)
{
var voirImageGalerie = await Galerie.OpenReadAsync();
Image_Photos.Source = ImageSource.FromStream(() => voirImageGalerie);
}
break;
case "Caméra":
var camera = await MediaPicker.CapturePhotoAsync();
if (camera != null)
{
var voirImageCamera = await camera.OpenReadAsync();
Image_Photos.Source = ImageSource.FromStream(() => voirImageCamera);
}
break;
}
When I press the add button of the listView:
App.listePosteNoteFrais.Add(new Data{PostePJ = Image_Photos.Source});
In my Data Class:
public ImageSource PostePJ { get; set; }
What I'm adding to my listview:
<Image x:Name="Image_PostePJ" Source="{Binding PostePJ}" HeightRequest="150" WidthRequest="150" Grid.Row="0" Grid.Column="12"/>

Given code:
ImageSource.FromStream(() => voirImageCamera)
The parameter to FromStream:
() => voirImageCamera
is executed every time the image is needed.
The exception message:
System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'Stream has been closed.
Is telling you that the stream (voirImageCamera) is no longer useable.
I'm not sure what internal code is disposing that stream. Maybe MediaPicker thinks its no longer needed. Or maybe its due to copying from one image source to another. Or something about how/when ListView accesses the image source.
As seen in doc Xamarin.Essentials: Media Picker / General Usage, a safe way to use a result from MediaPicker's OpenReadAsync, is to save the stream in a local file, then use that file as the image source:
// save the file into local storage
var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
using (var stream = await photo.OpenReadAsync())
using (var newStream = File.OpenWrite(newFile))
await stream.CopyToAsync(newStream);
Then set the image source to that file:
Image_Photos.Source = ImageSource.FromFile(newFile);
The advantage of FromFile, is that it should be able to open the file at any time it needs - there is no stream being held open.
NOTE: The doc example uses CacheDirectory. Depending on the situation, FileSystem.AppDataDirectory might be more appropriate (files that should be kept indefinitely).

Related

Xamarin Forms Convert from Image to Base64 from Image Control not from file

I am loading an image from the camera into an Image control. That works beautifully as shown below.
var photo = await Plugin.Media.CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions() { });
if (photo != null)
PhotoImageRear.Source = ImageSource.FromStream(() => { return photo.GetStream(); });
I sometime later need to take the images loaded into that PhotoImageRear control and convert it to a base64 string in order to post it to an API.
What would be the most efficient way of achieving that.
Thanks in advance for your help
From shared code ,once you get the photo, you can use the following code to convert to Base64 .
var stream = photo.GetStream();
var bytes = new byte [stream.Length];
await stream.ReadAsync(bytes, 0, (int)stream.Length);
string base64 = System.Convert.ToBase64String(bytes);

How can I auto save a captured image in a UWP app?

I have this code:
CameraCaptureUI captureUI = new CameraCaptureUI();
captureUI.PhotoSettings.AllowCropping = false;
StorageFile photo = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
How can I implement to auto save image option when click on the capture button?
How can I implement to auto save image option when click on the capture button?
The StorageFile containing the captured photo is given a dynamically generated name and saved in our app's local folder if we do not cancel the capture, so if we click on the capture button without clicking the confirm button, the photo will be saved automatically in our app's TempState folder.
For more info, refer Capture photos and video with Windows built-in camera UI.
To better organize your captured photos, you may want to move the file to a different folder. Please refer to the following sample which shows how to copy the latest capture photo from the TempState folder to the LocalFolder.
For example:
CameraCaptureUI captureUI = new CameraCaptureUI();
captureUI.PhotoSettings.AllowCropping = false;
StorageFile photo = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.TemporaryFolder;
var allFiles =await localFolder.GetFilesAsync();
foreach (StorageFile item in allFiles.OrderByDescending(a => a.DateCreated))
{
StorageFolder destinationFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("ProfilePhotoFolder", CreationCollisionOption.OpenIfExists);
await item.CopyAsync(destinationFolder, DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + ".jpg", NameCollisionOption.ReplaceExisting);
await item.DeleteAsync();
return;
}

MvvmCross.Plugins.File: A Downloaded and locally stored image is not displayed in MvxImageView

I save an image from the internet like this:
public void SetSelectedConsultant(string consultantId)
{
// ...
var path = this.fileStore.PathCombine(App.IMAGES_FOLDER, App.SELECTED_CONSULTANT_IMAGE_FILENAME);
if (this.fileStore.Exists(path))
{
this.fileStore.DeleteFile(path);
}
this.fileStore.EnsureFolderExists(App.IMAGES_FOLDER);
this.GeneralAsyncLoad(
App.SERVER_URL + App.CONSULTANT_FILE_NAME,
stream =>
{
this.SaveConsultantImage(stream, path);
this.mvxMessenger.Publish(new ConsultantUpdatedMessage(this));
});
}
private void SaveConsultantImage(Stream stream, string path)
{
var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
byte[] pictureBytes = memoryStream.ToArray();
this.fileStore.WriteFile(path, pictureBytes);
}
ConsultantUpdatedMessage is caught by my view model which will RaisePropertyChanged for ConsultantImageUrl. My other properties like ConsultantName etc. are refreshed correctly in the view, but the image refuses to show in the control:
<Mvx.MvxImageView
android:scaleType="fitXY"
android:layout_margin="5dp"
android:layout_width="220dp"
android:layout_height="wrap_content"
local:MvxBind="ImageUrl ConsultantImageUrl" />
I checked if the file exists, usin fileStore.Exists, which results "true", but the file won't show up. Is it possible I save the picture the wrong way?
EDIT: As a how-to, I used this tutorial (https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-16-CollectABull-Part5). However, there they use a photo from the local album instead of downloading one.
I found the problem. The url was wrong and it downloaded another (none-image) file and saved it. So a file was existing there, but could not be displayed in the view because it was not an image.

swf loading on top of each other in flash

I have a flash file, (banner ad) and i need to have an image gallery and an flv player, which i have. to save space i've used a loader to call them via their swf file using a button. but when i do this it calls the swf on top of my main flash page constantly layering more and more pages on top of each other.
heres is my loader code:
var loadedSWF:Loader = null;
var req:URLRequest = new URLRequest("imagegallery.swf");
loadedSWF = new Loader();
loadedSWF.load(req);
function loadSWF(file:String, container:MovieClip=null):void
{
if(container == null) container = MovieClip(root);
// removes the previously loaded SWF
if(loadedSWF != null)
{
if(loadedSWF.parent) loadedSWF.parent.removeChild(loadedSWF);
}
addChild(loadedSWF);
}
imageGallery_btn.addEventListener(MouseEvent.CLICK, _click);
function _click(e:MouseEvent):void
{
loadSWF("imagegallery.swf");
}
It's some code i found on this website.

How do you convert a HttpPostedFileBase to an Image?

I am using ASP.NET MVC and I've an action that uploads the file. The file is being uploaded properly. But I want width and height of the image. I think I need to convert the HttpPostedFileBase to Image first and then proceed. How do I do that?
And please let me know if there is another better way to get the width and height of the image.
I use Image.FromStream to as follows:
Image.FromStream(httpPostedFileBase.InputStream, true, true)
Note that the returned Image is IDisposable.
You'll need a reference to System.Drawing.dll for this to work, and Image is in the System.Drawing namespace.
Resizing the Image
I'm not sure what you're trying to do, but if you happen to be making thumbnails or something similar, you may be interested in doing something like...
try {
var bitmap = new Bitmap(newWidth,newHeight);
using (Graphics g = Graphics.FromImage(bitmap)) {
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(oldImage,
new Rectangle(0,0,newWidth,newHeight),
clipRectangle, GraphicsUnit.Pixel);
}//done with drawing on "g"
return bitmap;//transfer IDisposable ownership
} catch { //error before IDisposable ownership transfer
if (bitmap != null) bitmap.Dispose();
throw;
}
where clipRectangle is the rectangle of the original image you wish to scale into the new bitmap (you'll need to manually deal with aspect ratio). The catch-block is typical IDisposable usage inside a constructor; you maintain ownership of the new IDisposable object until it is returned (you may want to doc that with code-comments).
Saving as Jpeg
Unfortunately, the default "save as jpeg" encoder doesn't expose any quality controls, and chooses a terribly low default quality.
You can manually select the encoder as well, however, and then you can pass arbitrary parameters:
ImageCodecInfo jpgInfo = ImageCodecInfo.GetImageEncoders()
.Where(codecInfo => codecInfo.MimeType == "image/jpeg").First();
using (EncoderParameters encParams = new EncoderParameters(1))
{
encParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);
//quality should be in the range [0..100]
image.Save(outputStream, jpgInfo, encParams);
}
If you are sure, that the source is image and doesn't need editing, you can do it easily as described here
[HttpPost]
public void Index(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var filename = Path.GetFileName(file.FileName);
System.Drawing.Image sourceimage =
System.Drawing.Image.FromStream(file.InputStream);
}
}
To secure the file is image, add javascript validation to View by adding accept attribute with MIME type to input tag
<input type="file" accept="image/*">
and jQuery validation script
$.validator.addMethod('accept', function () { return true; });
The whole solution can be found here

Resources