Starting with iOS 13.0+, UIImage class has method withTintColor.
How do equivalent on iOS 12.4, to support older iPhones that can't run iOS 13?
The overall goal is to draw a tinted image, with a black or white glow around it (dark or light theme).
This is done as part of a Xamarin.Forms.Platform.iOS.PlatformEffect.
Xamarin C# iOS code that draws, into a bitmap, the glow overlaid by a tinted image - works on iOS 13:
private static UIImage ApplyGlow2( UIImage src, double radius, Xamarin.Forms.Color color,
Xamarin.Forms.Color? tintColor, int outW, int outH)
{
int glowRadius = (int)radius;
// Increase size of the initial image.
int marginX2 = glowRadius * 2;
int margin = glowRadius;
// Resize original image to display size.
UIGraphics.BeginImageContext(new CGSize(outW, outH));
src.Draw(new CGRect(0, 0, outW, outH));
src = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// Add margins.
UIGraphics.BeginImageContext(new CGSize(outW + marginX2, outH + marginX2));
CGContext context = UIGraphics.GetCurrentContext();
CGRect drawRect = new CGRect(margin, margin, outW, outH);
src.Draw(drawRect);
src = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// Create color overlay.
UIGraphics.BeginImageContext(new CGSize(outW + marginX2, outH + marginX2));
context = UIGraphics.GetCurrentContext();
drawRect = new CGRect(0, 0, outW + marginX2, outH + marginX2);
context.TranslateCTM(0, outH + marginX2);
context.ScaleCTM(1.0f, -1.0f);
context.SetBlendMode(CGBlendMode.Normal);
context.SetFillColor(color.ToCGColor());
context.FillRect(drawRect);
context.SetBlendMode(CGBlendMode.DestinationIn);
context.DrawImage(drawRect, src.CGImage);
UIImage ret = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// Create blurred image;
// create a CIGaussianBlur filter with the input image.
CIGaussianBlur gaussian_blur = new CIGaussianBlur()
{
InputImage = ret.CGImage,
Radius = (float)radius * 0.5f,
};
CIImage output = gaussian_blur.OutputImage;
CIContext context2 = CIContext.FromOptions(null);
CGImage cgimage = context2.CreateCGImage(output, new CGRect(new CGPoint(0,0), ret.Size));
UIImage blurredImage = UIImage.FromImage(cgimage);
// -- Merge blur with original. --
UIGraphics.BeginImageContext(new CGSize(outW + marginX2, outH + marginX2));
//CGContext context3 = UIGraphics.GetCurrentContext();
// Blur.
CGRect drawRect2 = new CGRect(0, 0, outW + marginX2, outH + marginX2);
CGRect drawRect3 = new CGRect(1, 1, outW + marginX2, outH + marginX2);
CGRect drawRect4 = new CGRect(2, 2, outW + marginX2, outH + marginX2);
blurredImage.Draw(drawRect2);
blurredImage.Draw(drawRect3);
blurredImage.Draw(drawRect4);
if (tintColor != null) {
// Draw tinted original (over blur).
var tintedImage = src.ApplyTintColor( tintColor.Value.ToUIColor() );
tintedImage.Draw( drawRect2 );
} else {
// Draw original (over blur).
src.Draw( drawRect2 );
}
ret = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return ret;
}
The lines from above that are most relevant to my question:
// Draw tinted original (over blur).
var tintedImage = src.ApplyTintColor( tintColor.Value.ToUIColor() );
tintedImage.Draw( drawRect2 );
What I've tried:
iOS 12 does have a TintColor that can be applied while rendering into a UIImageView, but I don't see a way to use that when drawing programmatically into a UIImage:
// Apply tint color. UIImageView Control.
Control.Image = Control.Image.ImageWithRenderingMode(UIKit.UIImageRenderingMode.AlwaysTemplate);
Control.TintColor = ((TintedImage)Element).TintColor.ToUIColor();
The above code is similar to Using Tint color on UIImageView, which is the closest SO post I see.
There are several other similar posts, but AFAIK they all use uiimageview.tintColor, and don't add any additional info relevant to drawing into a Bitmap (not a view).
How to apply a tintColor to a UIImage?
If there is some way to create a UIView
that isn't part of view hierarchy, set its TintColor, then render that into a bitmap, that might be a way to solve this. But I'm not seeing how to do that. One step of this approach would be similar to these posts:
- How to convert a UIView to an image.
- How to capture UIView to UIImage without loss of quality on retina display.
I'm programming via Xamarin.iOS, but a solution in any iOS language will be accepted.