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.
Implementation
Open Visual Studio and select a New Project.
Now, select Cross-Platform App, give the project a name, and set the project path. Then, click OK.
Select the template as "Blank App" and code sharing as "PCL".
Right-click on PCL Project and select Add >> New Item or Add >> Class.
We are creating a class BlurredImage.cs and writing the following C# code.
BlurredImage.cs
- public class BlurredImage : Image
- {
- }
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.
Then, we set all the properties when initializing the PCL Project.
Please make sure of the dependency ([assembly: ExportRenderer(typeof(BlurredImage), typeof(BlurredImage Renderer))]) of Android (BlurredImageRndered) and PCL (BlurredImage).
BlurredImageRendere.cd
- public class BlurredImageRenderer : ViewRenderer<BlurredImage, ImageView>
- {
- private bool _isDisposed;
-
- private const float BITMAP_SCALE = 0.3f;
- private const float RESIZE_SCALE = 0.2f;
-
- public BlurredImageRenderer()
- {
- AutoPackage = false;
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs<BlurredImage> e)
- {
- base.OnElementChanged(e);
-
- if (Control == null)
- {
- var imageView = new BlurredImageView(Context);
- SetNativeControl(imageView);
- }
-
- UpdateBitmap(e.OldElement);
- UpdateAspect();
- }
-
- protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == Image.SourceProperty.PropertyName)
- {
- UpdateBitmap(null);
- return;
- }
- if (e.PropertyName == Image.AspectProperty.PropertyName)
- {
- UpdateAspect();
- }
- }
-
- protected override void Dispose(bool disposing)
- {
- if (_isDisposed)
- {
- return;
- }
- _isDisposed = true;
- BitmapDrawable bitmapDrawable;
- if (disposing && Control != null && (bitmapDrawable = (Control.Drawable as BitmapDrawable)) != null)
- {
- Bitmap bitmap = bitmapDrawable.Bitmap;
- if (bitmap != null)
- {
- bitmap.Recycle();
- bitmap.Dispose();
- }
- }
- base.Dispose(disposing);
- }
-
- private void UpdateAspect()
- {
- using (ImageView.ScaleType scaleType = ToScaleType(Element.Aspect))
- {
- Control.SetScaleType(scaleType);
- }
- }
-
- private static ImageView.ScaleType ToScaleType(Aspect aspect)
- {
- switch (aspect)
- {
- case Aspect.AspectFill:
- return ImageView.ScaleType.CenterCrop;
- case Aspect.Fill:
- return ImageView.ScaleType.FitXy;
- }
- return ImageView.ScaleType.FitCenter;
- }
-
- private async void UpdateBitmap(Image previous = null)
- {
- Bitmap bitmap = null;
- ImageSource source = Element.Source;
- if (previous == null || !object.Equals(previous.Source, Element.Source))
- {
- SetIsLoading(true);
- ((BlurredImageView)base.Control).SkipInvalidate();
-
-
- Control.SetImageResource(17170445);
- if (source != null)
- {
- try
- {
- bitmap = await GetImageFromImageSource(source, Context);
- }
- catch (TaskCanceledException)
- {
- }
- catch (IOException)
- {
- }
- catch (NotImplementedException)
- {
- }
- }
- if (Element != null && object.Equals(Element.Source, source))
- {
- if (!_isDisposed)
- {
- Control.SetImageBitmap(bitmap);
- if (bitmap != null)
- {
- bitmap.Dispose();
- }
- SetIsLoading(false);
- ((IVisualElementController)base.Element).NativeSizeChanged();
- }
- }
- }
- }
-
- private async Task<Bitmap> GetImageFromImageSource(ImageSource imageSource, Context context)
- {
- IImageSourceHandler handler;
-
- if (imageSource is FileImageSource)
- {
- handler = new FileImageSourceHandler();
- }
- else if (imageSource is StreamImageSource)
- {
- handler = new StreamImagesourceHandler();
- }
- else if (imageSource is UriImageSource)
- {
- handler = new ImageLoaderSourceHandler();
- }
- else
- {
- throw new NotImplementedException();
- }
-
- var originalBitmap = await handler.LoadImageAsync(imageSource, context);
-
-
- var blurredBitmap = await Task.Run(() => CreateBlurredImage(CreateResizedImage(originalBitmap), 25));
-
- return blurredBitmap;
- }
-
- private Bitmap CreateBlurredImage(Bitmap originalBitmap, int radius)
- {
-
- Bitmap blurredBitmap;
- blurredBitmap = Bitmap.CreateBitmap(originalBitmap);
-
-
- RenderScript rs = RenderScript.Create(Context);
-
-
- Allocation input = Allocation.CreateFromBitmap(rs, originalBitmap, Allocation.MipmapControl.MipmapFull, AllocationUsage.Script);
- Allocation output = Allocation.CreateTyped(rs, input.Type);
-
-
- ScriptIntrinsicBlur script = ScriptIntrinsicBlur.Create(rs, Android.Renderscripts.Element.U8_4(rs));
- script.SetInput(input);
-
-
- script.SetRadius(radius);
-
-
- script.ForEach(output);
-
-
- output.CopyTo(blurredBitmap);
-
- return blurredBitmap;
- }
-
- private Bitmap CreateResizedImage(Bitmap originalBitmap)
- {
- int width = Convert.ToInt32(Math.Round(originalBitmap.Width * BITMAP_SCALE));
- int height = Convert.ToInt32(Math.Round(originalBitmap.Height * BITMAP_SCALE));
-
-
- Bitmap inputBitmap = Bitmap.CreateScaledBitmap(originalBitmap, width, height, false);
- Bitmap outputBitmap = Bitmap.CreateBitmap(inputBitmap);
-
-
- RenderScript rs = RenderScript.Create(Context);
-
-
- Allocation tmpIn = Allocation.CreateFromBitmap(rs, inputBitmap);
- Allocation tmpOut = Allocation.CreateFromBitmap(rs, outputBitmap);
-
-
- var t = Android.Renderscripts.Type.CreateXY(rs, tmpIn.Element, Convert.ToInt32(width * RESIZE_SCALE), Convert.ToInt32(height * RESIZE_SCALE));
- Allocation tmpScratch = Allocation.CreateTyped(rs, t);
-
- ScriptIntrinsicResize theIntrinsic = ScriptIntrinsicResize.Create(rs);
-
-
- theIntrinsic.SetInput(tmpIn);
- theIntrinsic.ForEach_bicubic(tmpScratch);
-
-
- theIntrinsic.SetInput(tmpScratch);
- theIntrinsic.ForEach_bicubic(tmpOut);
- tmpOut.CopyTo(outputBitmap);
-
- return outputBitmap;
- }
-
- private class BlurredImageView : ImageView
- {
- private bool _skipInvalidate;
-
- public BlurredImageView(Context context) : base(context)
- {
- }
-
- public override void Invalidate()
- {
- if (this._skipInvalidate)
- {
- this._skipInvalidate = false;
- return;
- }
- base.Invalidate();
- }
-
- public void SkipInvalidate()
- {
- this._skipInvalidate = true;
- }
- }
-
- private static FieldInfo _isLoadingPropertyKeyFieldInfo;
-
- private static FieldInfo IsLoadingPropertyKeyFieldInfo
- {
- get
- {
- if (_isLoadingPropertyKeyFieldInfo == null)
- {
- _isLoadingPropertyKeyFieldInfo = typeof(Image).GetField("IsLoadingPropertyKey", BindingFlags.Static | BindingFlags.NonPublic);
- }
- return _isLoadingPropertyKeyFieldInfo;
- }
- }
-
- private void SetIsLoading(bool value)
- {
- var fieldInfo = IsLoadingPropertyKeyFieldInfo;
- ((IElementController)base.Element).SetValueFromRenderer((BindablePropertyKey)fieldInfo.GetValue(null), value);
- }
- }
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.
Now, let us write some code for Image and Set Property.
BlurredImageRndered.cs
- public class BlurredImageRenderer : ImageRenderer
- {
- protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
- {
- if (Control == null)
- {
- SetNativeControl(new BlurredImageView
- {
- ContentMode = UIViewContentMode.ScaleAspectFit,
- ClipsToBounds = true
- });
- }
-
- base.OnElementChanged(e);
- }
-
- private class BlurredImageView : UIImageView
- {
- public override UIImage Image
- {
- get { return base.Image; }
- set
- {
-
- Task.Run(() =>
- {
- using (var context = CIContext.Create())
- using (var inputImage = CIImage.FromCGImage(value.CGImage))
- using (var filter = new CIGaussianBlur() { Image = inputImage, Radius = 5 })
- using (var resultImage = context.CreateCGImage(filter.OutputImage, inputImage.Extent))
- {
- InvokeOnMainThread(() => base.Image = new UIImage(resultImage));
- }
- });
- }
- }
- }
- }
Go to the PCL project and write this code in MainPage.xaml.
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
- <Grid>
- <AbsoluteLayout>
- <controls:BlurredImage AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"
- InputTransparent="false" x:Name="artwork"
- HorizontalOptions="FillAndExpand" Aspect="Fill" VerticalOptions="FillAndExpand" Source="icon"/>
- </AbsoluteLayout>
- <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
- <Label Text="Blurred Image Demo" TextColor="Black"
- FontAttributes="Bold" FontSize="Medium" HorizontalOptions="CenterAndExpand"/>
- <Image Source="icon" Aspect="Fill" VerticalOptions="CenterAndExpand"
- HorizontalOptions="CenterAndExpand"/>
-
- </StackLayout>
- </Grid>
Now, you will have your BlurredImage working!!