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.
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 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'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.
I am working on an app - or rather on some re-usable "framework" which I am happy to share once it works. Within this app the user should be able to choose from a list of color themes. Therefore the app must be able to tint its UI elements in some rather dynamic way.
For Buttons all the tinting does not work. Properly tinted background images must be supplied here. But preparing one set of background images for each them is just second best. It is not dynamic and flexible enough.
In the end a solution may come down to providing one monochrome (grey) gradiented image for the selected and normal state and tint that image programmatically using CoreGraphics or OpenGL. But frankly, I do not know where to start there. How should the gradient look like and how would I then programmatically tint that in any given color?
Pretty much applies to UISegmentedControls, just a bit more complicated. :) Any generic solution that covers UISegementedControls too is highliy appreciated.
In iOS7 you can use the method imagedWithRenderingMode: in conjunction with the method setTintColor:
But, be sure to use UIImageRenderingModeAlwaysTemplate as it replaces all non-transparent colors on a UIImage with the tint color. The default is UIImageRenderingModeAutomatic.
UIImageRenderingModeAlwaysTemplate
Always draw the image as a template image, ignoring its color information.
Objective-C:
UIImage * image = [myButton.currentImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[myButton setImage:image forState:UIControlStateNormal];
Swift:
let image = myButton.currentImage?.withRenderingMode(.alwaysTemplate)
myButton.setImage(image, for: .normal)
I made a UIImage category following another post that i cant find that takes the image and tints it as follows:
- (UIImage *)tintedImageWithColor:(UIColor *)tintColor {
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, self.CGImage);
// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImage;
}
This will take the image and fill in all of the areas with an alpha value with the given color.
I created a UIButton category using horsejockey's code:
https://github.com/filipstefansson/UITintedButton
Here's the new methods:
-(void)setImageTintColor:(UIColor *)color;
-(void)setBackgroundTintColor:(UIColor *)color forState:(UIControlState)state;
+(void)tintButtonImages:(NSArray *)buttons withColor:(UIColor *)color;
+(void)tintButtonBackgrounds:(NSArray *)buttons withColor:(UIColor *)color forState:(UIControlState)state;
Here is a partial answer to your question. This is a helper method I wrote that tints a grey scale image:
// baseImage is the grey scale image. color is the desired tint color
+ (UIImage *)tintImage:(UIImage *)baseImage withColor:(UIColor *)color {
UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, baseImage.scale);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, area, baseImage.CGImage);
[color set];
CGContextFillRect(ctx, area);
CGContextRestoreGState(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
CGContextDrawImage(ctx, area, baseImage.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// If the original image was stretchable, make the new image stretchable
if (baseImage.leftCapWidth || baseImage.topCapHeight) {
newImage = [newImage stretchableImageWithLeftCapWidth:baseImage.leftCapWidth topCapHeight:baseImage.topCapHeight];
}
return newImage;
}
I modifie some things from "horsejockey":
+(UIImage *)getTintedImage:(UIImage*)image withColor:(UIColor *)tintColor
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, image.CGImage);
// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImage;
}
I'm refering you to a SO question that seems to be what you are looking for and it's got an answer.
How to tint a transparent PNG image in iPhone?
In one class I have an array consisting of five UIImages such as tiangle.png and circle.png.
In the current class I have a list of colors. After clicking to the UIImage and after clicking to one color it is possible to change the color of the current UIImage.
This will be realized by masking the image, set its color and replace the old UIImage with the new one in the selected color.
But there is something wrong in the method, which should change the color:
- (void) changeColor: (UITapGestureRecognizer*) gestureRecognizer{
UIGraphicsBeginImageContext(test.newView.image.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint loc = [gestureRecognizer locationInView:self.view];
CGContextSetFillColorWithColor(context, [[self colorOfPoint:loc]CGColor]);
CGContextTranslateCTM(context, 0, test.newView.image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect rect = CGRectMake(test.newView.frame.origin.x,test.newView.frame.origin.x, test.newView.image.size.width,test.newView.image.size.height);
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGContextClipToMask(context, rect, test.newView.image.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context, kCGPathFill);
CGImageRef imgRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:imgRef];
CGImageRelease(imgRef);
CGContextRelease(context);
UIGraphicsEndImageContext();
test.newView.image = img;
}
The only thing what is happening is that the clicked UIImage is going to get opaque.
The imageview which is holding the UIImage is in this case not deleted.
I'm not sure that grabbing an imageRef using a CGBitmapContextCreateImage() call is appropriate inside a UIGraphics image context. Every example I've ever seen uses
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
to grab the image before closing the image context. You might try that.