34

I am working on an Iphone application.

I have png pictures that represents symbols. symbols are all black with a transparent background.

Is there a way I can turn the black color into another one? What I'm looking for is something that can help me choose the color I want and when using the symbols (in a UIImage) I can make them appear the color of my choice.

I have searched around and found a framework called OpenCV that can manipulate images but I cant find out how to recolor the picture.

Any help and suggestion is greatly appreciated.

Thank you

tiguero
  • 11,477
  • 5
  • 43
  • 61
Y2theZ
  • 10,162
  • 38
  • 131
  • 200

8 Answers8

106

The easiest and shortest:

Way to do that in case when you dealing with UIImageView:

Obj-C:

theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];

Swift:

let theImageView = UIImageView(image: UIImage(named:"foo")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate))
theImageView.tintColor = UIColor.redColor()
skywinder
  • 21,291
  • 15
  • 93
  • 123
  • The question requires you to perform the background color change on UIImage object instead of UIImageView. In some cases you want to be able to do that instead of setting the tint color on the view container. – Rushabh Jan 10 '17 at 19:44
35

hi you want to change remove/ one specific color means use the below category....

.h file:

#import <UIKit/UIKit.h>

@interface UIImage (Color)

+ (UIImage*)setBackgroundImageByColor:(UIColor *)backgroundColor withFrame:(CGRect )rect;


+ (UIImage*) replaceColor:(UIColor*)color inImage:(UIImage*)image withTolerance:(float)tolerance;

+(UIImage *)changeWhiteColorTransparent: (UIImage *)image;

+(UIImage *)changeColorTo:(NSMutableArray*) array Transparent: (UIImage *)image;

//resizing Stuff...
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize;

@end

.m file

#import <QuartzCore/QuartzCore.h>
#import "UIImage+Color.h"

@implementation UIImage (Color)




+ (UIImage* )setBackgroundImageByColor:(UIColor *)backgroundColor withFrame:(CGRect )rect{

    // tcv - temporary colored view
    UIView *tcv = [[UIView alloc] initWithFrame:rect];
    [tcv setBackgroundColor:backgroundColor];


    // set up a graphics context of button's size
    CGSize gcSize = tcv.frame.size;
    UIGraphicsBeginImageContext(gcSize);
    // add tcv's layer to context
    [tcv.layer renderInContext:UIGraphicsGetCurrentContext()];
    // create background image now
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     return image;
//    [tcv release];

}





+ (UIImage*) replaceColor:(UIColor*)color inImage:(UIImage*)image withTolerance:(float)tolerance {
    CGImageRef imageRef = [image CGImage];

    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    NSUInteger bitmapByteCount = bytesPerRow * height;

    unsigned char *rawData = (unsigned char*) calloc(bitmapByteCount, sizeof(unsigned char));

    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

    CGColorRef cgColor = [color CGColor];
    const CGFloat *components = CGColorGetComponents(cgColor);
    float r = components[0];
    float g = components[1];
    float b = components[2];
    //float a = components[3]; // not needed

    r = r * 255.0;
    g = g * 255.0;
    b = b * 255.0;

    const float redRange[2] = {
        MAX(r - (tolerance / 2.0), 0.0),
        MIN(r + (tolerance / 2.0), 255.0)
    };

    const float greenRange[2] = {
        MAX(g - (tolerance / 2.0), 0.0),
        MIN(g + (tolerance / 2.0), 255.0)
    };

    const float blueRange[2] = {
        MAX(b - (tolerance / 2.0), 0.0),
        MIN(b + (tolerance / 2.0), 255.0)
    };

    int byteIndex = 0;

    while (byteIndex < bitmapByteCount) {
        unsigned char red   = rawData[byteIndex];
        unsigned char green = rawData[byteIndex + 1];
        unsigned char blue  = rawData[byteIndex + 2];

        if (((red >= redRange[0]) && (red <= redRange[1])) &&
            ((green >= greenRange[0]) && (green <= greenRange[1])) &&
            ((blue >= blueRange[0]) && (blue <= blueRange[1]))) {
            // make the pixel transparent
            //
            rawData[byteIndex] = 0;
            rawData[byteIndex + 1] = 0;
            rawData[byteIndex + 2] = 0;
            rawData[byteIndex + 3] = 0;
        }

        byteIndex += 4;
    }

    UIImage *result = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];

    CGContextRelease(context);
    free(rawData);

    return result;
}

+(UIImage *)changeWhiteColorTransparent: (UIImage *)image
{
    CGImageRef rawImageRef=image.CGImage;

    const float colorMasking[6] = {222, 255, 222, 255, 222, 255};

    UIGraphicsBeginImageContext(image.size);
    CGImageRef maskedImageRef=CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
    {
        //if in iphone
        CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0.0, image.size.height);
        CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0); 
    }

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, image.size.width, image.size.height), maskedImageRef);
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    CGImageRelease(maskedImageRef);
    UIGraphicsEndImageContext();    
    return result;
}




+(UIImage *)changeColorTo:(NSMutableArray*) array Transparent: (UIImage *)image
{
    CGImageRef rawImageRef=image.CGImage;

//    const float colorMasking[6] = {222, 255, 222, 255, 222, 255};

     const float colorMasking[6] = {[[array objectAtIndex:0] floatValue], [[array objectAtIndex:1] floatValue], [[array objectAtIndex:2] floatValue], [[array objectAtIndex:3] floatValue], [[array objectAtIndex:4] floatValue], [[array objectAtIndex:5] floatValue]};


    UIGraphicsBeginImageContext(image.size);
    CGImageRef maskedImageRef=CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
    {
        //if in iphone
        CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0.0, image.size.height);
        CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0); 
    }

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, image.size.width, image.size.height), maskedImageRef);
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    CGImageRelease(maskedImageRef);
    UIGraphicsEndImageContext();    
    return result;
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    //UIGraphicsBeginImageContext(newSize);
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}



@end

i changed the removed white color to transparent by this code....

the call will be...

 self.rawImage.image=[UIImage changeWhiteColorTransparent:originalStateImage];

i hope this idea will help you....

Arun
  • 3,406
  • 4
  • 30
  • 55
  • 2
    Could you give an example usage of the `changeColorTo` method. i.e. what should the array parameter contain? – Tyson Mar 04 '13 at 00:01
  • I need to replace all white pixels with a different color at runtime, keeping the alpha values the same. e.g. RGBA of 255,255,255,255 -> 128,128,128,255. But RGBA of 255,255,255,128 -> 128,128,128,128. Is your `changeColorTo` method what I am after? – Tyson Mar 04 '13 at 00:03
  • You should use `UIGraphicsBeginImageContextWithOptions()` if you want images to look crisp on Retina devices. – Devfly May 23 '13 at 10:29
  • 4
    Give credit to the author. Here's the repo where that code probably came from: https://github.com/AckeeCZ/ACKategories/blob/master/UIImage%2BColor.h – jlmendezbonini Mar 31 '14 at 20:17
  • 5
    Somehow the link got messed up. https://github.com/AckeeCZ/ACKategories/tree/master/ACKategories/UIKit The categories in question are in UIImage+Color.h – jlmendezbonini Apr 01 '14 at 15:02
  • @Spynet im using same code in my application but when im replacing color border still exists im unable to remove that border can you please have a look on it? – Balu May 03 '17 at 15:42
10

hi use this category file to change the image entire color....

.h file:

#import <UIKit/UIKit.h>

@interface UIImage (AddtionalFunctionalities)

//TintColor...
- (UIImage *)imageWithTint:(UIColor *)tintColor;
//scale and resize...
-(UIImage*)scaleToSize:(CGSize)size;

@end

.m file:

#import "UIImage+AddtionalFunctionalities.h"

@implementation UIImage (AddtionalFunctionalities)


- (UIImage *)imageWithTint:(UIColor *)tintColor 
{
    // Begin drawing
    CGRect aRect = CGRectMake(0.f, 0.f, self.size.width, self.size.height);
    CGImageRef alphaMask;

    //
    // Compute mask flipping image
    //
    {
        UIGraphicsBeginImageContext(aRect.size);        
        CGContextRef c = UIGraphicsGetCurrentContext(); 

        // draw image
        CGContextTranslateCTM(c, 0, aRect.size.height);
        CGContextScaleCTM(c, 1.0, -1.0);
        [self drawInRect: aRect];

        alphaMask = CGBitmapContextCreateImage(c);

        UIGraphicsEndImageContext();
    }

    //
    UIGraphicsBeginImageContext(aRect.size);

    // Get the graphic context
    CGContextRef c = UIGraphicsGetCurrentContext(); 

    // Draw the image
    [self drawInRect:aRect];

    // Mask
    CGContextClipToMask(c, aRect, alphaMask);

    // Set the fill color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextSetFillColorSpace(c, colorSpace);

    // Set the fill color
    CGContextSetFillColorWithColor(c, tintColor.CGColor);

    UIRectFillUsingBlendMode(aRect, kCGBlendModeNormal);

    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();    

    // Release memory
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(alphaMask);

    return img;
}


-(UIImage*)scaleToSize:(CGSize)size
{
    // Create a bitmap graphics context
    // This will also set it as the current context
    UIGraphicsBeginImageContext(size);

    // Draw the scaled image in the current context
    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];

    // Create a new image from current context
    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    // Pop the current context from the stack
    UIGraphicsEndImageContext();

    // Return our new scaled image
    return scaledImage;
}

@end

the method call will be :

 self.outputImage.image=[sourceImage imageWithTint:[UIColor redColor]];

if u want to use the image means use this:

self.outputImage.image=[sourceImage imageWithTint:[UIColor colorWithPatternImage:[UIImage imageNamed: @"red.jpg"]]];

i hope this will help you...

Arun
  • 3,406
  • 4
  • 30
  • 55
6

Set the Image rendering mode then for color purpose use tintcolor property.

yourImageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[yourImageView setTintColor:[UIColor redColor]];
Ash
  • 5,525
  • 1
  • 40
  • 34
0

For playing with images using objective-c, mainly you have to use Quartz 2D/CoreGraphics framework. I suppose it will be the easiest way for you to accomplish your task.

The link to Quartz 2D guideline is here , the guideline is pretty comprehensive. Just have a look somewhere in filling the bitmap with color.

Also I've some records about the heavy image processing in my blog, you can have a look, it might be helpfull. http://levonp.blogspot.de/2012/05/quartz-getting-diff-images-of-two.html

Of course you can do it also using more advanced stuffs like OpenGL, OpenCV, etc.

deimus
  • 9,565
  • 12
  • 63
  • 107
0

You can create UIView which store UIImageView and change UIview background Color.

UIView *viewForImage = ....;
UIImageView *imageView = .....;
...

[viewForImage addSubview: imageView];
[self.view addSubview:viewForImage];
...

and then use for example

[viewForImage setBackgroundColor: [UIColor redColor]];
Tomasz Szulc
  • 4,217
  • 4
  • 43
  • 79
0

A very simple solution to change the color of the image. Idea: extensions for UIImage and UIImageView.

Swift 3, Xcode 8.1. https://stackoverflow.com/a/40884483/4488252

Code sample from my answer (link above):

// use extension UIImage
newImageView = createNewImageView(x: 100)
newImageView.image =  UIImage(named: "Apple")?.imageWithColor(newColor: UIColor.blue)

// use extension UIImageView
newImageView = createNewImageView(x: 160)
newImageView.image =  UIImage(named: "Apple")
newImageView.imageColor = UIColor.green
Community
  • 1
  • 1
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
0

For iOS 13.0

Obj-C:

self.yourImageView.image = [self.yourImageView.image imageWithTintColor:[UIColor.redColor]];

Swift:

yourImageView.image = yourImageView.image.withTintColor(UIColor.red);

If the image comes from the Asset Catalog, you can change the rendering in the Attribute Inspector

Attribute Inspector screenshot

Mendy
  • 176
  • 2
  • 8