如何在不透明的UIImage上用另一种颜色替换给定的颜色 [英] How to replace a given color with another on an opaque UIImage

查看:149
本文介绍了如何在不透明的UIImage上用另一种颜色替换给定的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想改变不透明UIImage的颜色。我的原始图片如下:

I want to change the color of an opaque UIImage. My original image is as follows:

和我想将图像转换为以下格式

and I want to convert the image to the following format

所以,基本上我想将图像中的红色颜色转换为黑色(任何其他颜色)颜色。添加以上两张图片是为了更好地理解。

So, basically I want to convert red color in the image into black (Any other color) color. Above two images are added for better understanding.

推荐答案

我在'重复'上看不到任何答案(这个问题不应该被标记为重复),它可以让你用另一种颜色替换给定的颜色在不透明的图像上工作,所以我决定添加一个颜色。

I couldn't see any answers on the 'duplicates' (this question shouldn't have been flagged as a duplicate) that will let you replace a given color with another color and work on an opaque image, so I decided to add one that would.

我创建了一个 UIImage 类别来做这个,基本上通过循环遍历每个像素并检测它与给定颜色的接近程度,并将其与替换颜色混合(如果是)。

I created a UIImage category to do this, it basically works by looping through each pixel and detecting how close it is to a given colour, and blends it with your replacement colour if it is.

这将适用于带有<的图像strong>透明度和不透明背景。

@implementation UIImage (UIImageColorReplacement)

-(UIImage*) imageByReplacingColor:(UIColor*)sourceColor withMinTolerance:(CGFloat)minTolerance withMaxTolerance:(CGFloat)maxTolerance withColor:(UIColor*)destinationColor {

    // components of the source color
    const CGFloat* sourceComponents = CGColorGetComponents(sourceColor.CGColor);
    UInt8* source255Components = malloc(sizeof(UInt8)*4);
    for (int i = 0; i < 4; i++) source255Components[i] = (UInt8)round(sourceComponents[i]*255.0);

    // components of the destination color
    const CGFloat* destinationComponents = CGColorGetComponents(destinationColor.CGColor);
    UInt8* destination255Components = malloc(sizeof(UInt8)*4);
    for (int i = 0; i < 4; i++) destination255Components[i] = (UInt8)round(destinationComponents[i]*255.0);

    // raw image reference
    CGImageRef rawImage = self.CGImage;

    // image attributes
    size_t width = CGImageGetWidth(rawImage);
    size_t height = CGImageGetHeight(rawImage);
    CGRect rect = {CGPointZero, {width, height}};

    // bitmap format
    size_t bitsPerComponent = 8;
    size_t bytesPerRow = width*4;
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;

    // data pointer
    UInt8* data = calloc(bytesPerRow, height);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create bitmap context
    CGContextRef ctx = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
    CGContextDrawImage(ctx, rect, rawImage);

    // loop through each pixel's components
    for (int byte = 0; byte < bytesPerRow*height; byte += 4) {

        UInt8 r = data[byte];
        UInt8 g = data[byte+1];
        UInt8 b = data[byte+2];

        // delta components
        UInt8 dr = abs(r-source255Components[0]);
        UInt8 dg = abs(g-source255Components[1]);
        UInt8 db = abs(b-source255Components[2]);

        // ratio of 'how far away' each component is from the source color
        CGFloat ratio = (dr+dg+db)/(255.0*3.0);
        if (ratio > maxTolerance) ratio = 1; // if ratio is too far away, set it to max.
        if (ratio < minTolerance) ratio = 0; // if ratio isn't far enough away, set it to min.

        // blend color components
        data[byte] = (UInt8)round(ratio*r)+(UInt8)round((1.0-ratio)*destination255Components[0]);
        data[byte+1] = (UInt8)round(ratio*g)+(UInt8)round((1.0-ratio)*destination255Components[1]);
        data[byte+2] = (UInt8)round(ratio*b)+(UInt8)round((1.0-ratio)*destination255Components[2]);

    }

    // get image from context
    CGImageRef img = CGBitmapContextCreateImage(ctx);

    // clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    free(data);
    free(source255Components);
    free(destination255Components);

    UIImage* returnImage = [UIImage imageWithCGImage:img];
    CGImageRelease(img);

    return returnImage;
}

@end

用法:

UIImage* colaImage = [UIImage imageNamed:@"cola1.png"];
UIImage* blackColaImage = [colaImage imageByReplacingColor:[UIColor colorWithRed:1 green:0 blue:0 alpha:1] withMinTolerance:0.5 withMaxTolerance:0.6 withColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1]];

minTolerance 是像素的点将开始与替换颜色混合(而不是被替换)。 maxTolerance 是像素停止混合的点。

The minTolerance is the point at which pixels will start to blend with the replacement colour (rather than being replaced). The maxTolerance is the point at which the pixels will stop being blended.

之前:

之后:

结果有点别名,但是请记住,您的原始图像相当小。使用更高分辨率的图像,这将更好地工作。您还可以使用公差来获得更好的结果!

The result is a little aliased, but bear in mind that your original image was fairly small. This will work much better with a higher resolution image. You can also play about with the tolerances to get even better results!

这篇关于如何在不透明的UIImage上用另一种颜色替换给定的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆