2009-07-21 16 views
27

Estoy tratando de desarrollar una pequeña aplicación. En él, necesito detectar el color de un píxel dentro de una UIView. Tengo un CGPoint que define el píxel que necesito. Los colores de UIView se cambian con CoreAnimation.¿Cómo obtener el color de un píxel en una UIView?

Sé que hay algunas formas complejas de extraer información de color de UIImages. Sin embargo, no pude encontrar una solución para UIViews.

En pseudo-código que estoy buscando algo como

pixel = [view getPixelAtPoint:myPoint]; 
UIColor *mycolor = [pixel getColor]; 

Cualquier entrada muy apreciado.

+0

¿Encontró una solución (rápida)? – CodeAndCats

+0

Usar el contexto del mapa de bits resultó ser lo suficientemente rápido para mis propósitos. Pruébelo y vea cómo funciona para usted. – 0x90

Respuesta

8

Es bastante horrible y lento. Básicamente se crea un contexto de mapa de bits con un almacén de respaldo que se asigna para que pueda leer la memoria, luego se renderiza la capa de vistas en el contexto y se lee el punto apropiado en ram.

Si sabe cómo hacerlo de una imagen ya se puede hacer algo como esto:

- (UIImage *)imageForView:(UIView *)view { 
    UIGraphicsBeginImageContext(view.frame.size); 
    [view.layer renderInContext: UIGraphicsGetCurrentContext()]; 
    UIImage *retval = UIGraphicsGetImageFromCurrentImageContext(void); 
    UIGraphicsEndImageContext(); 

    return retval; 
} 

Y por lo que recibirá una imagen donde se puede obtener los datos de píxeles. Estoy seguro de que el mecanismo que tiene para tratar con las imágenes implica pasarlas a un contexto de todos modos, por lo que puede fusionar eso con esto y factorizar la creación de la imagen real. Así que si usted toma que podía y quitar la parte en la que se carga la imagen y reemplazarlo con el contexto render:

[view.layer renderInContext: UIGraphicsGetCurrentContext()]; 

usted debe ser bueno.

3

han solucionado algunos errores menores

- (UIImage *)imageForView:(UIView *)view { 
    UIGraphicsBeginImageContext(view.frame.size); 
    [view.layer renderInContext: UIGraphicsGetCurrentContext()]; 
    UIImage *retval = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return retval; 
} 

Además, añadir

#import <QuartzCore/QuartzCore.h> 

a su archivo para evitar mensajes de advertencia.

La combinación de su código con el código encontrado here funciona sin problemas.

+0

¿Por qué parece que simplemente copió el código de Louis y eliminó el "vacío" superfluo en la llamada a 'UIGraphicsGetImageFromCurrentImageContext()'? –

+1

Eso es lo que hice. ¿Cuál es una mejor forma de manejar las correcciones aquí? – 0x90

70

Aquí es la solución más eficiente:

// UIView+ColorOfPoint.h 
@interface UIView (ColorOfPoint) 
- (UIColor *) colorOfPoint:(CGPoint)point; 
@end 

// UIView+ColorOfPoint.m 
#import "UIView+ColorOfPoint.h" 
#import <QuartzCore/QuartzCore.h> 

@implementation UIView (ColorOfPoint) 

- (UIColor *) colorOfPoint:(CGPoint)point 
{ 
    unsigned char pixel[4] = {0}; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); 

    CGContextTranslateCTM(context, -point.x, -point.y); 

    [self.layer renderInContext:context]; 

    CGContextRelease(context); 
    CGColorSpaceRelease(colorSpace); 

    //NSLog(@"pixel: %d %d %d %d", pixel[0], pixel[1], pixel[2], pixel[3]); 

    UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0]; 

    return color; 
} 

@end 

Enlace de archivos: https://github.com/ivanzoid/ikit/tree/master/UIView+ColorOfPoint

+0

Advertencia en .m, eliminada con '#import ' – Jonny

+0

Parece que está renderizando solo un píxel. Muy genial. – mahboudz

+1

@mahboudz: sí, está absolutamente correcto – ivanzoid

14

Una versión swift'ified de ivanzoid 's respuesta

Swift 3

extension CALayer { 

    func colorOfPoint(point:CGPoint) -> CGColor { 

     var pixel: [CUnsignedChar] = [0, 0, 0, 0] 

     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) 

     let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) 

     context!.translateBy(x: -point.x, y: -point.y) 

     self.render(in: context!) 

     let red: CGFloat = CGFloat(pixel[0])/255.0 
     let green: CGFloat = CGFloat(pixel[1])/255.0 
     let blue: CGFloat = CGFloat(pixel[2])/255.0 
     let alpha: CGFloat = CGFloat(pixel[3])/255.0 

     let color = UIColor(red:red, green: green, blue:blue, alpha:alpha) 

     return color.cgColor 
    } 
} 

Swift 2

extension CALayer { 

    func colorOfPoint(point:CGPoint)->CGColorRef 
    { 
     var pixel:[CUnsignedChar] = [0,0,0,0] 

     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue) 

     let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, bitmapInfo.rawValue) 

     CGContextTranslateCTM(context, -point.x, -point.y) 

     self.renderInContext(context!) 

     let red:CGFloat = CGFloat(pixel[0])/255.0 
     let green:CGFloat = CGFloat(pixel[1])/255.0 
     let blue:CGFloat = CGFloat(pixel[2])/255.0 
     let alpha:CGFloat = CGFloat(pixel[3])/255.0 

     let color = UIColor(red:red, green: green, blue:blue, alpha:alpha) 

     return color.CGColor 
    } 

} 

en torno a la CALayer subyacente pero fácilmente traducible de nuevo a UIView.

+0

gracias tanto que – Jacky

+1

intenté usarlo pero devuelve solo ceros. así que siempre tengo color blanco. Desafortunadamente mis habilidades de programación no son tan avanzadas como para descubrirme. gracias – Lachtan

Cuestiones relacionadas