UIImage颜色改变?

19
如何通过编程更改UIImage的颜色?请帮忙一下。如果我发送一个UIImage,它的颜色需要改变,请帮忙一下。如果我通过位图处理更改RGB颜色,它不起作用。

这个类不是一个颜色而是一个图像,你想问什么? - bobber205
1
我想通过编程的方式改变UIImage的颜色...当我这样调用函数时[ self changeImagecolor:myImage color:[UIColor redcolor]]; 函数必须返回我所指定的带有颜色的图像.....我知道我必须使用位图数据...你能帮忙吗? - senthilM
你可以查看这个链接。它运行良好。http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage - NiKKi
你能接受这个答案吗? - Efren
11个回答

36

如果您只需要让它看起来不同,只需使用imageView.tintColor(iOS 7+)。但问题是,默认情况下设置tintColor不起作用:

为什么我的图片不是蓝色的? 我正在设置 tintColor...

要使其起作用,请使用imageWithRenderingMode:

var image = UIImage(named: "stackoverflow")!
image = image.imageWithRenderingMode(.AlwaysTemplate)

let imageView = ...
imageView.tintColor = UIColor(red: 0.35, green: 0.85, blue: 0.91, alpha: 1)
imageView.image = image

现在它将起作用:

现在图像是橙色的!

链接到文档。


性能

在配置UIImageView后设置图像可以避免重复昂贵的操作:

// Good usage
let imageView = ...
imageView.tintColor = yourTintColor
var image = UIImage(named: "stackoverflow")!
image = image.imageWithRenderingMode(.AlwaysTemplate)
imageView.image = image        // Expensive

// Bad usage
var image = UIImage(named: "stackoverflow")!
image = image.imageWithRenderingMode(.AlwaysTemplate)
let imageView = ...
imageView.image = image        // Expensive
imageView.frame = ...          // Expensive
imageView.tintColor = yourTint // Expensive

异步获取和设置图像可以减少滚动和动画延迟(特别是在 UICollectionViewCellUITableViewCell 中对图像进行着色时):

let imageView = cell.yourImageView
imageView.image = nil // Clear out old image
imageView.tintColor = UIColor(red: 0.35, green: 0.85, blue: 0.91, alpha: 1)

// Setting the image asynchronously reduces stuttering 
// while scrolling.  Remember, the image should be set as
// late as possible to avoid repeating expensive operations
// unnecessarily.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
    var image = UIImage(named: "stackoverflow")!
    image = image.imageWithRenderingMode(.AlwaysTemplate)
    imageView.image = image
})

1
实际上,附加的图片是不正确的。它有白色背景,但应该是透明背景。 - Voloda2
@Voloda2 你说得对,你需要一张带有透明度的图片。 - cbh2000
如何在Objective-C中实现呢? - iosMentalist
我在使用 UIBarButtonItem 中的 UIButton 时遇到了问题。应该设置哪个图像?我使用 setImage(for: .normal) 配置了按钮中的图像,但似乎没有任何区别。 - Efren

7

要实现这一点的一种方法是使您的图像脱色,然后在所需颜色的图像上方添加色调。

脱色

-(UIImage *) getImageWithUnsaturatedPixelsOfImage:(UIImage *)image {
    const int RED = 1, GREEN = 2, BLUE = 3;

    CGRect imageRect = CGRectMake(0, 0, image.size.width*2, image.size.height*2);

    int width = imageRect.size.width, height = imageRect.size.height;

    uint32_t * pixels = (uint32_t *) malloc(width*height*sizeof(uint32_t));
    memset(pixels, 0, width * height * sizeof(uint32_t));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [image CGImage]);

    for(int y = 0; y < height; y++) {
        for(int x = 0; x < width; x++) {
            uint8_t * rgbaPixel = (uint8_t *) &pixels[y*width+x];
            uint32_t gray = (0.3*rgbaPixel[RED]+0.59*rgbaPixel[GREEN]+0.11*rgbaPixel[BLUE]);

            rgbaPixel[RED] = gray;
            rgbaPixel[GREEN] = gray;
            rgbaPixel[BLUE] = gray;
        }
    }

    CGImageRef newImage = CGBitmapContextCreateImage(context);

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(pixels);

    UIImage * resultUIImage = [UIImage imageWithCGImage:newImage scale:2 orientation:0];
    CGImageRelease(newImage);

    return resultUIImage;
}

覆盖层着色

-(UIImage *) getImageWithTintedColor:(UIImage *)image withTint:(UIColor *)color withIntensity:(float)alpha {
    CGSize size = image.size;

    UIGraphicsBeginImageContextWithOptions(size, FALSE, 2);
    CGContextRef context = UIGraphicsGetCurrentContext();

    [image drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:1.0];

    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextSetBlendMode(context, kCGBlendModeOverlay);
    CGContextSetAlpha(context, alpha);

    CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(CGPointZero.x, CGPointZero.y, image.size.width, image.size.height));

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

    return tintedImage;
}

操作指南

//For a UIImageView
yourImageView.image = [self getImageWithUnsaturatedPixelsOfImage:yourImageView.image];
yourImageView.image = [atom getImageWithTintedColor:yourImageView.image withTint:[UIColor redColor] withIntensity:0.7];

//For a UIImage
yourImage = [self getImageWithUnsaturatedPixelsOfImage:yourImage];
yourImage = [atom getImageWithTintedColor:yourImageView.image withTint:[UIColor redColor] withIntensity:0.7];

您可以将色调的颜色更改为您想要的任何颜色。


3
这个方法很好用,但我发现在对一个带透明度的PNG文件使用这两种方法时,甚至透明的像素也被染色了。有什么解决办法吗? - Sam Spencer
4
使用源alpha覆盖源颜色到您的颜色,请使用此混合模式(R = S * Da):在getImageWithTintedColor方法中使用CGContextSetBlendMode(context,kCGBlendModeSourceIn)。 - protuberian

2

我发现这个链接对我来说效果最好。我所做的唯一更改是那篇文章评论中建议的更改:使用kCGBlendModeColor而不是kCGBlendModeColorBurn可以使混合模式效果更好。我还用Swift重写了它 - 请参阅本主题中我的其他答案。 - GK100

2
请查看我的帖子(主要是重新编写代码)编辑:该代码基本上创建了一个新的CGContext,使用新颜色在其上绘制图层,并从中返回一个新的UIImage。我已经有一段时间没有深入研究这个代码了,但它似乎只是绘制一个与原始图像形状相同的UIImage,因此具有局限性(会失去图像中的任何细节)。

那段原始代码对于灰色颜色无效,但是注释中的代码是正确的。 - OMGPOP

2

1

你正在操作的 RGB 数据只是一份副本。在完成更改后,您需要将该数据转换回图像。

我首先创建一个新的位图:

CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
ctx = CGBitmapContextCreate( malloc(dataSize), width, height,
                                8, //   CGImageGetBitsPerComponent(cgImage),
                                bytesPerRow, //CGImageGetBytesPerRow(cgImage),
                                space,
                                //kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big );
                                kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
                                //kCGImageAlphaPremultipliedFirst  | kCGBitmapByteOrder32Little);

    CGColorSpaceRelease( space );

// now draw the image into the context
CGRect rect = CGRectMake( 0, 0, CGImageGetWidth(cgImage), CGImageGetHeight(cgImage) );
CGContextDrawImage( ctx, rect, cgImage );

获取像素:

pixels = CGBitmapContextGetData( ctx );

假设您的像素数据来自pixels = CGBitmapContextGetData( ctx );,那么使用该上下文构建一个新图像:
CGImageRef newImg = CGBitmapContextCreateImage(ctx);
[[UIImage imageWithCGImage:newImg] drawInRect:rect];
CGImageRelease(newImg);

你试过了吗?我试了,但没有结果,请问有什么问题吗? - user141302
你做错了什么,如果不知道你在改变位图后做了什么,我无法告诉你是什么。你如何将其转换回图像?在StackOverflow上搜索“[iphone]位图图像”。有大量的问题和答案。 - mahboudz
为确保您正确获取像素数据,请阅读此文档http://developer.apple.com/mac/library/qa/qa2007/qa1509.html。 - mahboudz
我已经按照苹果公司的指示做了,请再看一下我的问题.....?但返回的图像不是黑色的....因为我使用了r-0,g-0,b-0。 - user141302
你需要忽略透明部分。 - OMGPOP

0

用户576924提到的这篇好文章对我非常有帮助: iPhone: How to Dynamically Color a UIImage

而且在Swift中:

extension UIImage {

    func imageWithColor( color : UIColor ) -> UIImage {

       // begin a new image context, to draw our colored image onto
       UIGraphicsBeginImageContext(self.size)

       // get a reference to that context we created
       let context = UIGraphicsGetCurrentContext();

       // set the fill color
       color.setFill()

       // translate/flip the graphics context (for transforming from CG* coords to UI* coords
       CGContextTranslateCTM(context, 0, self.size.height)
       CGContextScaleCTM(context, 1.0, -1.0)

       // set the blend mode to color burn, and the original image
       CGContextSetBlendMode(context, kCGBlendModeColor)
       let rect = CGRect(origin: CGPointZero, size: self.size)
       CGContextDrawImage(context, rect, self.CGImage)

       // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
       CGContextClipToMask(context, rect, self.CGImage)
       CGContextAddRect(context, rect)
       CGContextDrawPath(context,kCGPathFill)

       // generate a new UIImage from the graphics context we drew onto
       let coloredImg = UIGraphicsGetImageFromCurrentImageContext()
       UIGraphicsEndImageContext()

       //return the color-burned image
       return coloredImg
   }

}

注意,我还将"kCGBlendModeColorBurn"更改为"kCGBlendModeColor",正如帖子评论部分所提到的。

我遇到了一个错误,提示“kCGPathFill”未解决的标识符。我需要导入什么?谢谢。 - user89862

0

试一下这个

- (UIImage *)imageWithOverlayColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);

    if (UIGraphicsBeginImageContextWithOptions) {
        CGFloat imageScale = 1.0f;
        if ([self respondsToSelector:@selector(scale)])  // The scale property is new with iOS4.
            imageScale = self.scale;
        UIGraphicsBeginImageContextWithOptions(self.size, NO, imageScale);
    }
    else {
        UIGraphicsBeginImageContext(self.size);
    }

    [self drawInRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(context, kCGBlendModeSourceIn);

    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);

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

    return image;
}

0

我认为你可以创建另一个上下文,并将其上下文颜色设置为你想要着色的RGB。然后将你的UIImage绘制到该上下文中,而不是直接使用你的图片。这是一个概念。这样,你就创建了一个带有彩色图像的离屏缓冲区。我没有在Cocoa中尝试过这个方法,只在Carbon中尝试过,但我认为它应该以相同的方式工作。


我使用UIGraphicsBeginImageContext从那张图片中获取上下文,但它没有起作用? - user141302
请查看此线程: https://dev59.com/JXNA5IYBdhLWcg3wC5RR 首先,在上下文中设置当前颜色为您想要着色图片的RGB,然后绘制图片。完成后,请使用您创建的上下文,而不是原始图片。 - Nava Carmon

0
嗯——字节的顺序不应该是RGBA吗?你设置成了ARGB...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接