I have a greyscale gem top view.
(PNG format, so has alpha component)
The easiest way to do it is to draw the image into an RGB-colorspaced CGBitmapContext, use CGContextSetBlendMode
to set kCGBlendModeColor
, and then draw over it with a solid color (e.g. with CGContextFillRect
).
The best looking results are going to come from using the gray value to index into a gradient that goes from the darkest to the lightest colors of the desired result. Unfortunately I don't know the specifics of doing that with core graphics.
This is an improvement upon the answer in the question and an implementation of @Anomie
First, put this at the beginning of your UIButton
class, or your view controller. It translates from UIColor
to an RGBA
value, which you will need later.
typedef enum { R, G, B, A } UIColorComponentIndices;
@implementation UIColor (EPPZKit)
- (CGFloat)redRGBAValue {
return CGColorGetComponents(self.CGColor)[R];
}
- (CGFloat)greenRGBAValue {
return CGColorGetComponents(self.CGColor)[G];
}
- (CGFloat)blueRGBAValue {
return CGColorGetComponents(self.CGColor)[B];
}
- (CGFloat)alphaRGBAValue {
return CGColorGetComponents(self.CGColor)[A];
}
@end
Now, make sure that you have your custom image button in IB, with a grayscale image and the right frame. This is considerably better and easier then creating the custom image button programmatically, because:
Assuming you are having the button be in IB (near the bottom will be support for having it programmatically created), add this method to your view controller or button cub class:
- (UIImage*)customImageColoringFromButton:(UIButton*)customImageButton fromColor:(UIColor*)color {
UIImage *customImage = [customImageButton.imageView.image copy];
UIGraphicsBeginImageContext(customImageButton.imageView.frame.size); {
CGContextRef X = UIGraphicsGetCurrentContext();
[customImage drawInRect: customImageButton.imageView.frame];
// Overlay a colored rectangle
CGContextSetBlendMode( X, kCGBlendModeColor) ;
CGContextSetRGBFillColor ( X, color.redRGBAValue, color.greenRGBAValue, color.blueRGBAValue, color.alphaRGBAValue);
CGContextFillRect ( X, customImageButton.imageView.frame);
// Redraw
[customImage drawInRect:customImageButton.imageView.frame blendMode: kCGBlendModeDestinationIn alpha: 1.0];
customImage = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
return customImage;
}
You then will need to call it in a setup method in your view controller or button subclass, and set the imageView of the button to it:
[myButton.imageView setImage:[self customImageColoringFromButton:myButton fromColor:desiredColor]];
If you are not using IB to create the button, use this method:
- (UIImage*)customImageColoringFromImage:(UIImage*)image fromColor:(UIColor*)color fromFrame:(CGRect)frame {
UIImage *customImage = [image copy];
UIGraphicsBeginImageContext(frame.size); {
CGContextRef X = UIGraphicsGetCurrentContext();
[customImage drawInRect: frame];
// Overlay a colored rectangle
CGContextSetBlendMode( X, kCGBlendModeColor) ;
CGContextSetRGBFillColor ( X, color.redRGBAValue, color.greenRGBAValue, color.blueRGBAValue, color.alphaRGBAValue);
CGContextFillRect ( X, frame);
// Redraw
[customImage drawInRect:frame blendMode: kCGBlendModeDestinationIn alpha: 1.0];
customImage = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
return customImage;
}
And call it with:
[self.disclosureButton.imageView setImage:[self customImageColoringFromImage:[UIImage imageNamed:@"GemTop_Dull.png"] fromColor:desiredColor fromFrame:desiredFrame]];