How To Create And Use A Blurred Image In Xamarin.Forms

 Introduction

This article demonstrates how to create and use a blurred image in Xamarin.Forms, XAML, and C#. This article starts with the introduction of the BlurredImage tag in XAML.

 BlurredImage in Xamarin

Implementation

Open Visual Studio and select a New Project.

BlurredImage in Xamarin

Now, select Cross-Platform App, give the project a name, and set the project path. Then, click OK.

BlurredImage in Xamarin

Select the template as "Blank App" and code sharing as "PCL".

BlurredImage in Xamarin

Right-click on PCL Project and select Add >> New Item or Add >> Class.

BlurredImage in Xamarin

We are creating a class BlurredImage.cs and writing the following C# code.

BlurredImage in Xamarin

BlurredImage.cs

  1. public class BlurredImage : Image  
  2.     {  
  3.     }  

This property is set in the Android project as well as in iOS project.

Let us start with Android. We are creating a class in Android project and rendering the image.

BlurredImage in Xamarin

 Then, we set all the properties when initializing the PCL Project.

BlurredImage in Xamarin

Please make sure of the dependency ([assembly: ExportRenderer(typeof(BlurredImage), typeof(BlurredImage Renderer))]) of Android (BlurredImageRndered) and PCL (BlurredImage).

BlurredImageRendere.cd

  1. public class BlurredImageRenderer : ViewRenderer<BlurredImage, ImageView>  
  2.   {  
  3.       private bool _isDisposed;  
  4.   
  5.       private const float BITMAP_SCALE = 0.3f;  
  6.       private const float RESIZE_SCALE = 0.2f;  
  7.   
  8.       public BlurredImageRenderer()  
  9.       {  
  10.           AutoPackage = false;  
  11.       }  
  12.   
  13.       protected override void OnElementChanged(ElementChangedEventArgs<BlurredImage> e)  
  14.       {  
  15.           base.OnElementChanged(e);  
  16.   
  17.           if (Control == null)  
  18.           {  
  19.               var imageView = new BlurredImageView(Context);  
  20.               SetNativeControl(imageView);  
  21.           }  
  22.   
  23.           UpdateBitmap(e.OldElement);  
  24.           UpdateAspect();  
  25.       }  
  26.   
  27.       protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)  
  28.       {  
  29.           base.OnElementPropertyChanged(sender, e);  
  30.   
  31.           if (e.PropertyName == Image.SourceProperty.PropertyName)  
  32.           {  
  33.               UpdateBitmap(null);  
  34.               return;  
  35.           }  
  36.           if (e.PropertyName == Image.AspectProperty.PropertyName)  
  37.           {  
  38.               UpdateAspect();  
  39.           }  
  40.       }  
  41.   
  42.       protected override void Dispose(bool disposing)  
  43.       {  
  44.           if (_isDisposed)  
  45.           {  
  46.               return;  
  47.           }  
  48.           _isDisposed = true;  
  49.           BitmapDrawable bitmapDrawable;  
  50.           if (disposing && Control != null && (bitmapDrawable = (Control.Drawable as BitmapDrawable)) != null)  
  51.           {  
  52.               Bitmap bitmap = bitmapDrawable.Bitmap;  
  53.               if (bitmap != null)  
  54.               {  
  55.                   bitmap.Recycle();  
  56.                   bitmap.Dispose();  
  57.               }  
  58.           }  
  59.           base.Dispose(disposing);  
  60.       }  
  61.   
  62.       private void UpdateAspect()  
  63.       {  
  64.           using (ImageView.ScaleType scaleType = ToScaleType(Element.Aspect))  
  65.           {  
  66.               Control.SetScaleType(scaleType);  
  67.           }  
  68.       }  
  69.   
  70.       private static ImageView.ScaleType ToScaleType(Aspect aspect)  
  71.       {  
  72.           switch (aspect)  
  73.           {  
  74.               case Aspect.AspectFill:  
  75.                   return ImageView.ScaleType.CenterCrop;  
  76.               case Aspect.Fill:  
  77.                   return ImageView.ScaleType.FitXy;  
  78.           }  
  79.           return ImageView.ScaleType.FitCenter;  
  80.       }  
  81.   
  82.       private async void UpdateBitmap(Image previous = null)  
  83.       {  
  84.           Bitmap bitmap = null;  
  85.           ImageSource source = Element.Source;  
  86.           if (previous == null || !object.Equals(previous.Source, Element.Source))  
  87.           {  
  88.               SetIsLoading(true);  
  89.               ((BlurredImageView)base.Control).SkipInvalidate();  
  90.   
  91.               // I'm not sure where this comes from.  
  92.               Control.SetImageResource(17170445);  
  93.               if (source != null)  
  94.               {  
  95.                   try  
  96.                   {  
  97.                       bitmap = await GetImageFromImageSource(source, Context);  
  98.                   }  
  99.                   catch (TaskCanceledException)  
  100.                   {  
  101.                   }  
  102.                   catch (IOException)  
  103.                   {  
  104.                   }  
  105.                   catch (NotImplementedException)  
  106.                   {  
  107.                   }  
  108.               }  
  109.               if (Element != null && object.Equals(Element.Source, source))  
  110.               {  
  111.                   if (!_isDisposed)  
  112.                   {  
  113.                       Control.SetImageBitmap(bitmap);  
  114.                       if (bitmap != null)  
  115.                       {  
  116.                           bitmap.Dispose();  
  117.                       }  
  118.                       SetIsLoading(false);  
  119.                       ((IVisualElementController)base.Element).NativeSizeChanged();  
  120.                   }  
  121.               }  
  122.           }  
  123.       }  
  124.   
  125.       private async Task<Bitmap> GetImageFromImageSource(ImageSource imageSource, Context context)  
  126.       {  
  127.           IImageSourceHandler handler;  
  128.   
  129.           if (imageSource is FileImageSource)  
  130.           {  
  131.               handler = new FileImageSourceHandler();  
  132.           }  
  133.           else if (imageSource is StreamImageSource)  
  134.           {  
  135.               handler = new StreamImagesourceHandler(); // sic  
  136.           }  
  137.           else if (imageSource is UriImageSource)  
  138.           {  
  139.               handler = new ImageLoaderSourceHandler(); // sic  
  140.           }  
  141.           else  
  142.           {  
  143.               throw new NotImplementedException();  
  144.           }  
  145.   
  146.           var originalBitmap = await handler.LoadImageAsync(imageSource, context);  
  147.   
  148.           // Blur it twice!  
  149.           var blurredBitmap = await Task.Run(() => CreateBlurredImage(CreateResizedImage(originalBitmap), 25));  
  150.   
  151.           return blurredBitmap;  
  152.       }  
  153.   
  154.       private Bitmap CreateBlurredImage(Bitmap originalBitmap, int radius)  
  155.       {  
  156.           // Create another bitmap that will hold the results of the filter.  
  157.           Bitmap blurredBitmap;  
  158.           blurredBitmap = Bitmap.CreateBitmap(originalBitmap);  
  159.   
  160.           // Create the Renderscript instance that will do the work.  
  161.           RenderScript rs = RenderScript.Create(Context);  
  162.   
  163.           // Allocate memory for Renderscript to work with  
  164.           Allocation input = Allocation.CreateFromBitmap(rs, originalBitmap, Allocation.MipmapControl.MipmapFull, AllocationUsage.Script);  
  165.           Allocation output = Allocation.CreateTyped(rs, input.Type);  
  166.   
  167.           // Load up an instance of the specific script that we want to use.  
  168.           ScriptIntrinsicBlur script = ScriptIntrinsicBlur.Create(rs, Android.Renderscripts.Element.U8_4(rs));  
  169.           script.SetInput(input);  
  170.   
  171.           // Set the blur radius  
  172.           script.SetRadius(radius);  
  173.   
  174.           // Start Renderscript working.  
  175.           script.ForEach(output);  
  176.   
  177.           // Copy the output to the blurred bitmap  
  178.           output.CopyTo(blurredBitmap);  
  179.   
  180.           return blurredBitmap;  
  181.       }  
  182.   
  183.       private Bitmap CreateResizedImage(Bitmap originalBitmap)  
  184.       {  
  185.           int width = Convert.ToInt32(Math.Round(originalBitmap.Width * BITMAP_SCALE));  
  186.           int height = Convert.ToInt32(Math.Round(originalBitmap.Height * BITMAP_SCALE));  
  187.   
  188.           // Create another bitmap that will hold the results of the filter.  
  189.           Bitmap inputBitmap = Bitmap.CreateScaledBitmap(originalBitmap, width, height, false);  
  190.           Bitmap outputBitmap = Bitmap.CreateBitmap(inputBitmap);  
  191.   
  192.           // Create the Renderscript instance that will do the work.  
  193.           RenderScript rs = RenderScript.Create(Context);  
  194.   
  195.   
  196.           Allocation tmpIn = Allocation.CreateFromBitmap(rs, inputBitmap);  
  197.           Allocation tmpOut = Allocation.CreateFromBitmap(rs, outputBitmap);  
  198.   
  199.           // Allocate memory for Renderscript to work with  
  200.           var t = Android.Renderscripts.Type.CreateXY(rs, tmpIn.Element, Convert.ToInt32(width * RESIZE_SCALE), Convert.ToInt32(height * RESIZE_SCALE));  
  201.           Allocation tmpScratch = Allocation.CreateTyped(rs, t);  
  202.   
  203.           ScriptIntrinsicResize theIntrinsic = ScriptIntrinsicResize.Create(rs);  
  204.   
  205.           // Resize the original img down.  
  206.           theIntrinsic.SetInput(tmpIn);  
  207.           theIntrinsic.ForEach_bicubic(tmpScratch);  
  208.   
  209.           // Resize smaller img up.  
  210.           theIntrinsic.SetInput(tmpScratch);  
  211.           theIntrinsic.ForEach_bicubic(tmpOut);  
  212.           tmpOut.CopyTo(outputBitmap);  
  213.   
  214.           return outputBitmap;  
  215.       }  
  216.   
  217.       private class BlurredImageView : ImageView  
  218.       {  
  219.           private bool _skipInvalidate;  
  220.   
  221.           public BlurredImageView(Context context) : base(context)  
  222.           {  
  223.           }  
  224.   
  225.           public override void Invalidate()  
  226.           {  
  227.               if (this._skipInvalidate)  
  228.               {  
  229.                   this._skipInvalidate = false;  
  230.                   return;  
  231.               }  
  232.               base.Invalidate();  
  233.           }  
  234.   
  235.           public void SkipInvalidate()  
  236.           {  
  237.               this._skipInvalidate = true;  
  238.           }  
  239.       }  
  240.   
  241.       private static FieldInfo _isLoadingPropertyKeyFieldInfo;  
  242.   
  243.       private static FieldInfo IsLoadingPropertyKeyFieldInfo  
  244.       {  
  245.           get  
  246.           {  
  247.               if (_isLoadingPropertyKeyFieldInfo == null)  
  248.               {  
  249.                   _isLoadingPropertyKeyFieldInfo = typeof(Image).GetField("IsLoadingPropertyKey", BindingFlags.Static | BindingFlags.NonPublic);  
  250.               }  
  251.               return _isLoadingPropertyKeyFieldInfo;  
  252.           }  
  253.       }  
  254.   
  255.       private void SetIsLoading(bool value)  
  256.       {  
  257.           var fieldInfo = IsLoadingPropertyKeyFieldInfo;  
  258.           ((IElementController)base.Element).SetValueFromRenderer((BindablePropertyKey)fieldInfo.GetValue(null), value);  
  259.       }  
  260.   }  

Now, it's time to go to the iOS project. Again, set the PCL(BlurredImage) property in IOS Project.

We are creating a Class, so right click on iOS Project and select Apple. Then, select "Class" and give this class a name as BlurredImageRndered.cs.

BlurredImage in Xamarin

Now, let us write some code for Image and Set Property.

BlurredImageRndered.cs

  1. public class BlurredImageRenderer : ImageRenderer  
  2.    {  
  3.        protected override void OnElementChanged(ElementChangedEventArgs<Image> e)  
  4.        {  
  5.            if (Control == null)  
  6.            {  
  7.                SetNativeControl(new BlurredImageView  
  8.                {  
  9.                    ContentMode = UIViewContentMode.ScaleAspectFit,  
  10.                    ClipsToBounds = true  
  11.                });  
  12.            }  
  13.   
  14.            base.OnElementChanged(e);  
  15.        }  
  16.   
  17.        private class BlurredImageView : UIImageView  
  18.        {  
  19.            public override UIImage Image  
  20.            {  
  21.                get { return base.Image; }  
  22.                set  
  23.                {  
  24.                    // This may take up to a second so don't block the UI thread.  
  25.                    Task.Run(() =>  
  26.                    {  
  27.                        using (var context = CIContext.Create())  
  28.                        using (var inputImage = CIImage.FromCGImage(value.CGImage))  
  29.                        using (var filter = new CIGaussianBlur() { Image = inputImage, Radius = 5 })  
  30.                        using (var resultImage = context.CreateCGImage(filter.OutputImage, inputImage.Extent))  
  31.                        {  
  32.                            InvokeOnMainThread(() => base.Image = new UIImage(resultImage));  
  33.                        }  
  34.                    });  
  35.                }  
  36.            }  
  37.        }  
  38.    }  

Go to the PCL project and write this code in MainPage.xaml.

BlurredImage in Xamarin

As you can see in the above code, we have to set the view reference in xmlns:custom="clr-namespace:BlurImage" MainPage.xaml.

Write the following code for BlurredImage.

MainPage.xaml

  1. <Grid>  
  2.         <AbsoluteLayout>  
  3.             <controls:BlurredImage AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"  
  4.                                    InputTransparent="false" x:Name="artwork"   
  5.                 HorizontalOptions="FillAndExpand" Aspect="Fill" VerticalOptions="FillAndExpand" Source="icon"/>  
  6.         </AbsoluteLayout>  
  7.         <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">  
  8.             <Label Text="Blurred Image Demo" TextColor="Black"   
  9.                    FontAttributes="Bold" FontSize="Medium" HorizontalOptions="CenterAndExpand"/>  
  10.             <Image Source="icon" Aspect="Fill" VerticalOptions="CenterAndExpand"   
  11.                    HorizontalOptions="CenterAndExpand"/>  
  12.               
  13.         </StackLayout>  
  14.     </Grid>  
BlurredImage in Xamarin

Now, you will have your BlurredImage working!!


Similar Articles