5

I am working an app which has different theme color, but i don't want to have too much image assets in the project (basically don't want to make the project size too big), is that possible to use one image but different colors?

Thanks!

iPatel
  • 46,010
  • 16
  • 115
  • 137
  • http://stackoverflow.com/questions/1223340/iphone-how-do-you-color-an-image/4630136#4630136 and http://stackoverflow.com/questions/14292212/changing-the-color-of-image-in-iphone-sdk and http://stackoverflow.com/questions/12396236/ios-change-the-colors-of-a-uiimage – iPatel Feb 14 '14 at 05:46
  • @iPatel Thank you for letting me know, i will check all those questions. – user3288387 Feb 14 '14 at 06:32

4 Answers4

6

You can modify the colors of an image in interesting ways programmatically using CIFilter, if that's what you're asking.

Take a stroll through the catalog... https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP40004346

matt
  • 515,959
  • 87
  • 875
  • 1,141
6

I agree with Matt, you should check CIFilter for future image modification. but if you are looking for a quick code sample, here is how i did it. works pretty fine for me, simply need to call like this :

 [self useColor:[UIColor redColor] forImage:WHATEVER_IMAGE];

 - (UIImage *)useColor:(UIColor *)color forImage:(UIImage *)image
 {
     if(!color)
         return image;

     NSUInteger width = CGImageGetWidth([image CGImage]);
     NSUInteger height = CGImageGetHeight([image CGImage]);
     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), [image CGImage]);

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

     int byteIndex = 0;

     while (byteIndex < bitmapByteCount)
     {
         int oldR = rawData[byteIndex];
         int oldG = rawData[byteIndex + 1];
         int oldB = rawData[byteIndex + 2];
         int oldA = rawData[byteIndex + 3];
         if(oldR != 0 || oldG != 0 || oldB != 0 || oldA != 0)
         {
             rawData[byteIndex] = r;
             rawData[byteIndex + 1] = g;
             rawData[byteIndex + 2] = b;
         }

         byteIndex += 4;
     }

     UIImage *result = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context) scale:image.scale orientation:image.imageOrientation];

     CGContextRelease(context);
     free(rawData);

     return result;
 }
Xu Yin
  • 3,932
  • 1
  • 26
  • 46
0

One more simple answer: if your image can be a single color (e.g. a line drawing), then just specify that you want UIImageRenderingModeAlwaysTemplate. Now the image will adopt the tintColor of its container, so you can change its color just by changing the tintColor.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

Based on Xu Yin's answer - a version which better fits SVG-like icons that have a circular pattern in them (and as such might be pixelated by the original version of the code).

The change is just the use (by multiplication) of the current alpha level against each pixel value.

- (UIImage *)useColor:(UIColor *)color forImage:(UIImage *)image {
    if(!color)
        return image;

    NSUInteger width = CGImageGetWidth([image CGImage]);
    NSUInteger height = CGImageGetHeight([image CGImage]);
    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), [image CGImage]);

    CGColorRef cgColor = [color CGColor];
    const CGFloat *components = CGColorGetComponents(cgColor);
    float r = components[0] * 255.0;
    float g = components[1] * 255.0;
    float b = components[2] * 255.0;

    int byteIndex = 0;

    while (byteIndex < bitmapByteCount) {
        int oldR = rawData[byteIndex];
        int oldG = rawData[byteIndex + 1];
        int oldB = rawData[byteIndex + 2];
        int oldA = rawData[byteIndex + 3];
        if(oldR != 0 || oldG != 0 || oldB != 0 || oldA != 0) {
            rawData[byteIndex] = r * (oldA / 255.0);
            rawData[byteIndex + 1] = g * (oldA / 255.0);
            rawData[byteIndex + 2] = b * (oldA / 255.0);
        }

        byteIndex += 4;
    }

    UIImage *result = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context) scale:image.scale orientation:image.imageOrientation];

    CGContextRelease(context);
    free(rawData);

    return result;
}
Community
  • 1
  • 1
sheba
  • 800
  • 6
  • 14