James Montemagno published a post about implementing circle images using Xamarin Forms.
His proposed implementation for Win Phone was good. It clipped the image into a circle, but stopped a little short to draw the circle image border.
Droid

|
WP

|
I played with this to solve this small issue.
Here is a more complete version for WP renderer:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
CircleImage circleImg = Element as CircleImage;
if(circleImg == null || Control == null || Control.Clip != null || circleImg.Source == null)
return;
double controlRadius = Math.Min(Element.Width, Element.Height) / 2.0f;
double controlDiameter = controlRadius * 2.0;
if(controlRadius <= 0)
return;
// **********************************************
// Note: this section ignores PNG transparency.
// **********************************************
try
{
BitmapImage srcBmp = Control.Source as BitmapImage;
WriteableBitmap wrBmpSrc = new WriteableBitmap((int) controlDiameter,
(int) controlDiameter);
ImageBrush imgBrush = new ImageBrush();
// use an image brush with the control’s image
imgBrush.ImageSource = srcBmp;
// set border thickness
int borderThickness = circleImg.BorderThickness;
Color borderColor = XamarinColor2WinColor(circleImg.BorderColor);
// create a path with an ellipse geometry
EllipseGeometry ellipseG = new EllipseGeometry()
{
Center = new System.Windows.Point(controlRadius, controlRadius),
RadiusX = controlRadius,
RadiusY = controlRadius
};
GeometryGroup geomGroup = new GeometryGroup();
geomGroup.Children.Add(ellipseG);
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path()
{
Stroke = new SolidColorBrush(borderColor),
StrokeThickness = borderThickness,
Data = geomGroup,
Width = controlDiameter,
Height = controlDiameter,
Fill = imgBrush,
};
wrBmpSrc.Render(path, null);
wrBmpSrc.Invalidate();
using (MemoryStream memStream = new MemoryStream())
{
wrBmpSrc.SaveJpeg(memStream, wrBmpSrc.PixelWidth, wrBmpSrc.PixelHeight, 0, 100);
srcBmp.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
srcBmp = new BitmapImage();
srcBmp.SetSource(memStream);
}
Control.Source = srcBmp;
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
return;
}
// clip the control into circle
Control.Clip = new EllipseGeometry
{
Center = new System.Windows.Point(controlRadius, controlRadius),
RadiusX = Math.Max(controlRadius, 0),
RadiusY = Math.Max(controlRadius, 0)
};
}
Color conversion helper method
public static Color XamarinColor2WinColor(Xamarin.Forms.Color xamColor)
{
return Color.FromArgb ( (byte)(xamColor.A * 255),
(byte)(xamColor.R * 255),
(byte)(xamColor.G * 255),
(byte)(xamColor.B * 255));
}
Droid

|
WP

|