private void Handle_PickedImages(object sender, MultiAssetEventArgs e) { ImageEntries = new List <ImageEntry>(); var phAssetArray = e.Assets; var manager = PHImageManager.DefaultManager; using (var options = new PHImageRequestOptions { Synchronous = true, DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat, ResizeMode = PHImageRequestOptionsResizeMode.Exact }) { foreach (var asset in phAssetArray) { if (asset.MediaType == PHAssetMediaType.Video) { HandleVideoSelected(); return; } manager.RequestImageForAsset(asset, new CGSize(asset.PixelWidth, asset.PixelHeight), PHImageContentMode.Default, options, (result, info) => { var resources = PHAssetResource.GetAssetResources(asset); var name = resources != null && resources.Length > 0 ? resources[0].OriginalFilename : string.Empty; ImageEntries.Add(new ImageEntry(result.ToSKImage(), name, (DateTime)asset.CreationDate, null)); }); } LaunchAnalysisScreen(ImageEntries); } }
private static void StoreImageData(PHAsset asset, int quality, float scale, bool rotate, MediaFile tempMedia, NSDictionary info, NSData data, TaskCompletionSource <string> tcs) { var targetDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal); try { var error = (NSError)info["PHImageErrorKey"]; if (error != null) { var description = error.LocalizedDescription; var reason = error.UserInfo.ValueForKey((NSString)"NSUnderlyingError"); throw new Exception($"{description}. {reason}"); } var resources = PHAssetResource.GetAssetResources(asset); var orgFilename = resources[0].OriginalFilename; orgFilename = orgFilename.EndsWith(".JPG", StringComparison.OrdinalIgnoreCase) ? orgFilename : $"{orgFilename}.JPG"; var path = Path.Combine(targetDir, orgFilename); var fullimage = CIImage.FromData(data); var image = UIImage.LoadFromData(data); var scaledImage = image.ScaleImage(scale); if (rotate) { scaledImage = scaledImage.RotateImage(); } SaveTempImage(fullimage, scaledImage, path, quality, rotate); var dateString = fullimage.Properties.Exif?.Dictionary?.ValueForKey(ImageIO.CGImageProperties.ExifDateTimeOriginal)?.ToString(); if (dateString != null) { tempMedia.MediaTakenAt = DateTime.ParseExact(dateString, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture); } else { tempMedia.MediaTakenAt = null; } int.TryParse(fullimage.Properties?.Orientation.ToString(), out tempMedia.Orientation); tempMedia.Latitude = fullimage.Properties?.Gps?.Latitude; tempMedia.LatitudeRef = fullimage.Properties?.Gps?.Dictionary.ValueForKey(ImageIO.CGImageProperties.GPSLatitudeRef).ToString() ?? string.Empty; tempMedia.Longitude = fullimage.Properties?.Gps?.Longitude; tempMedia.LongitudeRef = fullimage.Properties?.Gps?.Dictionary.ValueForKey(ImageIO.CGImageProperties.GPSLongitudeRef).ToString() ?? string.Empty; tcs.TrySetResult(path); } catch (Exception ex) { tcs.TrySetException(ex); } }
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) { var cell = (GMGridViewCell)CollectionView.DequeueReusableCell(GMGridViewCellIdentifier, indexPath); var asset = (PHAsset)AssetsFetchResults[indexPath.Item]; if (cell != null) { // Increment the cell's tag var currentTag = cell.Tag + 1; cell.Tag = currentTag; _imageManager.RequestImageForAsset(asset, AssetGridThumbnailSize, PHImageContentMode.AspectFill, new PHImageRequestOptions { DeliveryMode = PHImageRequestOptionsDeliveryMode.Opportunistic, ResizeMode = PHImageRequestOptionsResizeMode.Fast }, (image, info) => { // Only update the thumbnail if the cell tag hasn't changed. Otherwise, the cell has been re-used. if (cell.Tag == currentTag && cell.ImageView != null && image != null) { cell.ImageView.Image = image; } }); } cell.Bind(asset); cell.ShouldShowSelection = _picker.AllowsMultipleSelection; // Optional protocol to determine if some kind of assets can't be selected (long videos, etc...) cell.IsEnabled = _picker.VerifyShouldEnableAsset(asset); if (_picker.SelectedAssets.Contains(asset)) { cell.Selected = true; CollectionView.SelectItem(indexPath, false, UICollectionViewScrollPosition.None); } else { cell.Selected = false; } var resources = PHAssetResource.GetAssetResources(asset); var name = resources != null && resources.Length > 0 ? resources[0].OriginalFilename : string.Empty; ConfigureSelectCellAccessibilityAttributes(cell, cell.Selected, name); return(cell); }
private static string StorePickedVideo(PHAsset asset) { var tcs = new TaskCompletionSource <string>(); var task = tcs.Task; var imageManager = PHImageManager.DefaultManager; using (var requestOptions = new PHVideoRequestOptions { NetworkAccessAllowed = true, DeliveryMode = PHVideoRequestOptionsDeliveryMode.MediumQualityFormat }) { imageManager.RequestExportSession(asset, requestOptions, AVAssetExportSession.PresetPassthrough, (exportSession, info) => { Task.Factory.StartNew(async() => { var targetDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal); var error = (NSError)info["PHImageErrorKey"]; if (error != null) { var description = error.LocalizedDescription; var reason = error.UserInfo.ValueForKey((NSString)"NSUnderlyingError"); tcs.SetException(new FileLoadException($"{description}. {reason}")); return; } var resources = PHAssetResource.GetAssetResources(asset); var orgFilename = resources[0].OriginalFilename; var path = Path.Combine(targetDir, orgFilename); File.Delete(path); exportSession.OutputUrl = new NSUrl($"file://{path}"); exportSession.OutputFileType = AVFileType.Mpeg4; await exportSession.ExportTaskAsync(); if (exportSession.Status == AVAssetExportSessionStatus.Completed) { tcs.TrySetResult(path); } else { tcs.SetException(new Exception(exportSession.Error.Description)); } }); }); } return(task.Result); }
private void RefreshResources() { var resources = PHAssetResource.GetAssetResources(Asset); var list = new List <PHAssetResource>(resources.Length); foreach (var resource in resources) { if (resource.ResourceType == PHAssetResourceType.Photo || resource.ResourceType == PHAssetResourceType.Video || resource.ResourceType == PHAssetResourceType.Audio) { FileName = resource.OriginalFilename; } list.Add(resource); } Resources = list.AsReadOnly(); }
private void RefreshResources() { var resources = PHAssetResource.GetAssetResources(Asset); var list = new List <PHAssetResource>(resources.Length); foreach (var resource in resources) { if (resource.ResourceType == PHAssetResourceType.Photo || resource.ResourceType == PHAssetResourceType.Video || resource.ResourceType == PHAssetResourceType.Audio) { var dtstr = CreationDate.ToLocalTime().ToString("yyyy-MM-dd HH_mm"); FileName = $"{dtstr} {resource.OriginalFilename}"; } list.Add(resource); } Resources = list.AsReadOnly(); }
static FileResult DictionaryToMediaFile(NSDictionary info) { if (info == null) { return(null); } PHAsset phAsset = null; NSUrl assetUrl = null; if (Platform.HasOSVersion(11, 0)) { assetUrl = info[UIImagePickerController.ImageUrl] as NSUrl; // Try the MediaURL sometimes used for videos if (assetUrl == null) { assetUrl = info[UIImagePickerController.MediaURL] as NSUrl; } if (assetUrl != null) { if (!assetUrl.Scheme.Equals("assets-library", StringComparison.InvariantCultureIgnoreCase)) { return(new UIDocumentFileResult(assetUrl)); } phAsset = info.ValueForKey(UIImagePickerController.PHAsset) as PHAsset; } } if (phAsset == null) { assetUrl = info[UIImagePickerController.ReferenceUrl] as NSUrl; if (assetUrl != null) { phAsset = PHAsset.FetchAssets(new NSUrl[] { assetUrl }, null)?.LastObject as PHAsset; } } if (phAsset == null || assetUrl == null) { var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage; var imgUrl = info.ValueForKey(UIImagePickerController.ImageUrl) as NSString; if (img != null) { var rotatedImg = CorrectImageRotation(img); return(new UIImageFileResult(rotatedImg ?? img)); } } if (phAsset == null || assetUrl == null) { return(null); } string originalFilename; if (Platform.HasOSVersion(9, 0)) { originalFilename = PHAssetResource.GetAssetResources(phAsset).FirstOrDefault()?.OriginalFilename; } else { originalFilename = phAsset.ValueForKey(new NSString("filename")) as NSString; } return(new PHAssetFileResult(assetUrl, phAsset, originalFilename)); }
static FileResult DictionaryToMediaFile(NSDictionary info) { if (info == null) { return(null); } PHAsset phAsset = null; NSUrl assetUrl = null; if (OperatingSystem.IsIOSVersionAtLeast(11, 0)) { assetUrl = info[UIImagePickerController.ImageUrl] as NSUrl; // Try the MediaURL sometimes used for videos if (assetUrl == null) { assetUrl = info[UIImagePickerController.MediaURL] as NSUrl; } if (assetUrl != null) { if (!assetUrl.Scheme.Equals("assets-library", StringComparison.OrdinalIgnoreCase)) { return(new UIDocumentFileResult(assetUrl)); } phAsset = info.ValueForKey(UIImagePickerController.PHAsset) as PHAsset; } } #if !MACCATALYST if (phAsset == null) { assetUrl = info[UIImagePickerController.ReferenceUrl] as NSUrl; if (assetUrl != null) { phAsset = PHAsset.FetchAssets(new NSUrl[] { assetUrl }, null)?.LastObject as PHAsset; } } #endif if (phAsset == null || assetUrl == null) { var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage; if (img != null) { return(new UIImageFileResult(img)); } } if (phAsset == null || assetUrl == null) { return(null); } string originalFilename = PHAssetResource.GetAssetResources(phAsset).FirstOrDefault()?.OriginalFilename; return(new PHAssetFileResult(assetUrl, phAsset, originalFilename)); }
async void FinishedPickingAssets(object sender, MultiAssetEventArgs args) { IList <MediaFile> results = new List <MediaFile>(); TaskCompletionSource <IList <MediaFile> > tcs = new TaskCompletionSource <IList <MediaFile> >(); var options = new Photos.PHImageRequestOptions() { NetworkAccessAllowed = true }; options.Synchronous = false; options.ResizeMode = PHImageRequestOptionsResizeMode.Fast; options.DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat; bool completed = false; for (var i = 0; i < args.Assets.Length; i++) { var asset = args.Assets[i]; string fileName = string.Empty; if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { fileName = PHAssetResource.GetAssetResources(asset).FirstOrDefault().OriginalFilename; } switch (asset.MediaType) { case PHAssetMediaType.Video: PHImageManager.DefaultManager.RequestImageForAsset(asset, new SizeF(150.0f, 150.0f), PHImageContentMode.AspectFill, options, async(img, info) => { var startIndex = fileName.IndexOf(".", StringComparison.CurrentCulture); string path = ""; if (startIndex != -1) { path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, $"{fileName.Substring(0, startIndex)}-THUMBNAIL.JPG"); } else { path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, string.Empty); } if (!File.Exists(path)) { img.AsJPEG().Save(path, true); } TaskCompletionSource <string> tvcs = new TaskCompletionSource <string>(); var vOptions = new PHVideoRequestOptions(); vOptions.NetworkAccessAllowed = true; vOptions.Version = PHVideoRequestOptionsVersion.Original; vOptions.DeliveryMode = PHVideoRequestOptionsDeliveryMode.FastFormat; PHImageManager.DefaultManager.RequestAvAsset(asset, vOptions, (avAsset, audioMix, vInfo) => { var vPath = FileHelper.GetOutputPath(MediaFileType.Video, TemporalDirectoryName, fileName); if (!File.Exists(vPath)) { AVAssetExportSession exportSession = new AVAssetExportSession(avAsset, AVAssetExportSession.PresetHighestQuality); exportSession.OutputUrl = NSUrl.FromFilename(vPath); exportSession.OutputFileType = AVFileType.QuickTimeMovie; exportSession.ExportAsynchronously(() => { Console.WriteLine(exportSession.Status); tvcs.TrySetResult(vPath); //exportSession.Dispose(); }); } }); var videoUrl = await tvcs.Task; var meFile = new MediaFile() { Type = MediaFileType.Video, Path = videoUrl, PreviewPath = path }; results.Add(meFile); OnMediaPicked?.Invoke(this, meFile); if (args.Assets.Length == results.Count && !completed) { completed = true; tcs.TrySetResult(results); } }); break; default: Photos.PHImageManager.DefaultManager.RequestImageData(asset, options, (data, dataUti, orientation, info) => { string path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, fileName); if (!File.Exists(path)) { Debug.WriteLine(dataUti); var imageData = data; //var image = UIImage.LoadFromData(imageData); //if (imageScale < 1.0f) //{ // //begin resizing image // image = image.ResizeImageWithAspectRatio((float)imageScale); //} //if (imageQuality < 100) //{ // imageData = image.AsJPEG(Math.Min(imageQuality,100)); //} imageData?.Save(path, true); } var meFile = new MediaFile() { Type = MediaFileType.Image, Path = path, PreviewPath = path }; results.Add(meFile); OnMediaPicked?.Invoke(this, meFile); if (args.Assets.Length == results.Count && !completed) { completed = true; tcs.TrySetResult(results); } }); break; } } mediaPickTcs?.TrySetResult(await tcs.Task); }
async Task <MediaFile> GetPictureMediaFile(NSDictionary info) { var image = (UIImage)info[UIImagePickerController.EditedImage] ?? (UIImage)info[UIImagePickerController.OriginalImage]; if (image == null) { return(null); } var pathExtension = ((info[UIImagePickerController.ReferenceUrl] as NSUrl)?.PathExtension == "PNG") ? "png" : "jpg"; var path = GetOutputPath(MediaImplementation.TypeImage, options.Directory ?? ((IsCaptured) ? string.Empty : "temp"), options.Name, pathExtension); var cgImage = image.CGImage; var percent = 1.0f; float newHeight = image.CGImage.Height; float newWidth = image.CGImage.Width; if (options.PhotoSize != PhotoSize.Full) { try { switch (options.PhotoSize) { case PhotoSize.Large: percent = .75f; break; case PhotoSize.Medium: percent = .5f; break; case PhotoSize.Small: percent = .25f; break; case PhotoSize.Custom: percent = (float)options.CustomPhotoSize / 100f; break; } if (options.PhotoSize == PhotoSize.MaxWidthHeight && options.MaxWidthHeight.HasValue) { var max = Math.Max(image.CGImage.Width, image.CGImage.Height); if (max > options.MaxWidthHeight.Value) { percent = (float)options.MaxWidthHeight.Value / (float)max; } } if (percent < 1.0f) { //begin resizing image image = image.ResizeImageWithAspectRatio(percent); } } catch (Exception ex) { Console.WriteLine($"Unable to compress image: {ex}"); } } NSDictionary meta = null; try { if (options.SaveMetaData) { if (source == UIImagePickerControllerSourceType.Camera) { meta = info[UIImagePickerController.MediaMetadata] as NSDictionary; if (meta != null && meta.ContainsKey(ImageIO.CGImageProperties.Orientation)) { var newMeta = new NSMutableDictionary(); newMeta.SetValuesForKeysWithDictionary(meta); var newTiffDict = new NSMutableDictionary(); newTiffDict.SetValuesForKeysWithDictionary(meta[ImageIO.CGImageProperties.TIFFDictionary] as NSDictionary); newTiffDict.SetValueForKey(meta[ImageIO.CGImageProperties.Orientation], ImageIO.CGImageProperties.TIFFOrientation); newMeta[ImageIO.CGImageProperties.TIFFDictionary] = newTiffDict; meta = newMeta; } var location = options.Location; if (meta != null && location != null) { meta = SetGpsLocation(meta, location); } } else { var url = info[UIImagePickerController.ReferenceUrl] as NSUrl; if (url != null) { meta = PhotoLibraryAccess.GetPhotoLibraryMetadata(url); } } } } catch (Exception ex) { Console.WriteLine($"Unable to get metadata: {ex}"); } //iOS quality is 0.0-1.0 var quality = pathExtension == "jpg" ? (options.CompressionQuality / 100f) : 0f; var savedImage = false; if (meta != null) { savedImage = SaveImageWithMetadata(image, quality, meta, path, pathExtension); } if (!savedImage) { var finalQuality = quality; var imageData = pathExtension == "png" ? image.AsPNG() : image.AsJPEG(finalQuality); //continue to move down quality , rare instances while (imageData == null && finalQuality > 0) { finalQuality -= 0.05f; imageData = image.AsJPEG(finalQuality); } if (imageData == null) { throw new NullReferenceException("Unable to convert image to jpeg, please ensure file exists or lower quality level"); } imageData.Save(path, true); imageData.Dispose(); } string aPath = null; if (source != UIImagePickerControllerSourceType.Camera) { //try to get the album path's url var url = (NSUrl)info[UIImagePickerController.ReferenceUrl]; aPath = url?.AbsoluteString; } else { if (options.SaveToAlbum) { try { var library = new ALAssetsLibrary(); var albumSave = await library.WriteImageToSavedPhotosAlbumAsync(cgImage, meta); aPath = albumSave.AbsoluteString; } catch (Exception ex) { Console.WriteLine("unable to save to album:" + ex); } } } Func <Stream> getStreamForExternalStorage = () => { if (options.RotateImage) { return(RotateImage(image, options.CompressionQuality, pathExtension)); } else { return(File.OpenRead(path)); } }; string originalFilename = null; if (info.TryGetValue(UIImagePickerController.PHAsset, out var assetObj)) { var asset = (PHAsset)assetObj; if (asset != null) { originalFilename = PHAssetResource.GetAssetResources(asset)?.FirstOrDefault()?.OriginalFilename; } } return(new MediaFile(path, () => File.OpenRead(path), streamGetterForExternalStorage: () => getStreamForExternalStorage(), albumPath: aPath, originalFilename: originalFilename)); }
static FileResult DictionaryToMediaFile(NSDictionary info) { if (info == null) { return(null); } PHAsset phAsset = null; NSUrl assetUrl = null; if (OperatingSystem.IsIOSVersionAtLeast(11, 0)) { assetUrl = info[UIImagePickerController.ImageUrl] as NSUrl; // Try the MediaURL sometimes used for videos if (assetUrl == null) { assetUrl = info[UIImagePickerController.MediaURL] as NSUrl; } if (assetUrl != null) { if (!assetUrl.Scheme.Equals("assets-library", StringComparison.OrdinalIgnoreCase)) { return(new UIDocumentFileResult(assetUrl)); } #pragma warning disable CA1416 // TODO: 'UIImagePickerController.PHAsset' is only supported on: 'ios' from version 11.0 to 14.0 phAsset = info.ValueForKey(UIImagePickerController.PHAsset) as PHAsset; #pragma warning restore CA1416 } } #if !MACCATALYST #pragma warning disable CA1416 // TODO: 'UIImagePickerController.ReferenceUrl' is unsupported on 'ios' 11.0 and later if (phAsset == null) { assetUrl = info[UIImagePickerController.ReferenceUrl] as NSUrl; if (assetUrl != null) { phAsset = PHAsset.FetchAssets(new NSUrl[] { assetUrl }, null)?.LastObject as PHAsset; } } #pragma warning restore CA1416 // 'PHAsset.FetchAssets(NSUrl[], PHFetchOptions?)' is unsupported on 'ios' 11.0 and later #endif if (phAsset == null || assetUrl == null) { var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage; if (img != null) { return(new UIImageFileResult(img)); } } if (phAsset == null || assetUrl == null) { return(null); } #pragma warning disable CA1416 // https://github.com/xamarin/xamarin-macios/issues/14619 string originalFilename = PHAssetResource.GetAssetResources(phAsset).FirstOrDefault()?.OriginalFilename; #pragma warning restore CA1416 return(new PHAssetFileResult(assetUrl, phAsset, originalFilename)); }
async Task <IList <MediaAsset> > LoadMediaAsync() { IList <MediaAsset> assets = new List <MediaAsset>(); var imageManager = new PHCachingImageManager(); var hasPermission = await RequestPermissionAsync(); if (hasPermission) { await Task.Run(async() => { var thumbnailRequestOptions = new PHImageRequestOptions(); thumbnailRequestOptions.ResizeMode = PHImageRequestOptionsResizeMode.Fast; thumbnailRequestOptions.DeliveryMode = PHImageRequestOptionsDeliveryMode.FastFormat; thumbnailRequestOptions.NetworkAccessAllowed = true; thumbnailRequestOptions.Synchronous = true; var requestOptions = new PHImageRequestOptions(); requestOptions.ResizeMode = PHImageRequestOptionsResizeMode.Exact; requestOptions.DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat; requestOptions.NetworkAccessAllowed = true; requestOptions.Synchronous = true; var fetchOptions = new PHFetchOptions(); fetchOptions.SortDescriptors = new NSSortDescriptor[] { new NSSortDescriptor("creationDate", false) }; fetchOptions.Predicate = NSPredicate.FromFormat($"mediaType == {(int)PHAssetMediaType.Image} || mediaType == {(int)PHAssetMediaType.Video}"); var fetchResults = PHAsset.FetchAssets(fetchOptions); var tmpPath = Path.GetTempPath(); var allAssets = fetchResults.Select(p => p as PHAsset).ToArray(); var thumbnailSize = new CGSize(300.0f, 300.0f); imageManager.StartCaching(allAssets, thumbnailSize, PHImageContentMode.AspectFit, thumbnailRequestOptions); imageManager.StartCaching(allAssets, PHImageManager.MaximumSize, PHImageContentMode.AspectFit, requestOptions); foreach (var result in fetchResults) { var phAsset = (result as PHAsset); var name = PHAssetResource.GetAssetResources(phAsset)?.FirstOrDefault()?.OriginalFilename; var asset = new MediaAsset() { Id = phAsset.LocalIdentifier, Name = name, Type = phAsset.MediaType == PHAssetMediaType.Image ? MediaAssetType.Image : MediaAssetType.Video, }; imageManager.RequestImageForAsset(phAsset, thumbnailSize, PHImageContentMode.AspectFit, thumbnailRequestOptions, (image, info) => { if (image != null) { NSData imageData = null; if (image.CGImage.RenderingIntent == CGColorRenderingIntent.Default) { imageData = image.AsJPEG(0.8f); } else { imageData = image.AsPNG(); } if (imageData != null) { var fileName = Path.Combine(tmpPath, $"tmp_thumbnail_{Path.GetFileNameWithoutExtension(name)}.jpg"); NSError error = null; imageData.Save(fileName, true, out error); if (error == null) { asset.PreviewPath = fileName; } } } }); switch (phAsset.MediaType) { case PHAssetMediaType.Image: imageManager.RequestImageForAsset(phAsset, PHImageManager.MaximumSize, PHImageContentMode.AspectFit, requestOptions, (image, info) => { if (image != null) { NSData imageData = null; if (image.CGImage.RenderingIntent == CGColorRenderingIntent.Default) { imageData = image.AsJPEG(0.8f); } else { imageData = image.AsPNG(); } if (imageData != null) { var fileName = Path.Combine(tmpPath, $"tmp_{name}"); NSError error = null; imageData.Save(fileName, true, out error); if (error == null) { asset.Path = fileName; } } } }); break; case PHAssetMediaType.Video: var videoRequestOptions = new PHVideoRequestOptions(); videoRequestOptions.NetworkAccessAllowed = true; var tcs = new TaskCompletionSource <bool>(); imageManager.RequestAvAsset(phAsset, null, (vAsset, audioMix, info) => { var avAsset = vAsset as AVUrlAsset; var avData = NSData.FromUrl(avAsset.Url); NSError error = null; var path = Path.Combine(tmpPath, $"tmp_{name}"); avData.Save(path, true, out error); if (error == null) { asset.Path = path; tcs.TrySetResult(true); } else { tcs.TrySetResult(false); } }); await tcs.Task; break; } UIApplication.SharedApplication.InvokeOnMainThread(delegate { OnMediaAssetLoaded?.Invoke(this, new MediaEventArgs(asset)); }); assets.Add(asset); if (requestStop) { break; } } }); imageManager.StopCaching(); } return(assets); }
protected void Internal_FillCache() { if (_bCached) { return; } _globalLock.EnterWriteLock(); try { if (_bCached) { return; } var cacheDir = new Dictionary <string, PHAssetCollection>(); var cachePhoto = new Dictionary <string, PHPhotoItem>(); var collections = PHAssetCollection.FetchAssetCollections(PHAssetCollectionType.SmartAlbum, PHAssetCollectionSubtype.SmartAlbumUserLibrary, null); foreach (PHAssetCollection asset in collections) { cacheDir["/" + asset.LocalizedTitle] = asset; var assets = PHAsset.FetchAssets(asset, null); foreach (PHAsset photo in assets) { var assetResources = PHAssetResource.GetAssetResources(photo); var original = assetResources.FirstOrDefault(x => x.ResourceType == PHAssetResourceType.Video || x.ResourceType == PHAssetResourceType.Photo || x.ResourceType == PHAssetResourceType.Audio); if (original == null) { continue; } var dt = photo.CreationDate.ToDateTime(); var dtstr = dt.ToLocalTime().ToString("yyyy-MM-dd HH_mm"); var filename = $"{dtstr} {original.OriginalFilename}"; UPath up = Path.Combine(asset.LocalizedTitle, filename); var item = new PHPhotoItem { Col = asset, Asset = photo, Res = original }; item.Path = new Lazy <string>(item.FillPath); item.Length = new Lazy <long>(item.FillLength); cachePhoto[up.ToAbsolute().ToString().ToUpperInvariant()] = item; var originalName = Path.GetFileNameWithoutExtension(original.OriginalFilename); foreach (var resource in assetResources) { if (resource == original) { continue; } if (string.IsNullOrEmpty(resource.OriginalFilename)) { continue; } var extension = Path.GetExtension(resource.OriginalFilename) ?? string.Empty; var fileName = $"{dtstr} {originalName} ({resource.ResourceType:G}){extension}"; up = Path.Combine(asset.LocalizedTitle, fileName); item = new PHPhotoItem { Col = asset, Asset = photo, Res = resource }; item.Path = new Lazy <string>(item.FillPath); item.Length = new Lazy <long>(item.FillLength); cachePhoto[up.ToAbsolute().ToString().ToUpperInvariant()] = item; } } } _cacheDir = cacheDir; _cachePhoto = cachePhoto; _bCached = true; Task.Run(() => { Parallel.ForEach(cachePhoto, new ParallelOptions { MaxDegreeOfParallelism = 2 * Environment.ProcessorCount }, x => { _ = x.Value.Length.Value; _ = x.Value.Path.Value; }); }); } catch (Exception e) { Console.WriteLine(e.Message); } finally { _globalLock.ExitWriteLock(); } }
MediaFile GetPictureMediaFile(ALAsset asset, long index = 0) { var rep = asset.DefaultRepresentation; if (rep == null) { return(null); } var cgImage = rep.GetImage(); UIImage image = null; string originalFilename = null; if (cgImage == null) { var fetch = PHAsset.FetchAssets(new[] { asset.AssetUrl }, null); var ph = fetch.firstObject as PHAsset; originalFilename = PHAssetResource.GetAssetResources(ph)?.FirstOrDefault()?.OriginalFilename; var manager = PHImageManager.DefaultManager; var phOptions = new PHImageRequestOptions { Version = PHImageRequestOptionsVersion.Original, NetworkAccessAllowed = true, Synchronous = true }; phOptions.ProgressHandler = (double progress, NSError error, out bool stop, NSDictionary info) => { Debug.WriteLine($"Progress: {progress.ToString()}"); stop = false; }; if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0)) { manager.RequestImageDataAndOrientation(ph, phOptions, (data, i, orientation, k) => { if (data != null) { image = new UIImage(data, 1.0f); } }); } else { manager.RequestImageData(ph, phOptions, (data, i, orientation, k) => { if (data != null) { image = new UIImage(data, 1.0f); } }); } phOptions?.Dispose(); fetch?.Dispose(); ph?.Dispose(); } else { image = new UIImage(cgImage, 1.0f, (UIImageOrientation)rep.Orientation); } var path = MediaPickerDelegate.GetOutputPath(MediaImplementation.TypeImage, options.Directory ?? "temp", options.Name, asset.AssetUrl?.PathExtension, index); var isPng = Path.GetExtension(path).ToLowerInvariant() == ".png"; cgImage?.Dispose(); cgImage = null; rep?.Dispose(); rep = null; //There might be cases when the original image cannot be retrieved while image thumb was still present. //Then no need to try to save it as we will get an exception here //TODO: Ideally, we should notify the client that we failed to get original image //TODO: Otherwise, it might be confusing to the user, that he saw the thumb, but did not get the image if (image == null) { return(null); } if (isPng) { image.AsPNG().Save(path, true); } else { image.AsJPEG().Save(path, true); } image?.Dispose(); image = null; GC.Collect(GC.MaxGeneration, GCCollectionMode.Default); string aPath = null; //try to get the album path's url var url = asset.AssetUrl; aPath = url?.AbsoluteString; return(new MediaFile(path, () => File.OpenRead(path), albumPath: aPath, originalFilename: originalFilename)); }