Question
I have a CGImageRef image. It is actually a image which is going to be used as a mask. So, the "alpha layer" of it is what I really care about. I want to "thicken" the opaque part of the image, as if I would add a stroke around the opaque part. How to do that?
More context
I have an image (a CGImageRef) like that:
It has been created by
mask = CGBitmapContextCreateImage(context);
I'm using it as a mask. The UIView under the mask is the same text. The problem is that the text underneath is not completed covered by the mask. See:
More code
This code is in a UILabel subclass.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw text normally
[super drawTextInRect:rect];
if (self.alternativeTextColor) {
CGImageRef mask = NULL;
// Create a mask from the text
mask = CGBitmapContextCreateImage(context);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, self.frame.size.height);
CGContextScaleCTM(context, 1.0, (CGFloat) -1.0);
// Clip the current context to our mask
CGContextClipToMask(context, rect, mask);
// Set fill color
CGContextSetFillColorWithColor(context, [self.alternativeTextColor CGColor]);
// Path from mask
CGPathRef path;
if (CGRectIsEmpty(self.maskFrame)) {
path = CGPathCreateMutable();
} else {
UIBezierPath *roundRectBezierPath = [UIBezierPath bezierPathWithRoundedRect:self.maskFrame
cornerRadius:self.maskCornerRadius];
path = CGPathCreateCopy([roundRectBezierPath CGPath]);
}
CGContextAddPath(context, path);
// Fill the path
CGContextFillPath(context);
CFRelease(path);
// Clean up
CGContextRestoreGState(context);
CGImageRelease(mask);
}
}
Link to the project
https://github.com/colasjojo/Test-NYSegmentedControl
If you are trying to clip to text, I'd suggest not doing it via an intermediate bitmap and instead clipping to the paths of the actual text as in the snippet below from SVGgh's GHText class:
CGContextSaveGState(quartzContext);
CGContextSetTextDrawingMode(quartzContext, kCGTextStrokeClip);
CGContextSetLineWidth(quartzContext, strokeWidthToUse);
... Draw Text here ....
CGContextReplacePathWithStrokedPath(quartzContext);
CGContextClip(quartzContext);
... Do clipped drawing here ...
CGContextSetTextDrawingMode(quartzContext, kCGTextFill);
CGContextRestoreGState(quartzContext);
This isn't answering your question, but it's probably what you should do instead. Play around with CGContextSetTextDrawingMode to get the effect you are going for.
Related
I want to fill image with percentage (e.g. same as rating).
Actually am showing rating image with with float value.
Depend upon float value i need to fill the with particular image.
I got result to fill over all image. But my query is to fill image with percentage value.
My code:
- (void)viewDidLoad
{
[super viewDidLoad];
_ColImgView.image = [self imageNamed:#"star.png" withColor:[UIColor redColor]];
}
- (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color
{
// load the image
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
Preview image:
You have to add overlay. Overlay should be under image and image should be png with transparency. To fill overlay with color in specified area you can use code from here:
iOS - Fill bezierPath with multiple colors based on percentage
If I will find free time I will write code for you, but for now I can only explain what you should do.
I have an origin vehicle image and what I need to implement is fill this with different colors:
http://image.openlan.ru/images/25842748100117640420.png
I've tried to reach it using code below:
- (UIImage *) coloredImageWithColor:(UIColor *)color
{
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeDarken);
CGRect rect = (CGRect){ CGPointZero, self.size };
CGContextDrawImage(context, rect, self.CGImage);
CGContextClipToMask(context, rect, self.CGImage);
[color set];
CGContextFillRect(context, rect);
// wheel
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:(CGRect){ 700, 200, 200, 200 }];
CGContextSetBlendMode(context, kCGBlendModeClear);
[path fill];
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImage;
}
And of course it's not what I expected:
http://image.openlan.ru/images/05312201634158625573.png
Currently I've encountered with two problems. First of all I'd like to figure out how to reveal filled background in some area like wheels, as instance. And the second one is how to create the most similar colored vehicle images.
Your going to want to do most of this in Photoshop. You need a base image that is transparent in the places that you want to show through. Then you want to create a mask image that shows where you want color (using alpha to indicate how much tint to use). Then you'll mask the image and draw it on your background.
I assume a PhotoShop file with a layer mask was used to create the tinted vehicles in your initial example. You'll want those two layers (the base layer and the mask) as separate PNG files. Whoever created the original Photoshop file should be able to provide those.
Trying to do this programmatically from a single, flat image is unlikely to give you the kind of results you'd want.
I have looked at the various ways people are using to tint an image (I want to apply a red layer) and the only one I have go to work is ridiculously elaborate. Is there a simpler way?
// 1. Tint the Image
NSString *name = #"Skyline.png";
UIImage *imgBottomCrop = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(imgBottomCrop.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[[UIColor redColor] setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, imgBottomCrop.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rectBottomCrop = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rectBottomCrop, imgBottomCrop.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rectBottomCrop, imgBottomCrop.CGImage);
CGContextAddRect(context, rectBottomCrop);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Display Image
displayPicture2.image = coloredImg;
If the image is static (doesn't change while the application is running) the easiest way would be to have another image stored and just load it.
If it's not static - You're doing it correctly. Another way i can think of is just having a half-transparent red image stored and displaying it over Your image.
I am having problem understanding the reason for the following method, to return images that are visibly pixelated. I have double checked the size of the image, and it is fine. What's more, without tinting it, the image edges are smooth, and lack pixelation.
The method for tinting image, based on IOS7 ImageView's tintColor property, works fine, however I would love to find out what is wrong with the following code, because it seems to work for everybody but me. Thanks!
- (UIImage *)imageTintedWithColor:(UIColor *)color
{
if (color) {
UIImage *img = self; // The method is a part of UIImage category, hence the "self"
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
return self;
}
Change this line:
UIGraphicsBeginImageContext(img.size);
to:
UIGraphicsBeginImageContextWithOptions(img.size, NO, 0);
If your images will never have an transparency, change the NO to YES.
I'm trying to overlay a color on a UIImage, but only on the left half of the image (I'm using code from http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage to overlay the color). The code I have now is:
- (UIImage *)imageWithColor:(UIColor *)color{
// begin a new image context, to draw our colored image onto
CGSize size = CGSizeMake(self.line.image.size.width/2, self.line.image.size.height);
UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to overlay, and the original image
CGContextSetBlendMode(context, kCGBlendModeOverlay);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
CGContextDrawImage(context, rect, self.line.image.CGImage);
// set a mask that matches the shape of the image, then draw (overlay) a colored rectangle
CGContextClipToMask(context, rect, self.line.image.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
I thought setting the size to be half the width would work, but everything still gets color. I guess I'm missing something very fundamental. Any ideas?
In
CGContextAddRect(context, rect);
you are adding a rectangle with the full size.