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

Posted

技术标签:

【中文标题】如何在不透明的 UIImage 上用另一种颜色替换给定颜色 [重复]【英文标题】:How to replace a given color with another on an opaque UIImage [duplicate] 【发布时间】:2016-05-30 08:59:36 【问题描述】:

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

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

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

【问题讨论】:

检查这个....***.com/questions/12396236/… 您只是将红色区域转换为黑色,还是将红色区域提取为新的黑色图像?我问是因为第二张图片没有显示第一张图片中的阴影 @Russell:我想简单地将红色区域转换为黑色。 【参考方案1】:

我看不到任何关于“重复”的答案(这个问题不应该被标记为重复),这会让你用另一种颜色替换给定的颜色处理不透明的图像,所以我决定添加一个。


我创建了一个UIImage 类别来执行此操作,它的工作原理是循环遍历每个像素并检测它与给定颜色的接近程度,然后将其与您的替换颜色混合。

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

@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 是像素停止混合的点。

之前:

之后:

结果有点混叠,但请记住,您的原始图像相当小。对于更高分辨率的图像,这将工作得更好。您还可以调整公差以获得更好的结果!

【讨论】:

效果很好!尝试了其他几个解决方案,但这个是正确的。 你能用 Swift 3 重写它吗? 肯定是最好的答案。我翻译成 Swift 3 replaceColor.swift【参考方案2】:

你可以用这个

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

我认为您的图像有问题,这是我的图像,它是白色的。

这是模拟器的变化

【讨论】:

是的,这是我测试过的代码,它正在工作。 问题中的图片背景为白色,这仅适用于透明 PNG。 这是将其显示为黑色,但实际上并未更改图像。【参考方案3】:

注意:首先,您需要使用 Photoshop 或任何其他工具将图像的背景设置为透明。

然后使用下面的代码。

简单的方法, 您需要使用渲染模式来更改此颜色。

cokeImageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; // yourimageviewname 
[cokeImageView setTintColor:[UIColor blackColor]];

【讨论】:

当我应用上面的代码时,我的整个图像视图被转换成黑色 它首先工作你测试它。不要在没有测试代码的情况下给出负面标记。我一直在使用这种方法。 问题中的图片背景为白色,这仅适用于透明 PNG。 你的图片有问题 是的。 MAC中支持PNG格式的实际方式在大多数情况下没有白色背景。图片应该是透明的,而不是白色背景。

以上是关于如何在不透明的 UIImage 上用另一种颜色替换给定颜色 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 qlik 意义上用另一种方式替换大数据(大约百万行)上的 for..loop

ios:更改 UIImage 的颜色

如何删除 UIImage 背景颜色并使其透明?

如何在 eps 文件的每个对象中用一种颜色替换另一种颜色? [关闭]

用另一种颜色替换图像中的特定颜色

使用遮罩更改 UIImage 的颜色并将该图像替换为彩色图像