Forum Xamarin.iOS

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

PHImageManager RequestImageData Get Base64 for Live Image or Heic

AbhayLAbhayL Member ✭✭

I've to show the picker to select multiple images from iphone (and android).... and get the base64 of each image to save in DB. This base64 will be used on HTML to display image.

I working on FinishedPickingAssets event, and trying to get the Base64 of file that was uploaded. However i'm getting only a part of file (with few pixel height) ... when check the base64 online (base64 to image converter base64.imageonline.co)

Following is my code..
__
[assembly: Dependency(typeof(MultiMediaPickerService))]
namespace Student360Mobile.iOS
{

public class MultiMediaPickerService : IMultiMediaPickerService
{
    const string TemporalDirectoryName = "TmpMedia";
    public event EventHandler<MediaFile> OnMediaPicked;
    public event EventHandler<IList<MediaFile>> OnMediaPickedCompleted;

    GMImagePickerController currentPicker;
    TaskCompletionSource<IList<MediaFile>> mediaPickTcs;

    public MultiMediaPickerService()
    {
    }

    public void Clean()
    {
        var documentsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), TemporalDirectoryName);

        if (Directory.Exists(documentsDirectory))
        {
            Directory.Delete(documentsDirectory);
        }
    }

    public async Task<IList<MediaFile>> PickPhotosAsync()
    {
        return await PickMediaAsync("Select Images", PHAssetMediaType.Image);
    }

    public async Task<IList<MediaFile>> PickVideosAsync()
    {
        return await PickMediaAsync("Select Videos", PHAssetMediaType.Video);
    }

    async Task<IList<MediaFile>> PickMediaAsync(string title, PHAssetMediaType type)
    {

        mediaPickTcs = new TaskCompletionSource<IList<MediaFile>>();
        currentPicker = new GMImagePickerController()
        {
            Title = title,
            MediaTypes = new[] { type }
        };

        currentPicker.FinishedPickingAssets += FinishedPickingAssets;

        var window = UIApplication.SharedApplication.KeyWindow;
        var vc = window.RootViewController;
        while (vc.PresentedViewController != null)
        {
            vc = vc.PresentedViewController;
        }

        var tylerBlue = TylerColors.TylerBlue.ToUIColor();

        var navBar = UINavigationBar.AppearanceWhenContainedIn(typeof(GMImagePickerController));
        navBar.SetBackgroundImage(ImageWithColor(TylerColors.TylerBlue.ToUIColor()), UIBarMetrics.Default);

        // await vc.PresentViewControllerAsync(currentPicker, true);
        vc.PresentViewController(currentPicker, true, () =>
        {
            UINavigationBar.Appearance.BarTintColor = tylerBlue;
            UINavigationBar.Appearance.TintColor = UIColor.White;
            UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
            {
                TextColor = UIColor.White
            });
        });

        var results = await mediaPickTcs.Task;

        currentPicker.FinishedPickingAssets -= FinishedPickingAssets;
        OnMediaPickedCompleted?.Invoke(this, results);
        return results;
    }
    private UIImage ImageWithColor(UIColor color)
    {
        var rect = new CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0);
        var alpha = color.CGColor.Alpha;
        var opaque = alpha == 1;
        UIGraphics.BeginImageContextWithOptions(rect.Size, opaque, 0);
        var context = UIGraphics.GetCurrentContext();
        context?.SetFillColor(color.CGColor);
        context?.FillRect(rect);
        return UIGraphics.GetImageFromCurrentImageContext();
    }

    async void FinishedPickingAssets(object sender, MultiAssetEventArgs args)
    {
        IList<MediaFile> results = new List<MediaFile>();
        TaskCompletionSource<IList<MediaFile>> tcs = new TaskCompletionSource<IList<MediaFile>>();

        var options = new PHImageRequestOptions()
        {
            NetworkAccessAllowed = true
        };

        options.Synchronous = false;
        options.ResizeMode = PHImageRequestOptionsResizeMode.Fast;
        options.DeliveryMode = PHImageRequestOptionsDeliveryMode.FastFormat;
        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:
                    //DO NOT CONSIDER VDO
                    break;
                default:

                PHImageManager.DefaultManager.RequestImageData(asset, options, (data, dataUti, orientation, info) =>
                                {

                                    CIImage ciImage = new CIImage(data);
                                    var defaultContext = CIContext.Create();
                                    CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent, CIFormat.ARGB8, CGColorSpace.CreateDeviceRGB());
                                    // Or use this:
                                    // CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent);
                                    var image = new UIImage(outputImage);
                                    var outputData = image.AsJPEG();
                                    string base64 = outputData.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
                                });

                    break;
            }
        }


        mediaPickTcs?.TrySetResult(await tcs.Task);
    }

}

}
__

Answers

  • ColeXColeX Member, Xamarin Team Xamurai

    We need to ensure the code (if it's related to UI )should be invoked on the UI Thread in the callback .

    Try

     DispatchQueue.MainQueue.DispatchAsync(() => {
             CIImage ciImage = new CIImage(data);
                                        var defaultContext = CIContext.Create();
                                        CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent, CIFormat.ARGB8, CGColorSpace.CreateDeviceRGB());
                                        // Or use this:
                                        // CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent);
                                        var image = new UIImage(outputImage);
                                        var outputData = image.AsJPEG();
                                        string base64 = outputData.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    
                    });
    

    Or

    InvokeOnMainThread ( () => {
          CIImage ciImage = new CIImage(data);
                                        var defaultContext = CIContext.Create();
                                        CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent, CIFormat.ARGB8, CGColorSpace.CreateDeviceRGB());
                                        // Or use this:
                                        // CGImage outputImage = defaultContext.CreateCGImage(ciImage, ciImage.Extent);
                                        var image = new UIImage(outputImage);
                                        var outputData = image.AsJPEG();
                                        string base64 = outputData.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    });
    

    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

Sign In or Register to comment.