diff --git a/CHANGELOG.md b/CHANGELOG.md index 96d33413..6b1346c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ * Fix for #514: Videos on Android 8.1 stop after short time. * Upgrade to CurrentActivityPlugin 2.0 and Permissions 3.0 * Ability on iOS to specify pop over style +* Fix for #642: Android dock/undock issue +* Fix for #639: Null reference sometimes when can't accessing file on Android. +* Fix for #553: When not rotating image on android ensure we take max width/height into consideration. +* Fix for #545: iOS error sometimes when saving metadata. +* Fix for #608: Possible null on iOS when picking video sometimes. ### [3.1.3] * Remove need for Android Target versions (always use File Provider via #442 and @ddobrev) diff --git a/src/Media.Plugin/Android/MediaImplementation.cs b/src/Media.Plugin/Android/MediaImplementation.cs index e2b94921..13068d6d 100644 --- a/src/Media.Plugin/Android/MediaImplementation.cs +++ b/src/Media.Plugin/Android/MediaImplementation.cs @@ -109,7 +109,7 @@ bool IsValidExif(ExifInterface exif) } else { - await ResizeAsync(media.Path, options.PhotoSize, options.CompressionQuality, options.CustomPhotoSize, originalMetadata); + await ResizeAsync(media.Path, options, originalMetadata); } if (options.SaveMetaData && IsValidExif(originalMetadata)) { @@ -218,7 +218,7 @@ bool IsValidExif(ExifInterface exif) } else { - await ResizeAsync(media.Path, options.PhotoSize, options.CompressionQuality, options.CustomPhotoSize, exif); + await ResizeAsync(media.Path, options, exif); } if (options.SaveMetaData && IsValidExif(exif)) @@ -705,22 +705,49 @@ int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHe return inSampleSize; } - /// - /// Resize Image Async - /// - /// The file image path - /// Photo size to go to. - /// Image quality (1-100) - /// Custom size in percent - /// original metadata - /// True if rotation or compression occured, else false - public Task ResizeAsync(string filePath, PhotoSize photoSize, int quality, int customPhotoSize, ExifInterface exif) + + /// + /// Rotate an image if required and saves it back to disk. + /// + /// The file image path + /// The options. + /// original metadata + /// True if rotation or compression occured, else false + public Task ResizeAsync(string filePath, PickMediaOptions mediaOptions, ExifInterface exif) + { + return ResizeAsync( + filePath, + new StoreCameraMediaOptions + { + PhotoSize = mediaOptions.PhotoSize, + CompressionQuality = mediaOptions.CompressionQuality, + CustomPhotoSize = mediaOptions.CustomPhotoSize, + MaxWidthHeight = mediaOptions.MaxWidthHeight, + RotateImage = mediaOptions.RotateImage, + SaveMetaData = mediaOptions.SaveMetaData + }, + exif); + } + + /// + /// Resize Image Async + /// + /// The file image path + /// Photo size to go to. + /// Image quality (1-100) + /// Custom size in percent + /// original metadata + /// True if rotation or compression occured, else false + public Task ResizeAsync(string filePath, StoreCameraMediaOptions mediaOptions, ExifInterface exif) { if (string.IsNullOrWhiteSpace(filePath)) return Task.FromResult(false); try { + var photoSize = mediaOptions.PhotoSize; + var customPhotoSize = mediaOptions.CustomPhotoSize; + var quality = mediaOptions.CompressionQuality; return Task.Run(() => { try @@ -755,7 +782,16 @@ public Task ResizeAsync(string filePath, PhotoSize photoSize, int quality, //already on background task BitmapFactory.DecodeFile(filePath, options); - var finalWidth = (int)(options.OutWidth * percent); + if (mediaOptions.PhotoSize == PhotoSize.MaxWidthHeight && mediaOptions.MaxWidthHeight.HasValue) + { + var max = Math.Max(options.OutWidth, options.OutHeight); + if (max > mediaOptions.MaxWidthHeight) + { + percent = (float)mediaOptions.MaxWidthHeight / (float)max; + } + } + + var finalWidth = (int)(options.OutWidth * percent); var finalHeight = (int)(options.OutHeight * percent); //set scaled image dimensions diff --git a/src/Media.Plugin/Android/MediaPickerActivity.cs b/src/Media.Plugin/Android/MediaPickerActivity.cs index c3b65ce8..aef07587 100644 --- a/src/Media.Plugin/Android/MediaPickerActivity.cs +++ b/src/Media.Plugin/Android/MediaPickerActivity.cs @@ -20,7 +20,7 @@ namespace Plugin.Media /// /// Picker /// - [Activity(ConfigurationChanges= ConfigChanges.Orientation | ConfigChanges.ScreenSize)] + [Activity(ConfigurationChanges= ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] public class MediaPickerActivity : Activity, Android.Media.MediaScannerConnection.IOnScanCompletedListener { @@ -315,9 +315,9 @@ internal static Task GetMediaFileAsync(Context context, in return pathFuture.ContinueWith(t => { - var resultPath = t.Result.Item1; + var resultPath = t?.Result?.Item1; var aPath = originalPath; - if (resultPath != null && File.Exists(t.Result.Item1)) + if (resultPath != null && File.Exists(resultPath)) { var mf = new MediaFile(resultPath, () => { diff --git a/src/Media.Plugin/iOS/MediaPickerDelegate.cs b/src/Media.Plugin/iOS/MediaPickerDelegate.cs index ec83408f..224649eb 100644 --- a/src/Media.Plugin/iOS/MediaPickerDelegate.cs +++ b/src/Media.Plugin/iOS/MediaPickerDelegate.cs @@ -356,7 +356,9 @@ private async Task GetPictureMediaFile(NSDictionary info) } else { - meta = PhotoLibraryAccess.GetPhotoLibraryMetadata(info[UIImagePickerController.ReferenceUrl] as NSUrl); + var url = info[UIImagePickerController.ReferenceUrl] as NSUrl; + if(url != null) + meta = PhotoLibraryAccess.GetPhotoLibraryMetadata(url); } } @@ -533,24 +535,27 @@ private bool SaveImageWithMetadata(UIImage image, float quality, NSDictionary me private async Task GetMovieMediaFile(NSDictionary info) { - var url = (NSUrl)info[UIImagePickerController.MediaURL]; + var url = info[UIImagePickerController.MediaURL] as NSUrl; + if (url == null) + return null; var path = GetOutputPath(MediaImplementation.TypeMovie, - options.Directory ?? ((IsCaptured) ? string.Empty : "temp"), - options.Name ?? Path.GetFileName(url.Path)); + options?.Directory ?? ((IsCaptured) ? string.Empty : "temp"), + options?.Name ?? Path.GetFileName(url.Path)); + File.Move(url.Path, path); string aPath = null; if (source != UIImagePickerControllerSourceType.Camera) { //try to get the album path's url - var url2 = (NSUrl)info[UIImagePickerController.ReferenceUrl]; + var url2 = info[UIImagePickerController.ReferenceUrl] as NSUrl; aPath = url2?.AbsoluteString; } else { - if (options.SaveToAlbum) + if (options?.SaveToAlbum ?? false) { try { diff --git a/src/Media.Plugin/iOS/PhotoLibraryAccess.cs b/src/Media.Plugin/iOS/PhotoLibraryAccess.cs index b4e470ef..bedfdeea 100644 --- a/src/Media.Plugin/iOS/PhotoLibraryAccess.cs +++ b/src/Media.Plugin/iOS/PhotoLibraryAccess.cs @@ -20,37 +20,47 @@ public static NSDictionary GetPhotoLibraryMetadata(NSUrl url) NSDictionary meta = null; var image = PHAsset.FetchAssets(new NSUrl[] { url }, new PHFetchOptions()).firstObject as PHAsset; - var imageManager = PHImageManager.DefaultManager; - var requestOptions = new PHImageRequestOptions - { - Synchronous = true, - NetworkAccessAllowed = true, - DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat, - }; - imageManager.RequestImageData(image, requestOptions, (data, dataUti, orientation, info) => + if (image == null) + return null; + + try { - try + var imageManager = PHImageManager.DefaultManager; + var requestOptions = new PHImageRequestOptions { - var fullimage = CIImage.FromData(data); - if (fullimage?.Properties != null) + Synchronous = true, + NetworkAccessAllowed = true, + DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat, + }; + imageManager.RequestImageData(image, requestOptions, (data, dataUti, orientation, info) => + { + try { - meta = new NSMutableDictionary + var fullimage = CIImage.FromData(data); + if (fullimage?.Properties != null) { - [ImageIO.CGImageProperties.Orientation] = NSNumber.FromNInt ((int)(fullimage.Properties.Orientation ?? CIImageOrientation.TopLeft)), - [ImageIO.CGImageProperties.ExifDictionary] = fullimage.Properties.Exif?.Dictionary ?? new NSDictionary(), - [ImageIO.CGImageProperties.TIFFDictionary] = fullimage.Properties.Tiff?.Dictionary ?? new NSDictionary(), - [ImageIO.CGImageProperties.GPSDictionary] = fullimage.Properties.Gps?.Dictionary ?? new NSDictionary(), - [ImageIO.CGImageProperties.IPTCDictionary] = fullimage.Properties.Iptc?.Dictionary ?? new NSDictionary(), - [ImageIO.CGImageProperties.JFIFDictionary] = fullimage.Properties.Jfif?.Dictionary ?? new NSDictionary() - }; + meta = new NSMutableDictionary + { + [ImageIO.CGImageProperties.Orientation] = NSNumber.FromNInt((int)(fullimage.Properties.Orientation ?? CIImageOrientation.TopLeft)), + [ImageIO.CGImageProperties.ExifDictionary] = fullimage.Properties.Exif?.Dictionary ?? new NSDictionary(), + [ImageIO.CGImageProperties.TIFFDictionary] = fullimage.Properties.Tiff?.Dictionary ?? new NSDictionary(), + [ImageIO.CGImageProperties.GPSDictionary] = fullimage.Properties.Gps?.Dictionary ?? new NSDictionary(), + [ImageIO.CGImageProperties.IPTCDictionary] = fullimage.Properties.Iptc?.Dictionary ?? new NSDictionary(), + [ImageIO.CGImageProperties.JFIFDictionary] = fullimage.Properties.Jfif?.Dictionary ?? new NSDictionary() + }; + } + } + catch (Exception ex) + { + Console.WriteLine(ex); } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - }); + }); + } + catch + { + + } return meta; }