如何在 iOS 上以编程方式对图像进行着色?
-
12-09-2019 - |
题
我想用颜色参考对图像进行着色。结果应该类似于 Photoshop 中的乘法混合模式,其中 白人 将被替换为 着色:
我将不断改变颜色值。
跟进: 我会将执行此操作的代码放在 ImageView 的 drawRect 中:方法对吧?
一如既往,一个 代码片段 与链接相反,它将极大地帮助我的理解。
更新: 使用代码子类化 UIImageView 拉明 建议。
我把它放在 viewDidLoad 中:我的视图控制器:
[self.lena setImage:[UIImage imageNamed:kImageName]];
[self.lena setOverlayColor:[UIColor blueColor]];
[super viewDidLoad];
我看到了图像,但它没有被着色。我还尝试加载其他图像,在IB中设置图像,并调用setNeedsDisplay:在我的视图控制器中。
更新: :绘制矩形:没有被调用。
最终更新: 我发现一个旧项目正确设置了 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
}
解决方案
首先,您需要子类化 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)到图片和 overlayColor
为 UIColor 值(可以通过更改传递的颜色的 alpha 值来调整混合级别)。
其他提示
在iOS7,他们已经介绍了关于UIImage的上的UIImageView tintColor属性和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
我想着色用α的图像,并且我创建下面的类。请让如果你发现任何问题,它我知道。
我叫我的课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
只是一个快速的澄清(后有关这个主题的一些研究)。苹果DOC 这里明确规定的是:
在
UIImageView
类被优化以绘制其图像的显示。UIImageView
不调用它的子类的drawRect:
方法。如果你的子类需要包括自定义绘制代码,你应该继承的UIView
类代替。
所以甚至不浪费任何时间试图覆盖一个子类UIImageView
该方法。开始与UIView
代替。
这可能是非常有用的:PhotoshopFramework是一个功能强大的库来操纵上Objective-C的图像。这是发展带来的是Adobe Photoshop的用户所熟悉的相同的功能。实施例:使用RGB 0-255设置颜色,应用混合文件服务器,转化...
是开源的,这里是项目链接: https://sourceforge.net/projects/photoshopframew/
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
下面是实现图像着色,特别是如果你已经使用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"
对于那些你谁试图子类的UIImageView类和陷在“的drawRect:不被称为”,请注意,你应该继承的UIView类来代替,因为对于的UIImageView班,“drawRect中:”方法不调用。在这里阅读更多:的drawRect不叫我的UIImageView <子类/ A>
有关夫特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)
我能想到的唯一事情是将创建具有所需颜色的矩形几乎透明的视图,可以将其作为一个子视图躺在过来图像视图。我不知道这是否会真的在着色你想象的,虽然,我不知道你将如何攻入的图像,并有选择地与他人代替某些颜色......一路图像听起来很宏大的对我。
例如:
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.
此外,你可能要考虑缓存对性能的合成图像,只是渲染它的drawRect :,然后更新它,如果脏标志确实是脏的。虽然你可能会经常变化的话,可能存在被吸引进来的情况下,你是不是脏了,所以你可以简单地从缓存刷新。如果内存大于性能的问题,你可以忽略这一点:)
我有一个库我开源此: IOS-图像滤波器
我提出用于此目的的宏:
#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);