From 81378a46e6132ff48f191150ab67717521f4f57f Mon Sep 17 00:00:00 2001 From: Manbir Rakhra Date: Thu, 25 Jul 2019 11:28:16 +1000 Subject: [PATCH] [iOSResizeMultiplePhotosCrash] I have fixed the crash of iOS when selecting multiple photographs with resize. This can allow more than 100 photographs with resize. --- .../iOS/ECLImagePickerViewController.cs | 82 +------------- src/Media.Plugin/iOS/MediaImplementation.cs | 101 +++++++++++++++++- src/Media.Plugin/iOS/UIImageExtensions.cs | 51 +++++---- 3 files changed, 128 insertions(+), 106 deletions(-) diff --git a/src/Media.Plugin/iOS/ECLImagePickerViewController.cs b/src/Media.Plugin/iOS/ECLImagePickerViewController.cs index e673c097..9d5bb506 100644 --- a/src/Media.Plugin/iOS/ECLImagePickerViewController.cs +++ b/src/Media.Plugin/iOS/ECLImagePickerViewController.cs @@ -164,89 +164,11 @@ private MediaFile GetPictureMediaFile(ALAsset asset, long index = 0) rep?.Dispose(); rep = null; - var percent = 1.0f; - 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 - { - //meta = PhotoLibraryAccess.GetPhotoLibraryMetadata(asset.AssetUrl); - - //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 = MediaPickerDelegate.SetGpsLocation(meta, location); - } - } - catch (Exception ex) - { - Console.WriteLine($"Unable to get metadata: {ex}"); - } - - //iOS quality is 0.0-1.0 - var quality = (_options.CompressionQuality / 100f); - var savedImage = false; - if (meta != null) - savedImage = MediaPickerDelegate.SaveImageWithMetadata(image, quality, meta, path); - - if (!savedImage) - image.AsJPEG(quality).Save(path, true); + 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 diff --git a/src/Media.Plugin/iOS/MediaImplementation.cs b/src/Media.Plugin/iOS/MediaImplementation.cs index 07ad4c72..0a195bfe 100644 --- a/src/Media.Plugin/iOS/MediaImplementation.cs +++ b/src/Media.Plugin/iOS/MediaImplementation.cs @@ -24,10 +24,9 @@ public class MediaImplementation : IMedia /// public static UIStatusBarStyle StatusBarStyle { get; set; } - - /// - public Task Initialize() => Task.FromResult(true); + /// + public Task Initialize() => Task.FromResult(true); /// /// Implementation @@ -379,10 +378,104 @@ private static MediaPickerController SetupController(MediaPickerDelegate mpDeleg return Task.FromResult(new List()); } + var files = t.Result; + Parallel.ForEach(files, mediaFile => + { + ResizeAndCompressImage(options, mediaFile); + }); + return t; }).Unwrap(); } + private static void ResizeAndCompressImage(StoreCameraMediaOptions options, MediaFile mediaFile) + { + var image = UIImage.FromFile(mediaFile.Path); + var percent = 1.0f; + 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.Size.Width, image.Size.Height); + if (max > options.MaxWidthHeight.Value) + { + percent = (float)options.MaxWidthHeight.Value / (float)max; + } + } + + if (percent < 1.0f) + { + //begin resizing image + image = image.ResizeImageWithAspectRatio(percent); + } + + NSDictionary meta = null; + try + { + //meta = PhotoLibraryAccess.GetPhotoLibraryMetadata(asset.AssetUrl); + + //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 = MediaPickerDelegate.SetGpsLocation(meta, location); + } + } + catch (Exception ex) + { + Console.WriteLine($"Unable to get metadata: {ex}"); + } + + //iOS quality is 0.0-1.0 + var quality = (options.CompressionQuality / 100f); + var savedImage = false; + if (meta != null) + savedImage = MediaPickerDelegate.SaveImageWithMetadata(image, quality, meta, mediaFile.Path); + + if (!savedImage) + image.AsJPEG(quality).Save(mediaFile.Path, true); + + image?.Dispose(); + image = null; + + GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); + } + catch (Exception ex) + { + Console.WriteLine($"Unable to compress image: {ex}"); + } + } + } + private void Dismiss(UIPopoverController popover, UIViewController picker) { if (popover != null) @@ -399,7 +492,7 @@ private void Dismiss(UIPopoverController popover, UIViewController picker) { } - + GC.Collect(GC.MaxGeneration, GCCollectionMode.Default); Interlocked.Exchange(ref pickerDelegate, null); } diff --git a/src/Media.Plugin/iOS/UIImageExtensions.cs b/src/Media.Plugin/iOS/UIImageExtensions.cs index ba7bfd9a..0b1b3272 100644 --- a/src/Media.Plugin/iOS/UIImageExtensions.cs +++ b/src/Media.Plugin/iOS/UIImageExtensions.cs @@ -3,6 +3,7 @@ using System.Drawing; using UIKit; using CoreImage; +using Foundation; namespace Plugin.Media { @@ -21,34 +22,40 @@ public static UIImage ResizeImageWithAspectRatio(this UIImage imageSource, float { if (scale > 1.0f) return imageSource; - - using (var c = CIContext.Create()) - { - var sourceImage = CIImage.FromCGImage(imageSource.CGImage); - var f = new CILanczosScaleTransform - { - Scale = scale, - Image = sourceImage, - AspectRatio = 1.0f - }; + using (var c = CIContext.Create()) + { + var sourceImage = CIImage.FromCGImage(imageSource.CGImage); + var orientation = imageSource.Orientation; + imageSource?.Dispose(); - var output = f.OutputImage; + var transform = new CILanczosScaleTransform + { + Scale = scale, + Image = sourceImage, + AspectRatio = 1.0f + }; - var cgi = c.CreateCGImage(output, output.Extent); - return UIImage.FromImage(cgi, 1.0f, imageSource.Orientation); - } - } + var output = transform.OutputImage; + using (var cgi = c.CreateCGImage(output, output.Extent)) + { + transform?.Dispose(); + output?.Dispose(); + sourceImage?.Dispose(); - /// - /// Resize image to maximum size - /// keeping the aspect ratio - /// - public static UIImage ResizeImageWithAspectRatio(this UIImage sourceImage, float maxWidth, float maxHeight) - { - + return UIImage.FromImage(cgi, 1.0f, orientation); + } + + } + } + /// + /// Resize image to maximum size + /// keeping the aspect ratio + /// + public static UIImage ResizeImageWithAspectRatio(this UIImage sourceImage, float maxWidth, float maxHeight) + { var sourceSize = sourceImage.Size; var maxResizeFactor = Math.Max(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height); if (maxResizeFactor > 1)