iphone cocoa-touch image-processing

¿Cómo puedo teñir una imagen programáticamente en el iPhone?



cocoa-touch image-processing (12)

Me gustaría colorear una imagen con una referencia de color. Los resultados deben verse como el modo de fusión Multiplicar en Photoshop, donde los blancos serían reemplazados con tinte :

Voy a 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 en mi comprensión, a diferencia de un enlace.

Actualización: Subclassing UIImageView con el código sugerido por Ramin .

Puse esto en viewDidLoad: of my view controller:

[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 una imageView configurada correctamente para poder probar el código de Ramin y funciona como un encanto!

Final, actualización final:

Para aquellos de ustedes que recién están aprendiendo sobre Core Graphics, aquí es lo más simple que podría funcionar.

En tu UIView subclasificado:

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


Aquí hay otra forma de implementar el tintado de imagen, especialmente si ya está usando QuartzCore para otra cosa. Esta fue mi respuesta para 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 su lista de marcos de proyectos (si no está ya allí), de lo contrario obtendrá errores de compilación como este:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"


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


Esto podría ser muy útil: PhotoshopFramework es una poderosa biblioteca para manipular imágenes en Objective-C. Esto fue desarrollado para brindar las mismas funcionalidades que los usuarios de Adobe Photoshop están familiarizados. Ejemplos: Establezca colores usando RGB 0-255, aplique archivos de mezcla, transformaciones ...

Es de código abierto, aquí está el enlace del proyecto: https://sourceforge.net/projects/photoshopframew/


Lo único que se me ocurre es crear una vista rectangular, en su mayoría transparente, con el color deseado y colocarla sobre la vista de la imagen añadiéndola como subvista. No estoy seguro si esto realmente teñirá la imagen de la forma en que te imaginas, aunque no estoy seguro de cómo harías para piratear una imagen y reemplazar selectivamente ciertos colores con otros ... suena bastante ambicioso para mí.

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.


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)


Para aquellos de ustedes que intentan subclasificar una clase UIImageView y quedar atrapados en "drawRect: no se llama", tenga en cuenta que debe subclasificar una clase UIView en su lugar, porque para las clases UIImageView, no se llama al método "drawRect:". Lea más aquí: drawRect no se llama en mi subclase de UIImageView


Primero querrás 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 obliga a volver a dibujar 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 deberá dibujar la imagen y luego superponerla con un rectángulo relleno con el color que desee 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); }

Normalmente, para optimizar el dibujo, restringirías el dibujo real solo al área que se pasa a drawRect, pero como la imagen de fondo debe volver a dibujarse cada vez que cambia el color, es probable que todo deba actualizarse.

Para usarlo, crea una instancia del objeto y luego establece la propiedad de la image (heredada de UIImageView) en la imagen y overlayColor en un valor UIColor (los niveles de mezcla se pueden ajustar cambiando el valor alfa del color que pasas).


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 hereda de UIView ya que UIImageView no llama al método drawRect: como se menciona en las respuestas anteriores. He configurado un inicializador designado similar al que se encuentra en la clase 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


Solo una aclaración rápida (después de algunas investigaciones sobre este tema). El documento de Apple here establece claramente que:

La clase UIImageView está optimizada para dibujar sus imágenes en la pantalla. UIImageView no llama al método drawRect: de sus subclases. Si su subclase necesita incluir código de dibujo personalizado, debe UIView subclase de la clase UIView lugar.

así que no pierdas el tiempo tratando de anular ese método en una subclase UIImageView . Comience con UIView en UIView lugar.


También es posible que desee considerar el almacenamiento en caché de la imagen compuesta para el rendimiento y simplemente representarla en drawRect :, y luego actualizarla si una bandera sucia está realmente sucia. Aunque es posible que lo cambie a menudo, es posible que haya casos en los que los dibujos estén llegando y que no esté sucio, por lo que puede actualizarlos desde la memoria caché. Si la memoria es más un problema que el rendimiento, puede ignorar esto :)



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