87

我想用颜色参考为图像着色。结果应该看起来像 Photoshop 中的 Multiply 混合模式,其中白色将替换为tint

替代文字

我将不断改变颜色值。

跟进:我会将执行此操作的代码放在 ImageView 的 drawRect: 方法中,对吗?

与往常一样,代码片段将极大地帮助我理解,而不是链接。

更新:使用Ramin建议的代码对 UIImageView 进行子类化。

我把它放在我的视图控制器的 viewDidLoad: 中:

[self.lena setImage:[UIImage imageNamed:kImageName]];
[self.lena setOverlayColor:[UIColor blueColor]];
[super viewDidLoad];

我看到了图像,但它没有被着色。我还尝试加载其他图像,在 IB 中设置图像,并在我的视图控制器中调用 setNeedsDisplay:。

更新:drawRect:没有被调用。

最后更新:我发现一个旧项目的 imageView 设置正确,所以我可以测试 Ramin 的代码,它就像一个魅力!

最终,最终更新:

对于那些刚刚学习 Core Graphics 的人来说,这是最简单的方法。

在您的子类 UIView 中:

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColor(context, CGColorGetComponents([UIColor colorWithRed:0.5 green:0.5 blue:0 alpha:1].CGColor)); // don't make color too saturated

    CGContextFillRect(context, rect); // draw base

    [[UIImage imageNamed:@"someImage.png"] drawInRect: rect blendMode:kCGBlendModeOverlay alpha:1.0]; // draw image
}
4

13 回答 13

77

在 iOS7 中,他们在 UIImageView 上引入了 tintColor 属性,在 UIImage 上引入了 renderingMode。要在 iOS7 上为 UIImage 着色,您所要做的就是:

UIImageView* imageView = …
UIImage* originalImage = …
UIImage* imageForRendering = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
imageView.image = imageForRendering;
imageView.tintColor = [UIColor redColor]; // or any color you want to tint it with
于 2013-10-01T20:18:11.507 回答
45

首先,您需要继承 UIImageView 并覆盖 drawRect 方法。您的类需要一个 UIColor 属性(我们称之为 overlayColor)来保存混合颜色和一个自定义设置器,当颜色更改时强制重绘。像这样的东西:

- (void) setOverlayColor:(UIColor *)newColor {
   if (overlayColor)
     [overlayColor release];

   overlayColor = [newColor retain];
   [self setNeedsDisplay]; // fires off drawRect each time color changes
}

在 drawRect 方法中,您需要先绘制图像,然后用一个填充了您想要的颜色的矩形以及适当的混合模式覆盖它,如下所示:

- (void) drawRect:(CGRect)area
{
  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextSaveGState(context);

  // Draw picture first
  //
  CGContextDrawImage(context, self.frame, self.image.CGImage);

  // Blend mode could be any of CGBlendMode values. Now draw filled rectangle
  // over top of image.
  //
  CGContextSetBlendMode (context, kCGBlendModeMultiply);
  CGContextSetFillColor(context, CGColorGetComponents(self.overlayColor.CGColor));      
  CGContextFillRect (context, self.bounds);
  CGContextRestoreGState(context);
}

通常,为了优化绘图,您会将实际绘图限制为仅传递给 drawRect 的区域,但由于每次颜色更改时都必须重新绘制背景图像,因此整个事物可能需要刷新。

要使用它,请创建对象的实例,然后将image属性(从 UIImageView 继承)设置为图片和overlayColorUIColor 值(可以通过更改您传递的颜色的 alpha 值来调整混合级别)。

于 2009-07-13T06:54:07.453 回答
26

只是一个快速的澄清(在对该主题进行一些研究之后)。Apple doc here明确指出:

该类UIImageView经过优化以将其图像绘制到显示器上。UIImageView不调用drawRect:其子类的方法。如果您的子类需要包含自定义绘图代码,则应UIView改为子类化该类。

所以甚至不要浪费任何时间尝试在UIImageView子类中覆盖该方法。开始UIView吧。

于 2010-05-27T15:51:49.410 回答
26

我想用 alpha 为图像着色,并创建了以下类。如果您发现任何问题,请告诉我。

我已经命名了我的类CSTintedImageView,它继承自UIView因为UIImageView不调用该drawRect:方法,就像之前的回复中提到的那样。我设置了一个指定的初始化程序,类似于在UIImageView类中找到的初始化程序。

用法:

CSTintedImageView * imageView = [[CSTintedImageView alloc] initWithImage:[UIImage imageNamed:@"image"]];
imageView.tintColor = [UIColor redColor];

CSTintedImageView.h

@interface CSTintedImageView : UIView

@property (strong, nonatomic) UIImage * image;
@property (strong, nonatomic) UIColor * tintColor;

- (id)initWithImage:(UIImage *)image;

@end

CSTintedImageView.m

#import "CSTintedImageView.h"

@implementation CSTintedImageView

@synthesize image=_image;
@synthesize tintColor=_tintColor;

- (id)initWithImage:(UIImage *)image
{
    self = [super initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];

    if(self)
    {
        self.image = image;

        //set the view to opaque
        self.opaque = NO;
    }

    return self;
}

- (void)setTintColor:(UIColor *)color
{
    _tintColor = color;

    //update every time the tint color is set
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();    

    //resolve CG/iOS coordinate mismatch
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -rect.size.height);

    //set the clipping area to the image
    CGContextClipToMask(context, rect, _image.CGImage);

    //set the fill color
    CGContextSetFillColor(context, CGColorGetComponents(_tintColor.CGColor));
    CGContextFillRect(context, rect);    

    //blend mode overlay
    CGContextSetBlendMode(context, kCGBlendModeOverlay);

    //draw the image
    CGContextDrawImage(context, rect, _image.CGImage);    
}

@end
于 2011-12-02T04:30:12.080 回答
5

这可能非常有用:PhotoshopFramework 是一个在 Objective-C 上处理图像的强大库。这是为了带来 Adob​​e Photoshop 用户熟悉的相同功能。示例:使用 RGB 0-255 设置颜色、应用混合过滤器、转换...

是开源的,这里是项目链接:https ://sourceforge.net/projects/photoshopframew/

于 2009-10-22T20:44:16.320 回答
4
UIImage * image = mySourceImage;
UIColor * color = [UIColor yellowColor];  
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:1];
UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, image.size.width, image.size.height)];
[color setFill];
[path fillWithBlendMode:kCGBlendModeMultiply alpha:1]; //look up blending modes for your needs
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//use newImage for something
于 2015-02-07T04:25:44.850 回答
2

这是实现图像着色的另一种方法,特别是如果您已经将 QuartzCore 用于其他用途。这是我对类似问题的回答

导入 QuartzCore:

#import <QuartzCore/QuartzCore.h>

创建透明 CALayer 并将其添加为要着色的图像的子层:

CALayer *sublayer = [CALayer layer];
[sublayer setBackgroundColor:[UIColor whiteColor].CGColor];
[sublayer setOpacity:0.3];
[sublayer setFrame:toBeTintedImage.frame];
[toBeTintedImage.layer addSublayer:sublayer];

将 QuartzCore 添加到您的项目框架列表中(如果它不存在),否则您将收到如下编译器错误:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"
于 2013-09-14T18:48:46.797 回答
2

对于那些尝试子类化 UIImageView 类并陷入“drawRect: is not being called”的人,请注意,您应该改为子类化 UIView 类,因为对于 UIImageView 类,不会调用“drawRect:”方法。在这里阅读更多:在我的 UIImageView 子类中没有调用 drawRect

于 2010-11-25T20:58:43.183 回答
0

我唯一能想到的就是创建一个具有所需颜色的矩形大部分透明视图,然后通过将其添加为子视图将其放置在您的图像视图上。我不确定这是否真的会以您想象的方式为图像着色,但我不确定您将如何侵入图像并有选择地用其他颜色替换某些颜色……对我来说听起来很雄心勃勃。

例如:

UIImageView *yourPicture = (however you grab the image);
UIView *colorBlock = [[UIView alloc] initWithFrame:yourPicture.frame];
//Replace R G B and A with values from 0 - 1 based on your color and transparency
colorBlock.backgroundColor = [UIColor colorWithRed:R green:G blue:B alpha:A];
[yourPicture addSubView:colorBlock];

UIColor 的文档:

colorWithRed:green:blue:alpha:

Creates and returns a color object using the specified opacity and RGB component values.

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha

Parameters

red    - The red component of the color object, specified as a value from 0.0 to 1.0.

green  - The green component of the color object, specified as a value from 0.0 to 1.0.

blue   - The blue component of the color object, specified as a value from 0.0 to 1.0.



alpha  - The opacity value of the color object, specified as a value from 0.0 to 1.0.

Return Value

The color object. The color information represented by this object is in the device RGB colorspace. 
于 2009-07-13T02:26:08.250 回答
0

我有一个为此开源的库:ios-image-filters

于 2011-08-27T07:42:37.690 回答
0

此外,您可能需要考虑缓存合成图像以提高性能并仅在 drawRect: 中渲染它,然后在脏标志确实脏时更新它。虽然您可能会经常更改它,但在某些情况下可能会出现绘图并且您并不脏,因此您可以简单地从缓存中刷新。如果内存比性能更重要,你可以忽略这个:)

于 2009-07-13T16:21:24.427 回答
0

对于 Swift 2.0,

    let image: UIImage! = UIGraphicsGetImageFromCurrentImageContext()

    imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)

    imgView.tintColor = UIColor(red: 51/255.0, green: 51/255.0, blue: 

51/255.0, alpha: 1.0)
于 2016-03-01T11:03:58.633 回答
0

我为此目的制作了宏:

#define removeTint(view) \
if ([((NSNumber *)[view.layer valueForKey:@"__hasTint"]) boolValue]) {\
for (CALayer *layer in [view.layer sublayers]) {\
if ([((NSNumber *)[layer valueForKey:@"__isTintLayer"]) boolValue]) {\
[layer removeFromSuperlayer];\
break;\
}\
}\
}

#define setTint(view, tintColor) \
{\
if ([((NSNumber *)[view.layer valueForKey:@"__hasTint"]) boolValue]) {\
removeTint(view);\
}\
[view.layer setValue:@(YES) forKey:@"__hasTint"];\
CALayer *tintLayer = [CALayer new];\
tintLayer.frame = view.bounds;\
tintLayer.backgroundColor = [tintColor CGColor];\
[tintLayer setValue:@(YES) forKey:@"__isTintLayer"];\
[view.layer addSublayer:tintLayer];\
}

要使用,只需调用:

setTint(yourView, yourUIColor);
//Note: include opacity of tint in your UIColor using the alpha channel (RGBA), e.g. [UIColor colorWithRed:0.5f green:0.0 blue:0.0 alpha:0.25f];

删除色调时,只需调用:

removeTint(yourView);
于 2018-06-21T04:17:10.087 回答