how to darken a UIImageView - iphone

I need to darken a UIImageView when it gets touched, almost exactly like icons on the springboard (home screen).
Should I be added UIView with a 0.5 alpha and black background. This seems clumsy. Should I be using Layers or something (CALayers).

I would let a UIImageView handle the actual drawing of the image, but toggle the image to one that's been darkened in advance. Here's some code I've used to generate darkened images with alpha maintained:
+ (UIImage *)darkenImage:(UIImage *)image toLevel:(CGFloat)level
{
// Create a temporary view to act as a darkening layer
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
UIView *tempView = [[UIView alloc] initWithFrame:frame];
tempView.backgroundColor = [UIColor blackColor];
tempView.alpha = level;
// Draw the image into a new graphics context
UIGraphicsBeginImageContext(frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[image drawInRect:frame];
// Flip the context vertically so we can draw the dark layer via a mask that
// aligns with the image's alpha pixels (Quartz uses flipped coordinates)
CGContextTranslateCTM(context, 0, frame.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextClipToMask(context, frame, image.CGImage);
[tempView.layer renderInContext:context];
// Produce a new image from this context
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage *toReturn = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
UIGraphicsEndImageContext();
[tempView release];
return toReturn;
}

How about subclassing UIView and adding a UIImage ivar (called image)? Then you could override -drawRect: something like this, provided you had a boolean ivar called pressed that was set while touched.
- (void)drawRect:(CGRect)rect
{
[image drawAtPoint:(CGPointMake(0.0, 0.0))];
// if pressed, fill rect with dark translucent color
if (pressed)
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextSetRGBFillColor(ctx, 0.5, 0.5, 0.5, 0.5);
CGContextFillRect(ctx, rect);
CGContextRestoreGState(ctx);
}
}
You would want to experiment with RGBA values above. And, of course, non-rectangular shapes would require a bit more work - like a CGMutablePathRef.

UIImageView can have multiple images; you could have two versions of the image and switch to the darker one when needed.

Related

Change Color of UIImage Button

I would like to change the color of an image that I have placed as a button in my navBar. The code I am using to create the image/button is:
UIImage *btnGoImage = [UIImage imageNamed:#"settings_cog.png"];
UIButton *btnGoPre = [UIButton buttonWithType:UIButtonTypeCustom];
btnGoPre.bounds = CGRectMake( 0, 0, 30, 30 );
[btnGoPre setImage:btnGoImage forState:UIControlStateNormal];
[btnGoPre addTarget:self action:#selector(loginAction)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithCustomView:btnGoPre];
If I wanted to change the image to red (it is currently gray). How would I do this? Thanks!
this is the method that will help to change the color of your image you need to pass the image and color as your input variables and it will return the output image
-(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;
}
and here is the example how you can call this method
yourImageView.image = [self imageNamed:#"yourImageName" withColor:[UIColor orangeColor]];
Try a UIBarButtonItem class tintColor property.

iOS Drawing App Issue

I am creating a simple drawing application in which I have a UIView in background & UIImageView in foreground. I am doing some drawing stuff in UIView and I have set an image in UIImageView. I want to add the transparency effect in UIImageView to show the lines behind the image. I know I can do this by reducing alpha, but I don’t want to change the alpha of image.
I want to do it with CGContextSetBlendMode, but I don’t know how to do this. Kindly help me to resolve this issue.
Thanks!
IMAGE http://www.freeimagehosting.net/q3237
UIImage *img = [UIImage imageNamed:#"Image.png"];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
[img drawInRect:CGRectMake(0, 0, 768, 1004) blendMode:kCGBlendModeDarken alpha:1]; [imageView.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height)];
CGContextSetBlendMode(ctx, kCGBlendModeDarken);
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
No need to keep imageview do it like this..
Since you are drawing on two different context you wont be able to use blend modes across them. For that you need to draw other stuff on your drawing view and then draw your image..
- (void)drawRect:(CGRect)rect {
// do ur drawing stuff first
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, self.bounds, self.image.CGImage);
CGContextSetBlendMode(context, kCGBlendModeSaturation);
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, rect);
}

CGContextStrokeRect is drawing only a side of rect

I need to draw a rect filled with color and its border...
the rect is filled with color properly but the outside border is partially drawn, just the right side of the rect is drawn!
The generated UIImage is going to be used in a UITableViewCell's imageView.
- (UIImage *)legendItemWithColor:(UIColor *)color
{
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect outside = CGRectMake(128, 128, 128, 128);
CGRect legend = CGRectInset(outside, 1, 1);
NSLog(#"Outside: %#", NSStringFromCGRect(outside));
NSLog(#"Legend: %#", NSStringFromCGRect(legend));
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, legend);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextStrokeRect(context, outside);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsPopContext();
return img;
}
The problem is when you pass self.view.frame.size to UIGraphicsBeginImageContext() and then use drawn rectangle in array, it is downscaled and the border is obfuscated. Try to pass only the size you need so, i.e. CGSizeMake(2*128+128+2,2*128+128+2). Then it displays ok

How to tint a transparent PNG image in iPhone?

I know it's possible to tint a rectangular image by drawing a CGContextFillRect over it and setting the blend mode. However, I can't figure out how to do a tint on a transparent image such as an icon. It must be possible since the SDK does it itself on tab-bars in such. Would anyone be able to provide a snippet?
UPDATE:
Lots of great suggestions have been given for this problem since I originally asked. Be sure to read through all the answers to figure out what suits you best.
UPDATE (Apr 30, 2015):
With iOS 7.0, I can now just do the following, which would satisfy the needs of my original question. But if you have more complicated cases, check out all the answers.
UIImage *iconImage = [[UIImage imageNamed:#"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
Update: Here is a Gist for a Swift UIColor extension using the code below.
If you have a greyscale image and want white become the tinting color, kCGBlendModeMultiply is the way to go. With this method, you cannot have highlights lighter than your tinting color.
On the contrary, if you have either a non-greyscale image, OR you have highlights and shadows that should be preserved, the blend mode kCGBlendModeColor is the way to go. White will stay white and black will stay black as the lightness of the image is preserved. This mode is just made for tinting - it is the same as Photoshop's Color layer blend mode (disclaimer: slightly differing results may happen).
Note that tinting alpha-pixels does not work correctly neither in iOS nor in Photoshop - half-transparent black pixels would not stay black. I updated the answer below to work around that issue, it took quite a long time to find out.
You can also use one of the blend modes kCGBlendModeSourceIn/DestinationIn instead of CGContextClipToMask.
If you want to create a UIImage, each of the following code sections can be surrounded by the following code:
UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, myIconImage.scale); // for correct resolution on retina, thanks #MobileVet
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, myIconImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect rect = CGRectMake(0, 0, myIconImage.size.width, myIconImage.size.height);
// image drawing code here
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
So here's the code for tinting a transparent image with kCGBlendModeColor:
// draw black background to preserve color of transparent pixels
CGContextSetBlendMode(context, kCGBlendModeNormal);
[[UIColor blackColor] setFill];
CGContextFillRect(context, rect);
// draw original image
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);
// tint image (loosing alpha) - the luminosity of the original image is preserved
CGContextSetBlendMode(context, kCGBlendModeColor);
[tintColor setFill];
CGContextFillRect(context, rect);
// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);
If your image has no half-transparent pixels, you could also do it the other way around with kCGBlendModeLuminosity:
// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);
// replace luminosity of background (ignoring alpha)
CGContextSetBlendMode(context, kCGBlendModeLuminosity);
CGContextDrawImage(context, rect, myIconImage.CGImage);
// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);
If you don't care for luminosity, as you just have got an image with an alpha channel that should be tinted with a color, you can do it in a more efficient way:
// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);
// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);
or the other way around:
// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);
// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
Have fun!
I had most success with this method, because the others I tried caused distorted colors for semi-transparent pixels for certain color-combinations. This should also be a bit better on the performance side.
+ (UIImage *) imageNamed:(NSString *) name withTintColor: (UIColor *) tintColor {
UIImage *baseImage = [UIImage imageNamed:name];
CGRect drawRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);
UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, baseImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// draw original image
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, drawRect, baseImage.CGImage);
// draw color atop
CGContextSetFillColorWithColor(context, tintColor.CGColor);
CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
CGContextFillRect(context, drawRect);
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
After searching around, the best solution I've come to thus far is to use a combination of blend mode and the clipping mask to achieve colorizing/tinting a transparent PNG:
CGContextSetBlendMode (context, kCGBlendModeMultiply);
CGContextDrawImage(context, rect, myIconImage.CGImage);
CGContextClipToMask(context, rect, myIconImage.CGImage);
CGContextSetFillColorWithColor(context, tintColor);
CGContextFillRect(context, rect);
I can get results very close to the tint in the Apple navigation bar by using kCGBlendModeOverlay. Taking excelent #fabb answer and combining #omz approach in this post https://stackoverflow.com/a/4684876/229019 I came with this solution that helds the results I was expecting:
- (UIImage *)tintedImageUsingColor:(UIColor *)tintColor;
{
UIGraphicsBeginImageContextWithOptions (self.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
// draw original image
[self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];
// tint image (loosing alpha).
// kCGBlendModeOverlay is the closest I was able to match the
// actual process used by apple in navigation bar
CGContextSetBlendMode(context, kCGBlendModeOverlay);
[tintColor setFill];
CGContextFillRect(context, rect);
// mask by alpha values of original image
[self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
Here's an example tinting several grayscale images with transparency:
:
The first line is the apple toolbar tinted [UIColor orangeColor].
The second line is the same gradient tinted in several colors starting with clear color (= the actual gradient) and ending with the same orange.
The third is a simple circle with transparency (the linen is the background color)
The forth line is a complex dark noisy texture
You could create an UIImage category and do it like this:
- (instancetype)tintedImageWithColor:(UIColor *)tintColor {
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = (CGRect){ CGPointZero, self.size };
CGContextSetBlendMode(context, kCGBlendModeNormal);
[self drawInRect:rect];
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
In iOS7, they've introduced tintColor property on UIImageView and renderingMode on UIImage. See my example at https://stackoverflow.com/a/19125120/1570970
With iOS 7.0, you can also just do this to tint a basic UIImageView:
UIImage *iconImage = [[UIImage imageNamed:#"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
Note that in the accepted answer by fabb, the "surrounding" code for making a UIImage gave me the wrong resolution of images on retina screen. To fix, change:
UIGraphicsBeginImageContext(myIconImage.size);
to:
UIGraphicsBeginImageContextWithOptions(myIconImage.size, NO, 0.0);
The last parameter which is set to 0.0 is scale, and according to Apple documentation:
"If you specify a value of 0.0, the scale factor is set to the scale
factor of the device’s main screen".
Dont have the permission to comment, and editing seems a bit rude, so I mention this in an answer.
Just in case someone encounters this same problem.
UIImageView (or any view for that matter) has a background color which is RGBA. The alpha in the color may do what you need without inventing something new.
Not my work, but i've successfully used this approach:
http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage
I wanted to shade my image views in my custom UIButton subclass and the other solutions didn't do what I wanted. I needed to darken "tint" the image color. Here's how to change the brightness using CoreImage.
Make sure you add CoreImage.framework to your project's libraries. (Link Binary with Libraries)
UIImage shade method
- (UIImage *)shadeImage:(UIImage *)image {
CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage];
CIContext *context = [CIContext contextWithOptions:nil];
CIFilter *filter = [CIFilter filterWithName:#"CIColorControls"
keysAndValues:kCIInputImageKey, inputImage,
#"inputBrightness", [NSNumber numberWithFloat:-.5], nil];
CIImage *outputImage = [filter outputImage];
CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *newImage = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation];
CGImageRelease(cgImage);
return newImage;
}
You'll want to store a copy of the context as an ivar, rather than recreate it.
No answers will help me on stack overflow: our designers draw UI elements with various forms, various alpha values (and "alpha-holes"). In most cases, this is 32-Bit PNG file with alpha channel, which comprises black & white pixels (of all possible intensities). After tinting such a picture I had to get this tinted result: white pixels - tinted over more, and dark pixels - less. And all this in view of alpha channel. And i wrote this method for my UIImage category. Maybe it not high efficient, but it work as clock:) Here it is:
- (UIImage *)imageTintedWithColor:(UIColor *)color {
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextSetBlendMode(context, kCGBlendModeCopy);
[color setFill];
CGContextFillRect(context, rect);
[self drawInRect:rect blendMode:kCGBlendModeXOR alpha:1.0];
CGContextSetBlendMode(context, kCGBlendModeXOR);
CGContextFillRect(context, rect);
[self drawInRect:rect blendMode:kCGBlendModeMultiply alpha:1.0];
UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImage;
}
First I want to thank fabb for his exceptional solution which has helped me to accomplish my task to tint half transparent Icons. Because I needed a solution for C# (Monotouch) I had to translate his code. Here is what I came up with. Just copy paste this into your code and add your half transparent Image and your done.
So again all credits go to fabb. This is just to kick start C# users :)
//TINT COLOR IMAGE
UIImageView iImage = new UIImageView(new RectangleF(12, 14, 24,24));
iImage.ContentMode = UIViewContentMode.ScaleAspectFit;
iImage.Image = _dataItem.Image[0] as UIImage;
UIGraphics.BeginImageContextWithOptions(iImage.Bounds.Size, false, UIScreen.MainScreen.Scale);
CGContext context = UIGraphics.GetCurrentContext();
context.TranslateCTM(0, iImage.Bounds.Size.Height);
context.ScaleCTM(1.0f, -1.0f);
RectangleF rect = new RectangleF(0,0, iImage.Bounds.Width, iImage.Bounds.Height);
// draw black background to preserve color of transparent pixels
context.SetBlendMode(CGBlendMode.Normal);
UIColor.Black.SetFill();
context.FillRect(rect);
// draw original image
context.SetBlendMode(CGBlendMode.Normal);
context.DrawImage(rect, iImage.Image.CGImage);
// tint image (loosing alpha) - the luminosity of the original image is preserved
context.SetBlendMode(CGBlendMode.Color);
UIColor.Orange.SetFill();
context.FillRect(rect);
// mask by alpha values of original image
context.SetBlendMode(CGBlendMode.DestinationIn);
context.DrawImage(rect, iImage.Image.CGImage);
UIImage coloredImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
iImage = new UIImageView(coloredImage);
iImage.Frame = new RectangleF(12, 14, 24,24);
//END TINT COLOR IMAGE
cell.Add(iImage);

How can i take an UIImage and give it a black border programmatically?

How can i take an UIImage and give it a black border programmatically?
If i can receive code, it will be great.
tnx
If you only need to display the border you can do that with Core Animation on the UIImageView's layer. If you need to do it on the image itself then you will need to create a new image, draw the old image into the new image and then draw a rect on top of it.
- (UIImage*)imageWithBorderFromImage:(UIImage*)source;
{
CGSize size = [source size];
UIGraphicsBeginImageContext(size);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
[source drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.5, 1.0, 1.0);
CGContextStrokeRect(context, rect);
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}
This will put a pink border on an image and return the new image.
I'd have a look at this:
Can I Edit the Pixels of the UIImage's Property CGImage
As for the black border part, I assume you can figure that one out. Just iterate along each side and change the pixels to (0,0,0,255) for a certain amount.