I have the following code to open gallery.
var imageIntent = new Intent(
Intent.ActionPick);
imageIntent.SetType("image/*");
mageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionGetContent);
StartActivityForResult(
Intent.CreateChooser(imageIntent, "Select photo"), 1);
And I stuck at the following code which is the OnActivityResult in my MainActivity.cs
protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if((requestCode==1)&&(resultCode==Result.Ok))
{
if(data!=null)
{
ClipData clipData = data.ClipData;
if(clipData!=null)
{
for (int i = 0; i < clipData.ItemCount; i++)
{
ClipData.Item item = clipData.GetItemAt(i);
Android.Net.Uri selectedImage = item.Uri;
//How to convert Android.Net.Uri to a image file?
}
}
}
}
}
The Android.Net.Uri is something that I never seen before, the path is just like content/android/document/documents/31857. Yes, I can select multiple photo from the gallery, but I just don't know how to convert Android.Net.Uri to an legal image file? My final goal is to save the selected image to my desired file path like storage/emulated/0... Or is there any better way to select multiple images and save to the desired file? Thank you.
You could use Dependency Service
namespace xxx
{
public interface IPhotoPickerService
{
Task<Dictionary<string,Stream>> GetImageStreamAsync();
}
}
[assembly: Dependency (typeof (PhotoPickerService))]
namespace xxx.iOS
{
public class PhotoPickerService : IPhotoPickerService
{
TaskCompletionSource<Dictionary<string, Stream>> taskCompletionSource;
UIImagePickerController imagePicker;
Task<Dictionary<string, Stream>> IPhotoPickerService.GetImageStreamAsync()
{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};
// Set event handlers
imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
// Return Task object
taskCompletionSource = new TaskCompletionSource<Dictionary<string, Stream>>();
return taskCompletionSource.Task;
}
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;
if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data;
if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
{
data = image.AsPNG();
}
else
{
data = image.AsJPEG(1);
}
Stream stream = data.AsStream();
UnregisterEventHandlers();
Dictionary<string, Stream> dic = new Dictionary<string, Stream>();
dic.Add(args.ImageUrl.ToString(), stream);
// Set the Stream as the completion of the Task
taskCompletionSource.SetResult(dic);
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}
void OnImagePickerCancelled(object sender, EventArgs args)
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}
in MainActivity
public class MainActivity : FormsAppCompatActivity
{
...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
public TaskCompletionSource<Dictionary<string,Stream>> PickImageTaskCompletionSource { set; get; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
Dictionary<string, Stream> dic = new Dictionary<string, Stream>();
dic.Add(uri.ToString(), stream);
// Set the Stream as the completion of the Task
PickImageTaskCompletionSource.SetResult(dic);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
[assembly: Dependency(typeof(PhotoPickerService))]
namespace xxx.Droid
{
public class PhotoPickerService : IPhotoPickerService
{
public Task<Dictionary<string,Stream>> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
// Start the picture-picker activity (resumes in MainActivity.cs)
MainActivity.Instance.StartActivityForResult(
Intent.CreateChooser(intent, "Select Picture"),
MainActivity.PickImageId);
// Save the TaskCompletionSource object as a MainActivity property
MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Dictionary<string,Stream>>();
// Return Task object
return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}
Dictionary<string, Stream> dic = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
Stream stream;
string path;
foreach ( KeyValuePair<string, Stream> currentImage in dic )
{
stream = currentImage.Value;
// save it
}
thanks for you help. Below is my final solution for those who need help.
private string GetPathToImage(Android.Net.Uri uri)
{
string doc_id = "";
using (var c1 = ContentResolver.Query(uri, null, null, null, null))
{
c1.MoveToFirst();
string document_id = c1.GetString(0);
doc_id = document_id.Substring(document_id.LastIndexOf(":") + 1);
}
string path = null;
// The projection contains the columns we want to return in our query.
string selection = Android.Provider.MediaStore.Images.Media.InterfaceConsts.Id + " =? ";
using (var cursor = ContentResolver.Query(Android.Provider.MediaStore.Images.Media.ExternalContentUri, null, selection, new string[] { doc_id }, null))
{
if (cursor == null) return path;
var columnIndex = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
cursor.MoveToFirst();
path = cursor.GetString(columnIndex);
}
return path;
}
After that you can do whatever you want, cheers! Taken from: Get Path of Gallery Image Xamarin?
Here is the iOS implementation for picking multiple photos from Gallery in Xamarin. You will get a list of byte arrays as the result of calling Task<List<byte[]>> PickPhotos(). Android implementation works well in crossmedia plugin by Montemagno but iOS is buggy. This should fix it. I am using the new PHPickerViewController to get this done. Also included a native image resizer routine to size down the photos if needed.
public class PhotoService
{
public override async Task<List<byte[]>> PickPhotos()
{
var imagePicker = new PHPickerViewController(new PHPickerConfiguration
{
Filter = PHPickerFilter.ImagesFilter,
SelectionLimit = 50,
});
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
var tcs = new TaskCompletionSource<Task<List<byte[]>>>();
imagePicker.Delegate = new PPD
{
CompletedHandler = res => tcs.TrySetResult(PickerResultsToMediaFile(res))
};
await vc.PresentViewControllerAsync(imagePicker, true);
var resultTask = await tcs.Task;
var result = await resultTask;
await vc.DismissViewControllerAsync(true);
imagePicker?.Dispose();
return result;
}
private async Task<List<byte[]>> PickerResultsToMediaFile(PHPickerResult[] res)
{
var results = new List<byte[]>();
var tcs = new TaskCompletionSource<NSObject>();
foreach (var item in res)
{
try
{
var provider = item.ItemProvider;
var suggestedName = provider.SuggestedName;
var identifiers = provider?.RegisteredTypeIdentifiers;
var identifier = (identifiers?.Any(i => i.StartsWith(UTType.LivePhoto)) ?? false)
&& (identifiers?.Contains(UTType.JPEG) ?? false)
? identifiers?.FirstOrDefault(i => i == UTType.JPEG)
: identifiers?.FirstOrDefault();
if (string.IsNullOrWhiteSpace(identifier))
continue;
var fileName = $"{provider?.SuggestedName}.{GetTag(identifier, UTType.TagClassFilenameExtension)}";
var stream = (await provider.LoadDataRepresentationAsync(identifier))?.AsStream();
byte[] bytes;
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
bytes = ms.ToArray();
}
results.Add(bytes);
}
catch(Exception)
{
continue;
}
}
return results;
}
public override byte[] ResizeImage(byte[] imageData)
{
float width, height;
UIImage originalImage = ImageFromByteArray(imageData);
if (originalImage == null)
{
return imageData;
}
UIImageOrientation orientation = originalImage.Orientation;
if (originalImage.Size.Width > originalImage.Size.Height)
{
if (originalImage.Size.Width > 1920)
{
width = 1920;
height = 1920 * (float)originalImage.Size.Height / (float)originalImage.Size.Width;
}
else
{
width = (float)originalImage.Size.Width;
height = (float)originalImage.Size.Height;
}
}
else
{
if (originalImage.Size.Height > 1920)
{
height = 1920;
width = 1920 * (float)originalImage.Size.Width / (float)originalImage.Size.Height;
}
else
{
width = (float)originalImage.Size.Width;
height = (float)originalImage.Size.Height;
}
}
//create a 24bit RGB image
using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero,
(int)width, (int)height, 8,
4 * (int)width, CGColorSpace.CreateDeviceRGB(),
CGImageAlphaInfo.PremultipliedFirst))
{
RectangleF imageRect = new RectangleF(0, 0, width, height);
// draw the image
context.DrawImage(imageRect, originalImage.CGImage);
UIImage resizedImage = UIImage.FromImage(context.ToImage(), 0, orientation);
// save the image as a jpeg
return resizedImage.AsJPEG().ToArray();
}
}
public UIImage ImageFromByteArray(byte[] data)
{
if (data == null)
{
return null;
}
UIImage image;
try
{
image = new UIImage(Foundation.NSData.FromArray(data));
}
catch (Exception e)
{
Console.WriteLine("Image load failed: " + e.Message);
return null;
}
return image;
}
protected internal static string GetTag(string identifier, string tagClass)
=> UTType.CopyAllTags(identifier, tagClass)?.FirstOrDefault();
}
class PPD : PHPickerViewControllerDelegate
{
public Action<PHPickerResult[]> CompletedHandler { get; set; }
public override void DidFinishPicking(PHPickerViewController picker, PHPickerResult[] results) =>
CompletedHandler?.Invoke(results?.Length > 0 ? results : null);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.