如何在不透明的 UIImage 上用另一种颜色替换给定颜色

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

本文介绍了如何在不透明的 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

所以,基本上我想将图像中的 red 颜色转换为 black(任何其他颜色)颜色.上面两张图是为了更好理解而添加的.

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.

这适用于具有透明和不透明背景的图像.

@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 上用另一种颜色替换给定颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:如何在不透明的 UIImage 上用另一种颜色替换给定颜色

基础教程推荐