Converting an HEIC image to Jpg and upload to the Server in Xamarin iOS
Asked Answered
E

2

4

I am trying to convert the HEIC image to Jpg from below code in using Dependency Service and trying to display with Image and uploading to Web API.. But both are not working, Is it a correct way of doing HEIC conversion to Jpg? if not please suggest me how to achieve this.

Dependency Service method:

public byte[] GetJpgFromHEIC(string path)
{
        byte[] imageAsBytes = File.ReadAllBytes(path);
        UIImage images = new UIImage(NSData.FromArray(imageAsBytes));
        byte[] bytes = images.AsJPEG().ToArray();
        // Stream imgStream = new MemoryStream(bytes);

        return bytes;
}

In Xaml Code Behind Displaying Image:

Image image = new Image(){};
byte[] bytes = DependencyService.Get<ICommonHelper>
                      ().GetJpgFromHEIC(fileData.FileName);
image.Source = ImageSource.FromStream(() => new MemoryStream(bytes));

Uploading code to web API: Tried in both StreamContent and ByteArrayContent as HttpContent like below

   HttpResponseMessage response = null;

    string filename = data.FileName; // here data object is a FileData, picked from using FilePicker.

    byte[] fileBytes = DependencyService.Get<ICommonHelper>().GetJpgFromHEIC(data.FilePath);

            HttpContent fileContent = new ByteArrayContent(fileBytes);

    // Stream fileStream = new MemoryStream(fileBytes);
    // HttpContent fileContent = new StreamContent(fileStream);

    fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name =         
             "file", FileName = data.FileName };
    fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
            using (var formData = new MultipartFormDataContent())
            {
                formData.Add(fileContent);
                response = await client.PostAsync(uri, formData);
                if (response.IsSuccessStatusCode)
                {
                    Debug.WriteLine(@" Upload CommentsAttachments SUCCESS>> " + response.Content.ToString());
                }
            }

Please suggest me What I am doing wrong and how to achieve and possible ways for this conversion and upload.

Thank you,

Electrometer answered 9/1, 2019 at 5:35 Comment(0)
P
4

Something like this works for a HEIC path/file (or any valid iOS supported image format). I'm using the sample autumn_1440x960.heic.

using (var image = UIImage.FromFile(path))
using (var jpg = image.AsJPEG(0.5f))
using (var stream = jpg.AsStream())
{
    // do something with your stream, just saving it to the cache directory as an example...

    using (var cache = NSFileManager.DefaultManager.GetUrl(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.All, null, true, out var nsError))
    using (var fileStream = new FileStream(Path.Combine(cache.Path, "cache.jpg"), FileMode.Create, FileAccess.Write))
    {
        stream.CopyTo(fileStream);
        imageView1.Image = UIImage.FromFile(Path.Combine(cache.Path, "cache.jpg"));
    }
}

FYI: Copying byte[] around is very inefficient, you might just want to pass the original stream back and use that to populate your form content to post, just make you Dispose it otherwise you will leak native allocations...

Priestley answered 9/1, 2019 at 6:33 Comment(0)
M
1

First retrieve compressed image stream from heic image path and saved it to other location to upload it on server. Here is the code for saving compressed image from high definition images :

public async Task<Stream> RetriveCompressedImageStreamFromLocation(string location)
    {
        Stream imgStream = null;
        try
        {
            byte[] imageAsBytes = File.ReadAllBytes(location);
            UIKit.UIImage images = new UIKit.UIImage(Foundation.NSData.FromArray(imageAsBytes));
            byte[] bytes = images.AsJPEG(0.5f).ToArray();
            Stream imgStreamFromByte = new MemoryStream(bytes);
            imgStream = imgStreamFromByte;
            return imgStream;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        return imgStream;
    }

Then, save that stream to desired location and retrieve from that location when needed.

public async Task<string> SaveImageFile(Stream StreamToWrite)
    {
        string savedImgFilePath = string.Empty;
        try
        {
            byte[] imgByteData = null;
            using (MemoryStream ms = new MemoryStream())
            {
                StreamToWrite.CopyTo(ms);
                imgByteData = ms.ToArray();
            }

            string FileName = “MyImg.jpg";
            var Docdirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var directory = Docdirectory + “/MyImages”;

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
            var path = Path.Combine(directory, FileName);
            if (File.Exists(path))
            {
                File.Delete(path);
            }
            File.WriteAllBytes(path, imgByteData);
            Debug.WriteLine(“Image File Path=== " + path);
            savedImgFilePath = path;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        return savedImgFilePath;
    }

Now just need to retrieve bytes from saved path and pass it for uploading on server as MultipartFormDataContent.

Mcreynolds answered 30/9, 2020 at 12:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.