Me gustaría teñir una imagen con una referencia de color. Los resultados deberían verse como el modo de fusión Multiplicar en Photoshop, donde los blancos se reemplazarían con tinte :
Cambiaré el valor del color continuamente.
Seguimiento: pondría el código para hacer esto en el método drawRect: de mi ImageView, ¿verdad?
Como siempre, un fragmento de código sería de gran ayuda para mi comprensión, a diferencia de un enlace.
Actualización: Subclasificación de un UIImageView con el código que sugirió Ramin .
Pongo esto en viewDidLoad: de mi controlador de vista:
[self.lena setImage:[UIImage imageNamed:kImageName]];
[self.lena setOverlayColor:[UIColor blueColor]];
[super viewDidLoad];
Veo la imagen, pero no está teñida. También intenté cargar otras imágenes, configurar la imagen en IB y llamar a setNeedsDisplay: en mi controlador de vista.
Actualización : drawRect: no se está llamando.
Actualización final: encontré un proyecto antiguo que tenía un imageView configurado correctamente para poder probar el código de Ramin y ¡funciona como un encanto!
Actualización final, final:
Para aquellos de ustedes que recién están aprendiendo sobre Core Graphics, aquí está lo más simple que podría funcionar.
En su UIView subclasificada:
- (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
}
fuente
Respuestas:
Primero querrá subclasificar UIImageView y anular el método drawRect. Su clase necesita una propiedad UIColor (llamémosla overlayColor) para mantener el color de mezcla y un setter personalizado que fuerza un redibujo cuando cambia el color. Algo como esto:
- (void) setOverlayColor:(UIColor *)newColor { if (overlayColor) [overlayColor release]; overlayColor = [newColor retain]; [self setNeedsDisplay]; // fires off drawRect each time color changes }
En el método drawRect, primero querrá dibujar la imagen y luego superponerla con un rectángulo relleno con el color que desea junto con el modo de fusión adecuado, algo como esto:
- (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); }
Por lo general, para optimizar el dibujo, restringiría el dibujo real solo al área pasada a drawRect, pero como la imagen de fondo debe volver a dibujarse cada vez que cambia el color, es probable que sea necesario actualizar todo.
Para usarlo, cree una instancia del objeto y luego establezca la
image
propiedad (heredada de UIImageView) en la imagen yoverlayColor
en un valor de UIColor (los niveles de mezcla se pueden ajustar cambiando el valor alfa del color que transmite).fuente
En iOS7, han introducido la propiedad tintColor en UIImageView y renderingMode en UIImage. Para teñir un UIImage en iOS7, todo lo que tienes que hacer es:
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
fuente
Quería teñir una imagen con alfa y creé la siguiente clase. Por favor, avíseme si encuentra algún problema con él.
He nombrado mi clase
CSTintedImageView
y la heredaUIView
yaUIImageView
que no llama aldrawRect:
método, como se mencionó en respuestas anteriores. He configurado un inicializador designado similar al que se encuentra en laUIImageView
clase.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
fuente
Solo una aclaración rápida (después de investigar un poco sobre este tema). El documento de Apple aquí establece claramente que:
así que ni siquiera pierda el tiempo intentando anular ese método en una
UIImageView
subclase. Comience con en suUIView
lugar.fuente
Esto podría ser muy útil: PhotoshopFramework es una poderosa biblioteca para manipular imágenes en Objective-C. Esto fue desarrollado para traer las mismas funcionalidades que los usuarios de Adobe Photoshop conocen. Ejemplos: Establecer colores usando RGB 0-255, aplicar filtros de mezcla, transformaciones ...
Es de código abierto, aquí está el enlace del proyecto: https://sourceforge.net/projects/photoshopframew/
fuente
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
fuente
Aquí hay otra forma de implementar el tinte de imagen, especialmente si ya está utilizando QuartzCore para otra cosa. Esta fue mi respuesta a una pregunta similar .
Importar QuartzCore:
#import <QuartzCore/QuartzCore.h>
Cree CALayer transparente y agréguelo como una subcapa para la imagen que desea teñir:
CALayer *sublayer = [CALayer layer]; [sublayer setBackgroundColor:[UIColor whiteColor].CGColor]; [sublayer setOpacity:0.3]; [sublayer setFrame:toBeTintedImage.frame]; [toBeTintedImage.layer addSublayer:sublayer];
Agregue QuartzCore a la lista de Framework de su proyecto (si aún no está allí), de lo contrario, obtendrá errores de compilación como este:
Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"
fuente
Para aquellos de ustedes que intentan subclasificar una clase UIImageView y se quedan atascados en "drawRect: no se está llamando", tenga en cuenta que debe subclasificar una clase UIView en su lugar, porque para las clases UIImageView, el método "drawRect:" no se llama. Lea más aquí: no se llama a drawRect en mi subclase de UIImageView
fuente
Lo único que se me ocurre es crear una vista rectangular mayormente transparente con el color deseado y colocarla sobre la vista de la imagen agregándola como una subvista. Sin embargo, no estoy seguro de si esto realmente teñirá la imagen de la manera que imagina, no estoy seguro de cómo piratear una imagen y reemplazar selectivamente ciertos colores con otros ... me suena bastante ambicioso.
Por ejemplo:
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];
Documentación para 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.
fuente
También es posible que desee considerar almacenar en caché la imagen compuesta para el rendimiento y simplemente renderizarla en drawRect :, luego actualizarla si una bandera sucia está realmente sucia. Si bien es posible que lo cambie con frecuencia, puede haber casos en los que ingresen extracciones y no esté sucio, por lo que simplemente puede actualizar desde la caché. Si la memoria es más un problema que el rendimiento, puede ignorar esto :)
fuente
Tengo una biblioteca que abrí para esto: ios-image-filtros
fuente
Para 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)
fuente
Hice macros para este 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, simplemente llame a:
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];
Al quitar el tinte simplemente llame a:
removeTint(yourView);
fuente