Como eu poderia colorir uma imagem programaticamente no iPhone?

Eu gostaria de colorir uma imagem com uma referência de cor. Os resultados devem se parecer com o modo de mesclagem Multiply no Photoshop, onde os brancos seriam substituídos por tonalidade :

texto alternativo

Eu estarei mudando o valor da cor continuamente.

Follow up: Eu colocaria o código para fazer isso no método drawRect: my do ImageView, certo?

Como sempre, um trecho de código ajudaria muito no meu entendimento, ao contrário de um link.

Atualização: Subclassificando um UIImageView com o código sugerido por Ramin .

Eu coloquei isso no viewDidLoad: do meu view controller:

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

Eu vejo a imagem, mas ela não está sendo pintada. Também tentei carregar outras imagens, configurar a imagem em IB e chamar setNeedsDisplay: no meu controlador de visualização.

Atualização : drawRect: não está sendo chamado.

Atualização final: Eu encontrei um projeto antigo que tinha um imageView configurado corretamente para que eu pudesse testar o código de Ramin e funcionar como um encanto!

Atualização final final:

Para aqueles que estão aprendendo sobre o Core Graphics, aqui está a coisa mais simples que poderia funcionar.

Em seu UIView subclass:

 - (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 } 

Primeiro você vai querer subclassificar o UIImageView e sobrescrever o método drawRect. Sua class precisa de uma propriedade UIColor (vamos chamá-la de overlayColor) para manter a cor da mesclagem e um setter personalizado que força um redesenho quando a cor muda. Algo assim:

 - (void) setOverlayColor:(UIColor *)newColor { if (overlayColor) [overlayColor release]; overlayColor = [newColor retain]; [self setNeedsDisplay]; // fires off drawRect each time color changes } 

No método drawRect, você vai querer desenhar a imagem primeiro e depois sobrepô-la com um retângulo preenchido com a cor que você quer, junto com o modo de mesclagem apropriado, algo assim:

 - (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); } 

Normalmente, para otimizar o desenho, você restringiria o desenho real somente à área passada para drawRect, mas como a imagem de fundo precisa ser redesenhada cada vez que a cor muda, é provável que a coisa toda precise ser atualizada.

Para usá-lo, crie uma instância do object e, em seguida, defina a propriedade image (herdada de UIImageView) para a imagem e overlayColor como um valor UIColor (os níveis de mesclagem podem ser ajustados alterando o valor alfa da cor passada).

No iOS7, eles introduziram a propriedade tintColor no UIImageView e renderMode no UIImage. Para colorir um UIImage no iOS7, tudo o que você precisa fazer é:

 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 

Apenas um esclarecimento rápido (depois de alguma pesquisa sobre este tema). O documento da Apple aqui afirma claramente que:

A class UIImageView é otimizada para desenhar suas imagens no display. UIImageView não chama o método drawRect: de suas subclasss. Se sua subclass precisar include um código de desenho personalizado, você deve criar uma subclass da class UIView .

então nem perca tempo tentando replace esse método em uma subclass UIImageView . Comece com o UIView .

Eu queria colorir uma imagem com alpha e criei a seguinte class. Por favor, deixe-me saber se você encontrar algum problema com isso.

Eu nomeei minha class CSTintedImageView e ela é herdada do UIView pois o UIImageView não chama o método CSTintedImageView como mencionado nas respostas anteriores. Eu configurei um inicializador designado semelhante ao encontrado na class UIImageView .

Uso:

 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 

Isso pode ser muito útil: o PhotoshopFramework é uma biblioteca poderosa para manipular imagens no Objective-C. Isso foi desenvolvido para trazer as mesmas funcionalidades que os usuários do Adobe Photoshop estão familiarizados. Exemplos: definir colors usando RGB 0-255, aplicar filtros de mesclagem, transformações …

É open source, aqui está o link do projeto: 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 

Aqui está outra maneira de implementar a matização da imagem, especialmente se você já estiver usando o QuartzCore para outra coisa. Esta foi a minha resposta para uma pergunta semelhante .

Importação QuartzCore:

 #import  

Crie um CALayer transparente e adicione-o como uma subcamada para a imagem que você deseja colorir:

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

Adicione QuartzCore à sua lista de Frameworks de projetos (se ainda não estiver lá), caso contrário, você obterá erros do compilador como este:

 Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer" 

Para aqueles que tentam subclassificar uma class UIImageView e ficarem presos em “drawRect: não está sendo chamado”, observe que você deve criar uma class UIView, porque para as classs UIImageView, o método “drawRect:” não é chamado. Leia mais aqui: drawRect não sendo chamado na minha subclass de UIImageView

Para o 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) 

A única coisa em que consigo pensar seria criar uma vista retangular quase transparente com a cor desejada e colocá-la sobre a visualização da imagem, adicionando-a como uma subvisualização. Eu não tenho certeza se isso vai realmente tingir a imagem da maneira que você imagina, não sei como você iria hackear uma imagem e replace seletivamente certas colors por outras … parece muito ambicioso para mim.

Por exemplo:

 UIImageView *yourPicture = (however you grab the image); UIView *colorBlock = [[UIView alloc] initWithFrame:yourPicture.frame]; //Replace RGB 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]; 

Documentação para o 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. 

Além disso, você pode considerar o armazenamento em cache da imagem composta para desempenho e apenas renderizá-la no drawRect :, e então atualizá-la se um sinalizador sujo estiver realmente sujo. Embora você possa estar mudando com frequência, pode haver casos em que os desenhos estão chegando e você não está sujo, então você pode simplesmente atualizar a partir do cache. Se a memory é mais um problema do que o desempenho, você pode ignorar isso 🙂

Eu tenho uma biblioteca que eu open-source para isso: ios-image-filters

Eu fiz macros para esse propósito:

 #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];\ } 

Para usar, basta ligar:

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

Ao remover a tonalidade, basta ligar:

 removeTint(yourView);