We have several exciting new features for our existing controls. One of the most practical features is the GetImage() method, which captures an image of a control as a byte array. In this article we cover basic implementation of the GetImage() method of the FlexChart control in a Xamarin.Forms portable class library project, creating an interface for saving the picture to disk, and using a DependencyService to automatically call the correct logic for saving an image based on the platform. The GetImage() method is beneficial in any scenario where an image file is easier to work with, such as incorporating graphics into an email, document, or presentation. A more obvious scenario is when a user simply wants to preserve a snapshot of data from their mobile application. Though saving an image can be accomplished in a straightforward manner on the native platforms, doing so in Xamarin.Forms requires a more nuanced approach, since it requires accommodating iOS, Android, and Windows Phone all at once.

Use GetImage() to Return a Byte Array

The first step in this walkthrough is to use GetImage() to return a byte array. This is quite simple to accomplish. Assuming we’ve already created a FlexChart object (called “chart” here), the usage to return a byte array is:



chart.GetImage();  


Creating the byte array is thus quite easy, but saving the image to disk is complicated by the matter of each platform having its own capabilities and file system structure. Fortunately, Xamarin.Forms provides us with the ability to implement a DependencyService, which we use in tandem with our own interface, so we can provide platform-specific implementations for saving our byte array to disk. The interface is fairly simple, because we're really only interested in passing the byte array and a filename when we save the image to disk.



public interface IPicture  
{  
    void SavePictureToDisk (string filename, byte[] imageData);  
}  


In this manner, we can provide a basic API for saving our byte arrays. The portable class library will use a dependency service to call the correct native implementation of the interface. We’ll eventually create classes in each platform-specific project for file saving, and our DependencyService will delegate image saving to the appropriate class. The usage for the DependencyService is:



DependencyService.Get<IPicture>().SavePictureToDisk("ChartImage", chart.GetImage());  


Create Classes in Platform-Specific Projects

iOS Project

The next step is to create classes in each of our platform-specific projects to work with IPicture. Each class will handle saving somewhat differently. For iOS, this is a relatively straightforward call to the SaveToPhotosAlbum() Method:



[assembly: Xamarin.Forms.Dependency(typeof(Picture_iOS))]  

namespace FlexChartImageSave.iOS  
{  
    public class Picture_iOS: IPicture  
    {  
        public void SavePictureToDisk(string filename, byte[] imageData)  
        {  
            var chartImage = new UIImage(NSData.FromArray(imageData));  
            chartImage.SaveToPhotosAlbum((image, error) =>  
            {  
                //you can retrieve the saved UI Image as well if needed using  
                //var i = image as UIImage;  
                if(error != null)  
                {  
                    Console.WriteLine(error.ToString());  
                }  
            });  
        }  
    }  
}  


Note that it's important to include the following line for the DependencyService to work:



[assembly: Xamarin.Forms.Dependency (typeof (Picture_iOS))]  


Android Project

The implementation for Android is similar, but before we write any code, we need to give our solution permission to write to the external storage of a device. This requires navigating to the Droid Project’s properties, choosing Android Manifest, and selecting Write_External_Storage from the Required permissions list: Xuni FlexChart for Xamarin Platform, Android Now we can implement our picture saving code for Android. This is a two-step process on Android where the first step involves saving our picture to the external storage of the device, and the second step is to use mediaScanIntent to add the saved image to the Gallery. We'll also generate a timestamp to the file name to ensure unique image names.



[assembly: Xamarin.Forms.Dependency(typeof(Picture_Droid))]  

namespace FlexChartImageSave.Droid  
{  
    public class Picture_Droid : IPicture  
    {  
        public void SavePictureToDisk(string filename, byte[] imageData)  
        {  
            var dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim);  
            var pictures = dir.AbsolutePath;  
            //adding a time stamp time file name to allow saving more than one image... otherwise it overwrites the previous saved image of the same name  
            string name = filename + System.DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg";  
            string filePath = System.IO.Path.Combine(pictures, name);  
            try  
            {  
                System.IO.File.WriteAllBytes(filePath, imageData);  
                //mediascan adds the saved image into the gallery  
                var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);  
                mediaScanIntent.SetData(Uri.FromFile(new File(filePath)));  
                Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent);  
            }  
            catch(System.Exception e)  
            {  
                System.Console.WriteLine(e.ToString());  
            }  

        }  
    }  
}  


Windows Phone Project

The Windows Phone portion also requires permission for our application to save the images to the device. To add this capability navigate to the WinPhone project, select Properties, and open the WMAppManifest.xml file. Select the Capabilities tab and check the box for ID_CAP_MEDIALIB_PHOTO: Blog_MEDIALIB_PHOTO Saving the image to a Windows Phone device is mostly a matter of getting the byte array data into a WriteableBitmap. This requires loading the data into a memoryStream, creating a bitmap image with the memory stream as its source, and finally instantiating a new WriteableBitmap using the bitmapImage in the constructor. From here, we can create a jpeg and save it to the Media Library of the device.


[assembly: Xamarin.Forms.Dependency(typeof(Picture_WinPhone))]  

namespace FlexChartImageSave.WinPhone  
{  
    public class Picture_WinPhone : IPicture  
    {  
      public async void SavePictureToDisk(string filename, byte[] imageData)  
      {  
            //adding a timestamp to create a unique name  
            string name = filename + System.DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg";  

            //this could also be accomplished with a guid instead  
            //var tempName = Guid.NewGuid().ToString();  

            var store = IsolatedStorageFile.GetUserStoreForApplication();  
            var bitmapImage = new BitmapImage();  
            var memoryStream = new MemoryStream(imageData);  
            bitmapImage.SetSource(memoryStream);  
            WriteableBitmap b = new WriteableBitmap(bitmapImage);  
            using (var fileStream = store.CreateFile(name))  
            {  
                 Extensions.SaveJpeg(b, fileStream, b.PixelWidth, b.PixelHeight, 0, 100);  
            }  
            using (var fileStream = store.OpenFile(name, FileMode.Open, FileAccess.Read))  
            {  
                var library = new MediaLibrary();  
                try {  

                     library.SavePicture(filename, fileStream);  
                }  
                catch(Exception e)  
                {  
                    Console.WriteLine(e.ToString());  
                }      
            }  
       }  
    }  
}  


Add the Dependency Servie to the Portable Class Library Project

Now that we have the logic for saving the image on each of the three platforms, we can add the DependencyService to the shared project. In this sample, we’ll add a button click event and call the DependencyService.



async void OnButtonClicked(object sender, EventArgs args)  
{  
       Button button = (Button)sender;     
       //uses the IPicture interface to use the appropriate saving mechanism from the picture class in each individual project  
       DependencyService.Get<IPicture>().SavePictureToDisk("ChartImage", flexChart.GetImage());  
       //generic success message  
       await DisplayAlert("Image Save",  
           "The image has been saved",  
           "OK");        
}  

Now we can build and run the application. Xuni FlexChart for Xamarin Platform Media Library DependencyServices provide a strong tool for creating seamless application behaviors using specific code tailored for each platform. Combining this functionality with Xuni’s new getImage() method allows you to readily preserve data visualizations as images that can easily be shared and incorporated into other documents. The new release of Xuni adds powerful new features to enhance your mobile development so be sure to check out our other blogs deeper looks into new controls and features.

Download the Sample >>

Read more about FlexChart >>

Try ComponentOne's Xamarin controls

Download the latest version of ComponentOne Studio for Xamarin

Download Now!