如何从Xamarin Forms的库中选择多个图像并保存到所需的文件路径?



我有以下代码来打开图库。

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

我坚持使用以下代码,这是我的主活动中的OnActivityResult.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?

}
}
}
}
}

Android.Net.Uri是我以前从未见过的东西,路径就像content/android/document/documents/31857一样。是的,我可以从图库中选择多张照片,但我只是不知道如何将Android.Net.Uri转换为合法的图像文件?我的最终目标是将所选图像保存到我想要的文件路径,例如存储/模拟/0...或者有没有更好的方法来选择多个图像并保存到所需的文件?谢谢。

您可以使用依赖关系服务

在表单中创建界面

namespace xxx
{
public interface IPhotoPickerService
{
Task<Dictionary<string,Stream>> GetImageStreamAsync();
}
}

在 iOS 中

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

}
}

在安卓中

在主活动中

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    
}

感谢您的帮助。以下是我对那些需要帮助的人的最终解决方案。

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

之后你可以做任何你想做的事,干杯!取自:获取图库图像Xamarin的路径?

下面是用于从 Xamarin 中的库中选取多张照片的 iOS 实现。作为调用 Task<byte[]>> PickPhotos(( 的结果,您将获得一个字节数组列表。Android实现在Montemagno的跨媒体插件中运行良好,但iOS有问题。这应该可以解决它。 我正在使用新的PHPickerViewController来完成这项工作。还包括一个本机图像缩放器例程,可根据需要缩小照片大小。

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

最新更新