2009-05-10 12 views
15

Estoy intentando agregar una superposición negra sobre algunos UIImage's actuales (que son blancos). He estado tratando de utilizar siguiente código:¿Superponer un UIImage con un color?

[[UIColor blackColor] set]; 
[image drawAtPoint:CGPointMake(0, 0) blendMode:kCGBlendModeOverlay alpha:1.0]; 

Pero no está funcionando, y estoy bastante seguro de conjunto no se supone que es allí.

Respuesta

29

Usted tendrá que cortar el contexto de una máscara de imagen y luego rellenar con un color sólido:

- (void)drawRect:(CGRect)rect 
{ 
    CGRect bounds = [self bounds]; 
    [[UIColor blackColor] set]; 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextClipToMask(context, bounds, [myImage CGImage]); 
    CGContextFillRect(context, bounds); 
} 

Nota: myImage debería ser una variable de instancia que contiene un UIImage. No estoy seguro de si se necesita la máscara del canal alfa o la intensidad, así que prueba ambos.

+0

¿Puedes hablar sobre dónde se hace esto realmente? ¿Estoy haciendo una subclase de UIImage? – davis

+0

@DavisG. El código anterior es un ejemplo de un método drawRect: anulado en una subclase UIView. Sería muy sencillo modificarlo para usar un contexto de mapa de bits en su lugar. – rpetrich

+0

@rpetrich ¿No debería ser '[[UIColor blackColor] setFill]' ya que está llenando en lugar de acariciar? –

0

-set se utiliza para establecer el color de las operaciones de dibujo posteriores que no incluye blits. Sugiero como una primera llamada, mostrando otra (vacío) UIView sobre su UIImageView y el establecimiento de su color de fondo:

myView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5]; 

Obviamente se deben utilizar los valores de blanco y alfa que desea.

+2

El problema con esto es mi UIImage no es un bloque rectangular, que es un icono. ¿Este método tampoco dibujaría el color alrededor de la imagen?Básicamente, solo quiero convertir un UIImage blanco en un UIImage negro. – Oliver

3

Además de la solución por rpetrich (que es genial por cierto - me ayude magníficamente), también puede reemplazar la línea CGContextClipToMask con:

CGContextSetBlendMode(context, kCGBlendModeSourceIn); //this is the main bit! 

Es la blendMode SourceIn que hace el trabajo de enmascaramiento el color por lo que sea que esté en GetCurrentContext.

+0

Debe tenerse en cuenta que una de las razones para preferir usar CGContextSetBlendMode es que con CGContextClipToMask puede obtener un contorno fino en su imagen con el color anterior - no estoy seguro si esto es un error en la implementación o un problema con antialiasing, pero usando CGContextSetBlendMode lo arregló por mí. – petrocket

11

Acabo de escribir un tutorial que ayudará con esto. Mi enfoque te da una copia de un UIImage, con las alteraciones de color que deseas. El enfoque de rpetrich es genial, pero requiere que estés creando una subclase. Mi enfoque es solo unas pocas líneas de código que se pueden colocar donde sea que las necesite. http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage

NSString *name = @"badge.png"; 
UIImage *img = [UIImage imageNamed:name]; 

// begin a new image context, to draw our colored image onto 
UIGraphicsBeginImageContext(img.size); 

// get a reference to that context we created 
CGContextRef context = UIGraphicsGetCurrentContext(); 

// set the fill color 
[color setFill]; 

// translate/flip the graphics context (for transforming from CG* coords to UI* coords 
CGContextTranslateCTM(context, 0, img.size.height); 
CGContextScaleCTM(context, 1.0, -1.0); 

// set the blend mode to color burn, and the original image 
CGContextSetBlendMode(context, kCGBlendModeColorBurn); 
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height); 
CGContextDrawImage(context, rect, img.CGImage); 

// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle 
CGContextClipToMask(context, rect, img.CGImage); 
CGContextAddRect(context, rect); 
CGContextDrawPath(context,kCGPathFill); 

// generate a new UIImage from the graphics context we drew onto 
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 

//return the color-burned image 
return coloredImg; 
+2

Si utiliza este método, debe reemplazar la línea CGContextClipToMask con CGContextSetBlendMode (context, kCGBlendModeSourceIn); según la recomendación de @seaniepie a continuación. Para mí, resolvió un problema por el que CGContextClipToMask causaba un contorno tenue alrededor de todas las imágenes en el color original. – petrocket

+0

Creo que este método es mejor que el método de rpetrich –

+0

@Chadwick Wood Probé la solución, pero no tuve suerte. Quiero una imagen tintada como [aquí] (http://stackoverflow.com/questions/29330334/creating-a-tinted-uiimage-from-given-uiimage). ¿Puede usted ayudar? – meteors

8

mirada en este método

+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size; 
    { 
     UIImage *img = nil; 

     CGRect rect = CGRectMake(0, 0, size.width, size.height); 
     UIGraphicsBeginImageContext(rect.size); 
     CGContextRef context = UIGraphicsGetCurrentContext(); 
     CGContextSetFillColorWithColor(context, 
            color.CGColor); 
     CGContextFillRect(context, rect); 
     img = UIGraphicsGetImageFromCurrentImageContext(); 

     UIGraphicsEndImageContext(); 

     return img; 
    } 
50

Por lo tanto, para resumir todas las respuestas en un solo aquí está el método de la gota-in que funciona perfectamente desde iOS 6 todo el camino hasta iOS 11 con todo tipo de imágenes e iconos:

+ (UIImage *)filledImageFrom:(UIImage *)source withColor:(UIColor *)color{ 

    // begin a new image context, to draw our colored image onto with the right scale 
    UIGraphicsBeginImageContextWithOptions(source.size, NO, [UIScreen mainScreen].scale); 

    // get a reference to that context we created 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // set the fill color 
    [color setFill]; 

    // translate/flip the graphics context (for transforming from CG* coords to UI* coords 
    CGContextTranslateCTM(context, 0, source.size.height); 
    CGContextScaleCTM(context, 1.0, -1.0); 

    CGContextSetBlendMode(context, kCGBlendModeColorBurn); 
    CGRect rect = CGRectMake(0, 0, source.size.width, source.size.height); 
    CGContextDrawImage(context, rect, source.CGImage); 

    CGContextSetBlendMode(context, kCGBlendModeSourceIn); 
    CGContextAddRect(context, rect); 
    CGContextDrawPath(context,kCGPathFill); 

    // generate a new UIImage from the graphics context we drew onto 
    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    //return the color-burned image 
    return coloredImg; 
} 

actualización: Swift 3 versión

func filledImage(source: UIImage, fillColor: UIColor) -> UIImage { 

    UIGraphicsBeginImageContextWithOptions(source.size, false, UIScreen.main.scale) 

    let context = UIGraphicsGetCurrentContext() 
    fillColor.setFill() 

    context!.translateBy(x: 0, y: source.size.height) 
    context!.scaleBy(x: 1.0, y: -1.0) 

    context!.setBlendMode(CGBlendMode.colorBurn) 
    let rect = CGRect(x: 0, y: 0, width: source.size.width, height: source.size.height) 
    context!.draw(source.cgImage!, in: rect) 

    context!.setBlendMode(CGBlendMode.sourceIn) 
    context!.addRect(rect) 
    context!.drawPath(using: CGPathDrawingMode.fill) 

    let coloredImg : UIImage = UIGraphicsGetImageFromCurrentImageContext()! 
    UIGraphicsEndImageContext() 

    return coloredImg 
} 
+1

¡Apreciar esto! Esta solución funciona bien en pantallas 2x y 3x. – huyleit

+0

Hola, esto es genial, ¿podemos hacerlo con animación? Como llenando? – Dilip

7

Desde iOS 7 no es una solución mucho más simple:

UIImage* im = [UIImage imageNamed:@"blah"]; 
im = [im imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 
[[UIColor blackColor] setFill]; 
[im drawInRect:rect]; 
+0

pero cuando muestro el resultado, tengo color azul. – Shial

+0

¿está llamando drawInRect usted mismo o simplemente pasando la imagen a otra clase? El código anterior solo funciona desde un método drawRect o similar. – zeroimpl

+0

Lo estoy pasando a uiview. Funciona cuando cambio Uiview tintcolor para el mismo color que la imagen – Shial

0

Así es como lo haces con Swift 3.0 y el uso de extensiones de UIImage. Súper simple.

public extension UIImage { 
    func filledImage(fillColor: UIColor) -> UIImage { 
     UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.main.scale) 

     let context = UIGraphicsGetCurrentContext()! 
     fillColor.setFill() 

     context.translateBy(x: 0, y: self.size.height) 
     context.scaleBy(x: 1.0, y: -1.0) 

     context.setBlendMode(CGBlendMode.colorBurn) 

     let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) 
     context.draw(self.cgImage!, in: rect) 

     context.setBlendMode(CGBlendMode.sourceIn) 
     context.addRect(rect) 
     context.drawPath(using: CGPathDrawingMode.fill) 

     let coloredImg : UIImage = UIGraphicsGetImageFromCurrentImageContext()! 
     UIGraphicsEndImageContext() 

     return coloredImg 
    } 
} 

A continuación, para ejecutar simplemente hacer:

let image = UIImage(named: "image_name").filledImage(fillColor: UIColor.red)