0

I'm developing a photography software in Xamarin.iOS. I'm using the PHPhoto class.

When I take a photo, I'm trying to send it to the web. I plan to send them in byte[]. Where can I get the data for the photo in the DidFinishCapture method? When I start the debug launch, I see that PHPhotoLibrary.SharedPhotoLibrary.PerformChanges() will automatically save the photos to the photo library.

How do I retrieve photos by byte[]? I couldn't find it in PhotoData.

I thought there was a path for the saved photos in LivePhotoCompanionMovieUrl, but this is always null.

    public partial class PhotoCaptureDelegate : AVCapturePhotoCaptureDelegate
    {
        public override void DidFinishCapture(AVCapturePhotoOutput captureOutput, 
                                              AVCaptureResolvedPhotoSettings resolvedSettings, 
                                              NSError error)
        {
            PHPhotoLibrary.RequestAuthorization(status =>
            {
                if (status == PHAuthorizationStatus.Authorized)
                {
                    PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
                    {
                        var creationRequest = PHAssetCreationRequest.CreationRequestForAsset();
                        creationRequest.AddResource(PHAssetResourceType.Photo, PhotoData, null);

                        var url = LivePhotoCompanionMovieUrl;
                        if (url != null)
                        {
                            var livePhotoCompanionMovieFileResourceOptions = new PAssetResourceCreationOptions
                            {
                                ShouldMoveFile = true
                            };
                            creationRequest.AddResource(PHAssetResourceType.PairedVideo, url, livePhotoCompanionMovieFileResourceOptions);
                        }
                    }, (success, err) =>
                    {
                        if (err != null)
                            Debug.WriteLine($"Error occurered while saving photo to photo library: {error.LocalizedDescription}");
                    });
                }
            });
        }
    }
}

1 Answers1

0

If you want to convert the photo to Byte array , you could use the plugin Media.Plugin from Nuget to pick or take photo .

await CrossMedia.Current.Initialize();
    
    if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
    {
        DisplayAlert("No Camera", ":( No camera available.", "OK");
        return;
    }

    var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
    {
        SaveToAlbum = true,
        Name = "test.jpg"
    });

    if (file == null)
        return;

Then convert it to Stream firstly before convert it to byte array .

 Stream stream = file.GetStream();
public byte[] GetImageStreamAsBytes(Stream input)
{
  var buffer = new byte[16*1024];
  using (MemoryStream ms = new MemoryStream())
  {
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
                ms.Write(buffer, 0, read);
    }
      return ms.ToArray();
   }
}

Now you can get the byte array like following

var imgDate = GetImageStreamAsBytes(stream);

Update

You could use UIImagePickerController

 UIImagePickerController imagePicker;

And invoke the following lines when need to take photo

      imagePicker = new UIImagePickerController
        {
            SourceType = UIImagePickerControllerSourceType.Camera,
            MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.Camera)
        };

        // Set event handlers
        imagePicker.FinishedPickingMedia += ImagePicker_FinishedPickingMedia; ;
        imagePicker.Canceled += ImagePicker_Canceled; ;

        // Present UIImagePickerController;
        this.PresentViewController(imagePicker, true, null);
        private void ImagePicker_Canceled(object sender, EventArgs e)
        {
            imagePicker.DismissModalViewController(true);
        }

        private void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
        {
            UIImage image = args.EditedImage ?? args.OriginalImage;

            if (image != null)
            {
                // Convert UIImage to .NET Stream object
                NSData data;
                if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
                {
                    data = image.AsPNG();
                }
                else
                {
                    data = image.AsJPEG(1);
                }

                Stream stream = data.AsStream();

              
            }
            else
            {
               
            }
            imagePicker.DismissModalViewController(true);
        }
public byte[] GetImageStreamAsBytes(Stream input)
{
  var buffer = new byte[16*1024];
  using (MemoryStream ms = new MemoryStream())
  {
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
                ms.Write(buffer, 0, read);
    }
      return ms.ToArray();
   }
}

Now you can get the byte array like following

var imgDate = GetImageStreamAsBytes(stream);
Lucas Zhang
  • 18,630
  • 3
  • 12
  • 22
  • Thanks for the prompt. I see that Media.Plagin seems to work, and I thought it might work. But no, it didn't work. Media.Plagin can be NuGet for .NET Standard projects. I'm currently working on a Xamarin.iOS project, so I got an error. Error A reference could not be added. The package 'Xamarin.Essentials' tried to add a framework reference to 'System.Drawing.Common.dll', but it was not found in the GAC. This could be a bug in the package. Contact the owner of the package for assistance. Error HRESULT E_FAIL was returned from a call to a COM component. –  Sep 29 '20 at 08:25
  • Did you get the UIImage in your code when using UIImagePickerController ? – Lucas Zhang Sep 29 '20 at 13:35
  • Check my update answer . And don't forget to accept it if it is helpful to you :) – Lucas Zhang Sep 29 '20 at 13:57
  • Thanks for the advice. I have verified it and it works!!! I changed SourceType = UIMAGEPickerControllerSourceType.PhotoLibrary, However, using FilePicker requires the user to do some manipulation. I want to upload to the web automatically after I take a picture, so please continue to tell me how to get byte[] directly without using FilePicker. –  Sep 30 '20 at 08:35
  • Thank you for your comment. Yes, I am aware that the first Media.Plungin code does not use Picker. I know the first Media.Plungin code does not use Picker. But unfortunately the Media.Plugin doesn't work. That's why I'm currently running it in the Update's Picker code. –  Oct 01 '20 at 00:46
  • The Update's Picker code is working, and I got the UIImage in the code. –  Oct 01 '20 at 02:34
  • That's great ! You could accept my answer if it helps you :) – Lucas Zhang Oct 01 '20 at 02:36