ios 更改 UIImage 颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12872680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:44:05  来源:igfitidea点击:

Changing UIImage color

iphoneobjective-ciosuiimagecgcontext

提问by RomanHouse

I'm trying to change color of UIImage. My code:

我正在尝试更改 UIImage 的颜色。我的代码:

-(UIImage *)coloredImage:(UIImage *)firstImage withColor:(UIColor *)color {
    UIGraphicsBeginImageContext(firstImage.size);

    CGContextRef context = UIGraphicsGetCurrentContext();
    [color setFill];

    CGContextTranslateCTM(context, 0, firstImage.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextSetBlendMode(context, kCGBlendModeCopy);
    CGRect rect = CGRectMake(0, 0, firstImage.size.width, firstImage.size.height);
    CGContextDrawImage(context, rect, firstImage.CGImage);

    CGContextClipToMask(context, rect, firstImage.CGImage);
    CGContextAddRect(context, rect);
    CGContextDrawPath(context,kCGPathElementMoveToPoint);

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

    return coloredImg;
}

This code works, but obtained image is not so well as shoud be: bounds pixels of returned image are intermittent and not so smooth as in my first image. How can I resolve this problem?

这段代码有效,但获得的图像并不像应该的那么好:返回图像的边界像素是断断续续的,不像我的第一张图像那样平滑。我该如何解决这个问题?

回答by Ankish Jain

Since iOS 7, this is the most simple way of doing it.

从 iOS 7 开始,这是最简单的方法。

Objective-C:

目标-C:

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

Swift 2.0:

斯威夫特 2.0:

theImageView.image = theImageView.image?.imageWithRenderingMode(.AlwaysTemplate) 
theImageView.tintColor = UIColor.magentaColor()

Swift 4.0:

斯威夫特 4.0:

theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate) 
theImageView.tintColor = .magenta

Storyboard:

故事板:

First configure the image as template ( on right bar - Render as) in your assets. Then the color of the image would be the tint color applied. enter image description here

首先在您的资产中将图像配置为模板(在右侧栏 - 渲染为)。然后图像的颜色将是应用的色调颜色。 在此处输入图片说明

回答by user1270061

This is pretty much the answer above, but slightly shortened. This only takes the image as a mask and does not actually "multiply" or color the image.

这几乎是上面的答案,但略有缩短。这仅将图像作为蒙版,实际上并不“相乘”或为图像着色。

Objective C:

目标 C:

    UIColor *color = <# UIColor #>;
    UIImage *image = <# UIImage #>;// Image to mask with
    UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [color setFill];
    CGContextTranslateCTM(context, 0, image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextClipToMask(context, CGRectMake(0, 0, image.size.width, image.size.height), [image CGImage]);
    CGContextFillRect(context, CGRectMake(0, 0, image.size.width, image.size.height));

    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

Swift:

迅速:

    let color: UIColor = <# UIColor #>
    let image: UIImage = <# UIImage #> // Image to mask with
    UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
    let context = UIGraphicsGetCurrentContext()
    color.setFill()
    context?.translateBy(x: 0, y: image.size.height)
    context?.scaleBy(x: 1.0, y: -1.0)
    context?.clip(to: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), mask: image.cgImage!)
    context?.fill(CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
    let coloredImg = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

回答by Anna Dickinson

Another way to tint an image is to simply multiply it by a constant color. Sometimes, this is preferable because it doesn't "lift" the color values in black areas; it keeps the relative intensities in the image the same. Using an overlay as a tint tends to flatten out the contrast.

给图像着色的另一种方法是简单地将其乘以恒定颜色。有时,这更可取,因为它不会“提升”黑色区域的颜色值;它使图像中的相对强度保持不变。使用叠加作为色调往往会使对比度变平。

This is the code I use:

这是我使用的代码:

UIImage *MultiplyImageByConstantColor( UIImage *image, UIColor *color ) {

    CGSize backgroundSize = image.size;
    UIGraphicsBeginImageContext(backgroundSize);

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGRect backgroundRect;
    backgroundRect.size = backgroundSize;
    backgroundRect.origin.x = 0;
    backgroundRect.origin.y = 0;

    CGFloat r,g,b,a;
    [color getRed:&r green:&g blue:&b alpha:&a];
    CGContextSetRGBFillColor(ctx, r, g, b, a);
    CGContextFillRect(ctx, backgroundRect);

    CGRect imageRect;
    imageRect.size = image.size;
    imageRect.origin.x = (backgroundSize.width - image.size.width)/2;
    imageRect.origin.y = (backgroundSize.height - image.size.height)/2;

    // Unflip the image
    CGContextTranslateCTM(ctx, 0, backgroundSize.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
    CGContextDrawImage(ctx, imageRect, image.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}

Swift version

迅捷版

extension UIImage{

    static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
        let backgroundSize = image.size
        UIGraphicsBeginImageContext(backgroundSize)

        let ctx = UIGraphicsGetCurrentContext()

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var r:CGFloat
        var g:CGFloat
        var b:CGFloat
        var a:CGFloat
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        CGContextSetRGBFillColor(ctx, r, g, b, a)
        CGContextFillRect(ctx, backgroundRect)

        var imageRect=CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width)/2
        imageRect.origin.y = (backgroundSize.height - image.size.height)/2

        // Unflip the image
        CGContextTranslateCTM(ctx, 0, backgroundSize.height)
        CGContextScaleCTM(ctx, 1.0, -1.0)

        CGContextSetBlendMode(ctx, .Multiply)
        CGContextDrawImage(ctx, imageRect, image.CGImage)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

回答by ColossalChris

In Swift 3.0

在 Swift 3.0 中

imageView.image? = (imageView.image?.withRenderingMode(.alwaysTemplate))!
imageView.tintColor = UIColor.magenta

In Swift 2.0

在 Swift 2.0 中

yourImage.image? = (yourImage.image?.imageWithRenderingMode(.AlwaysTemplate))!
yourImage.tintColor = UIColor.magentaColor()

Enjoy you Swift pioneers

享受你的 Swift 先驱

回答by Charlton Provatas

Swift 4.2 Solution

Swift 4.2 解决方案

extension UIImage {
    func withColor(_ color: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        guard let ctx = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
        color.setFill()
        ctx.translateBy(x: 0, y: size.height)
        ctx.scaleBy(x: 1.0, y: -1.0)
        ctx.clip(to: CGRect(x: 0, y: 0, width: size.width, height: size.height), mask: cgImage)
        ctx.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
        guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
        UIGraphicsEndImageContext()
        return colored
    }
}

// Usage:
// let redImage = UIImage().withColor(.red)

回答by Murlakatam

Starting from iOS 10you can use UIGraphicsImageRenderer:

iOS 10开始,您可以使用UIGraphicsImageRenderer

extension UIImage {

    func colored(_ color: UIColor) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { context in
            color.setFill()
            self.draw(at: .zero)
            context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height), blendMode: .sourceAtop)
        }
    }

}

回答by Mario A Guzman

If you don't have to do it programmatically, you can just do it using Xcode UI.

如果您不必以编程方式执行此操作,则只需使用 Xcode UI 即可。

If you go to the image in your image assets folder, open the inspector on the right hand side and there is a "Render As" dropdown with the following options:

如果您转到图像资产文件夹中的图像,请打开右侧的检查器,然后会出现一个“渲染为”下拉菜单,其中包含以下选项:

  1. Default
  2. Original
  3. Template
  1. 默认
  2. 原来的
  3. 模板

Once you've made the Template selection, you can change the tintColor of the image however you want - whether it is using the Xcode storyboard UI or programmatically.

完成模板选择后,您可以根据需要更改图像的 tintColor - 无论是使用 Xcode 故事板 UI 还是以编程方式。

enter image description here

在此处输入图片说明

See this image:

看这张图片:

enter image description here

在此处输入图片说明

回答by algrid

Here's my adaptation of @Anna's answer. Two key points here:

这是我对@Anna 回答的改编。这里有两个关键点:

  • Use destinationInblending mode
  • Call UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)to get smooth image
  • 使用destinationIn混合模式
  • 调用UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)以获得平滑的图像

Code in in Swift 3:

Swift 3 中的代码:

extension UIImage {

    static func coloredImage(image: UIImage?, color: UIColor) -> UIImage? {

        guard let image = image else {
            return nil
        }

        let backgroundSize = image.size
        UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)

        let ctx = UIGraphicsGetCurrentContext()!

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var r:CGFloat = 0
        var g:CGFloat = 0
        var b:CGFloat = 0
        var a:CGFloat = 0
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
        ctx.fill(backgroundRect)

        var imageRect = CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width) / 2
        imageRect.origin.y = (backgroundSize.height - image.size.height) / 2

        // Unflip the image
        ctx.translateBy(x: 0, y: backgroundSize.height)
        ctx.scaleBy(x: 1.0, y: -1.0)

        ctx.setBlendMode(.destinationIn)
        ctx.draw(image.cgImage!, in: imageRect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

回答by Bill Chan

Base on @Anna's answer and I rewrite for swift 2.2 and handles image with alpha channel:

基于@Anna 的回答,我重写了 swift 2.2 并使用 alpha 通道处理图像:

static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
    let backgroundSize = image.size
    UIGraphicsBeginImageContext(backgroundSize)

    let ctx = UIGraphicsGetCurrentContext()

    var backgroundRect=CGRect()
    backgroundRect.size = backgroundSize
    backgroundRect.origin.x = 0
    backgroundRect.origin.y = 0

    var r:CGFloat = 0
    var g:CGFloat = 0
    var b:CGFloat = 0
    var a:CGFloat = 0
    color.getRed(&r, green: &g, blue: &b, alpha: &a)
    CGContextSetRGBFillColor(ctx, r, g, b, a)

    // Unflip the image
    CGContextTranslateCTM(ctx, 0, backgroundSize.height)
    CGContextScaleCTM(ctx, 1.0, -1.0)
    CGContextClipToMask(ctx, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
    CGContextFillRect(ctx, backgroundRect)

    var imageRect=CGRect()
    imageRect.size = image.size
    imageRect.origin.x = (backgroundSize.width - image.size.width)/2
    imageRect.origin.y = (backgroundSize.height - image.size.height)/2


    CGContextSetBlendMode(ctx, .Multiply)
    CGContextDrawImage(ctx, imageRect, image.CGImage)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

回答by Lowell Bahner

Anna's code works well for copying a UIImage.image over a colored .image background by using kCGBlendModeNormal rather than kCGBlendModeMultiply. For instance, self.mainImage.image = [self NormalImageByConstantColor: self.mainImage.image withColor: yourColor];will place the contents of mainImage.image over the tint yourColor while preserving the opacity of yourColor. This solved my problem of placing a background color with opacity behind an image to be saved to the Camera Roll.

Anna 的代码适用于通过使用 kCGBlendModeNormal 而不是 kCGBlendModeMultiply 在彩色 .image 背景上复制 UIImage.image。例如,self.mainImage.image = [self NormalImageByConstantColor: self.mainImage.image withColor: yourColor];将 mainImage.image 的内容放置在色调 yourColor 上,同时保留 yourColor 的不透明度。这解决了我在要保存到相机胶卷的图像后面放置不透明背景颜色的问题。