Skip to content

Instantly share code, notes, and snippets.

@Hackmodford
Created September 17, 2021 13:55
Show Gist options
  • Save Hackmodford/9060579ccab4fd0917061ced474cdb05 to your computer and use it in GitHub Desktop.
Save Hackmodford/9060579ccab4fd0917061ced474cdb05 to your computer and use it in GitHub Desktop.
MediaPicker CapturePhotoAsync Rotation Fix
public interface IPhotoService
{
public Task<Stream> TakePhotoAsync(MediaPickerOptions options = null);
}
public class PlatformPhotoService : IPhotoService
{
private static UIImagePickerController _picker;
public async Task<Stream> TakePhotoAsync(MediaPickerOptions options)
{
const UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceType.Camera;
var mediaType = UTType.Image;
if (!UIImagePickerController.IsSourceTypeAvailable(sourceType))
throw new FeatureNotSupportedException();
if (!UIImagePickerController.AvailableMediaTypes(sourceType).Contains(mediaType))
throw new FeatureNotSupportedException();
await EnsureGrantedAsync<Permissions.Camera>();
var vc = GetCurrentViewController();
_picker = new UIImagePickerController
{
SourceType = sourceType,
MediaTypes = new string[] {mediaType},
AllowsEditing = false
};
if (!string.IsNullOrWhiteSpace(options?.Title))
_picker.Title = options.Title;
if (DeviceInfo.Idiom == DeviceIdiom.Tablet && _picker.PopoverPresentationController != null && vc.View != null)
_picker.PopoverPresentationController.SourceRect = vc.View.Bounds;
var tcs = new TaskCompletionSource<Stream>(_picker);
_picker.Delegate = new PhotoPickerDelegate
{
CompletedHandler = info => GetImageStream(info, tcs)
};
if (_picker.PresentationController != null)
{
_picker.PresentationController.Delegate = new PhotoPickerPresentationControllerDelegate
{
CompletedHandler = info => GetImageStream(info, tcs)
};
}
await vc.PresentViewControllerAsync(_picker, true);
var result = await tcs.Task;
await vc.DismissViewControllerAsync(true);
_picker?.Dispose();
_picker = null;
return result;
}
static void GetImageStream(NSDictionary info, TaskCompletionSource<Stream> tcs)
{
try
{
tcs.TrySetResult(DictionaryToStream(info));
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
static Stream DictionaryToStream(NSDictionary info)
{
var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage;
img = img.NormalizeOrientation();
var data = img?.AsPNG();
return data?.AsStream();
}
class PhotoPickerDelegate : UIImagePickerControllerDelegate
{
public Action<NSDictionary> CompletedHandler { get; set; }
public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info) =>
CompletedHandler?.Invoke(info);
public override void Canceled(UIImagePickerController picker) =>
CompletedHandler?.Invoke(null);
}
class PhotoPickerPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate
{
public Action<NSDictionary> CompletedHandler { get; set; }
public override void DidDismiss(UIPresentationController presentationController) =>
CompletedHandler?.Invoke(null);
}
internal static UIViewController GetCurrentViewController(bool throwIfNull = true)
{
UIViewController viewController = null;
var window = UIApplication.SharedApplication.KeyWindow;
if (window != null && window.WindowLevel == UIWindowLevel.Normal)
viewController = window.RootViewController;
if (viewController == null)
{
window = UIApplication.SharedApplication
.Windows
.OrderByDescending(w => w.WindowLevel)
.FirstOrDefault(w => w.RootViewController != null && w.WindowLevel == UIWindowLevel.Normal);
if (window == null && throwIfNull)
throw new InvalidOperationException("Could not find current view controller.");
else
viewController = window?.RootViewController;
}
while (viewController?.PresentedViewController != null)
viewController = viewController.PresentedViewController;
if (throwIfNull && viewController == null)
throw new InvalidOperationException("Could not find current view controller.");
return viewController;
}
internal static bool HasOSVersion(int major, int minor) =>
UIDevice.CurrentDevice.CheckSystemVersion(major, minor);
internal static async Task EnsureGrantedAsync<TPermission>()
where TPermission : Permissions.BasePermission, new()
{
var status = await Permissions.RequestAsync<TPermission>();
if (status != PermissionStatus.Granted)
throw new PermissionException($"{typeof(TPermission).Name} permission was not granted: {status}");
}
}
@MichaelLHerman
Copy link

MichaelLHerman commented Oct 20, 2022

NormalizeOrientation

public static UIImage NormalizeOrientation(this UIImage image)
 {
    if (image.Orientation == UIImageOrientation.Up)
    {
        return image;
    }
            
    UIGraphics.BeginImageContext(image.Size);
    image.Draw(new CGRect(CGPoint.Empty, image.Size));
    var normalizedImage = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return normalizedImage;
}

xamarin/Essentials#1562 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment