2010-07-19 16 views

Respuesta

10

No puede acceder directamente a los datos brutos, pero al obtener la CGImage de esta imagen puede acceder a ella. aquí es un enlace a otra pregunta que responde a su pregunta y otros que pueda tener con respecto a la manipulación de imágenes detalladas: CGImage

85

probar este código muy simple:

he usado para detectar una pared en mi juego de laberinto (la única información que necesito es el canal alfa, pero incluye el código para obtener los otros colores para usted):

- (BOOL)isWallPixel:(UIImage *)image xCoordinate:(int)x yCoordinate:(int)y { 

    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 
    const UInt8* data = CFDataGetBytePtr(pixelData); 

    int pixelInfo = ((image.size.width * y) + x) * 4; // The image is png 

    //UInt8 red = data[pixelInfo];   // If you need this info, enable it 
    //UInt8 green = data[(pixelInfo + 1)]; // If you need this info, enable it 
    //UInt8 blue = data[pixelInfo + 2]; // If you need this info, enable it 
    UInt8 alpha = data[pixelInfo + 3];  // I need only this info for my maze game 
    CFRelease(pixelData); 

    //UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f]; // The pixel color info 

    if (alpha) return YES; 
    else return NO; 

} 
+0

podría usted ayudar a obtener la posición del píxel en relación con el tamaño de la imagen. Estoy usando esto para el posicionamiento de objetos en mi juego. Gracias. – tallen11

+0

Lo siento, pero no entendí su pregunta. ¿Puedes ser mas específico? Publicar un código de ejemplo? ¿Quieres encontrar un píxel en una imagen? –

+0

¿qué es xyy? –

16

OnTouch

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [[touches allObjects] objectAtIndex:0]; 
    CGPoint point1 = [touch locationInView:self.view]; 
    touch = [[event allTouches] anyObject]; 
    if ([touch view] == imgZoneWheel) 
    { 
     CGPoint location = [touch locationInView:imgZoneWheel]; 
     [self getPixelColorAtLocation:location]; 
     if(alpha==255) 
     { 
      NSLog(@"In Image Touch view alpha %d",alpha); 
      [self translateCurrentTouchPoint:point1.x :point1.y]; 
      [imgZoneWheel setImage:[UIImage imageNamed:[NSString stringWithFormat:@"blue%d.png",GrndFild]]]; 
     } 
    } 
} 



- (UIColor*) getPixelColorAtLocation:(CGPoint)point 
{ 

    UIColor* color = nil; 

    CGImageRef inImage; 

    inImage = imgZoneWheel.image.CGImage; 


    // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue 
    CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage]; 
    if (cgctx == NULL) { return nil; /* error */ } 

    size_t w = CGImageGetWidth(inImage); 
    size_t h = CGImageGetHeight(inImage); 
    CGRect rect = {{0,0},{w,h}}; 


    // Draw the image to the bitmap context. Once we draw, the memory 
    // allocated for the context for rendering will then contain the 
    // raw image data in the specified color space. 
    CGContextDrawImage(cgctx, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap 
    // context. 
    unsigned char* data = CGBitmapContextGetData (cgctx); 
    if (data != NULL) { 
     //offset locates the pixel in the data from x,y. 
     //4 for 4 bytes of data per pixel, w is width of one row of data. 
     int offset = 4*((w*round(point.y))+round(point.x)); 
     alpha = data[offset]; 
     int red = data[offset+1]; 
     int green = data[offset+2]; 
     int blue = data[offset+3]; 
     color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)]; 
    } 

    // When finished, release the context 
    //CGContextRelease(cgctx); 
    // Free image data memory for the context 
    if (data) { free(data); } 

    return color; 
} 

- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef)inImage 
{ 
    CGContextRef context = NULL; 
    CGColorSpaceRef colorSpace; 
    void *   bitmapData; 
    int    bitmapByteCount; 
    int    bitmapBytesPerRow; 

    // Get image width, height. We'll use the entire image. 
    size_t pixelsWide = CGImageGetWidth(inImage); 
    size_t pixelsHigh = CGImageGetHeight(inImage); 

    // Declare the number of bytes per row. Each pixel in the bitmap in this 
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and 
    // alpha. 
    bitmapBytesPerRow = (pixelsWide * 4); 
    bitmapByteCount  = (bitmapBytesPerRow * pixelsHigh); 

    // Use the generic RGB color space. 
    colorSpace = CGColorSpaceCreateDeviceRGB(); 

    if (colorSpace == NULL) 
    { 
     fprintf(stderr, "Error allocating color space\n"); 
     return NULL; 
    } 

    // Allocate memory for image data. This is the destination in memory 
    // where any drawing to the bitmap context will be rendered. 
    bitmapData = malloc(bitmapByteCount); 
    if (bitmapData == NULL) 
    { 
     fprintf (stderr, "Memory not allocated!"); 
     CGColorSpaceRelease(colorSpace); 
     return NULL; 
    } 

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits 
    // per component. Regardless of what the source image format is 
    // (CMYK, Grayscale, and so on) it will be converted over to the format 
    // specified here by CGBitmapContextCreate. 
    context = CGBitmapContextCreate (bitmapData, 
            pixelsWide, 
            pixelsHigh, 
            8,  // bits per component 
            bitmapBytesPerRow, 
            colorSpace, 
            kCGImageAlphaPremultipliedFirst); 
    if (context == NULL) 
    { 
     free (bitmapData); 
     fprintf (stderr, "Context not created!"); 
    } 

    // Make sure and release colorspace before returning 
    CGColorSpaceRelease(colorSpace); 

    return context; 
} 
+0

'point = CGPointMake (point.x * image.scale, point.y * image.scale);' – uranpro

0

En primer lugar reconocedor de crear y adjuntar grifo gesto permiten permiten interacciones de los usuarios:

UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)]; 
[self.label addGestureRecognizer:tapRecognizer]; 
self.label.userInteractionEnabled = YES; 

Ahora implementan -tapGesture:

- (void)tapGesture:(UITapGestureRecognizer *)recognizer 
{ 
    CGPoint point = [recognizer locationInView:self.label]; 

    UIGraphicsBeginImageContext(self.label.bounds.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    [self.label.layer renderInContext:context]; 

    int bpr = CGBitmapContextGetBytesPerRow(context); 
    unsigned char * data = CGBitmapContextGetData(context); 
    if (data != NULL) 
    { 
     int offset = bpr*round(point.y) + 4*round(point.x); 
     int blue = data[offset+0]; 
     int green = data[offset+1]; 
     int red = data[offset+2]; 
     int alpha = data[offset+3]; 

     NSLog(@"%d %d %d %d", alpha, red, green, blue); 

     if (alpha == 0) 
     { 
      // Here is tap out of text 
     } 
     else 
     { 
      // Here is tap right into text 
     } 
    } 

    UIGraphicsEndImageContext(); 
} 

Esta voluntad trabaja en UILabel con fondo transparente, si esto no es lo que quiere puede comparar alfa, rojo, verde, azul con self.label.backgroundColor ...

+1

¿Qué tiene que ver esto? con un gesto de toque? – amleszk

9

Aquí hay un método genérico para obtener el color del píxel en una imagen UI, basándose en Minas Petterson ' s respuesta:

- (UIColor*)pixelColorInImage:(UIImage*)image atX:(int)x atY:(int)y { 

    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 
    const UInt8* data = CFDataGetBytePtr(pixelData); 

    int pixelInfo = ((image.size.width * y) + x) * 4; // 4 bytes per pixel 

    UInt8 red = data[pixelInfo + 0]; 
    UInt8 green = data[pixelInfo + 1]; 
    UInt8 blue = data[pixelInfo + 2]; 
    UInt8 alpha = data[pixelInfo + 3]; 
    CFRelease(pixelData); 

    return [UIColor colorWithRed:red /255.0f 
          green:green/255.0f 
          blue:blue /255.0f 
          alpha:alpha/255.0f]; 
} 

Tenga en cuenta que X e Y pueden intercambiarse; esta función accede directamente al mapa de bits subyacente y no considera las rotaciones que pueden ser parte del UIImage.

+0

¿Hay alguna manera de volver a colocar la imagen junto con estos números de color? – anivader

+1

esta función tampoco tiene en cuenta el formato, que es BGR para mí. – Andy

7
- (UIColor *)colorAtPixel:(CGPoint)point inImage:(UIImage *)image { 

    if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), point)) { 
     return nil; 
    } 

    // Create a 1x1 pixel byte array and bitmap context to draw the pixel into. 
    NSInteger pointX = trunc(point.x); 
    NSInteger pointY = trunc(point.y); 
    CGImageRef cgImage = image.CGImage; 
    NSUInteger width = image.size.width; 
    NSUInteger height = image.size.height; 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    int bytesPerPixel = 4; 
    int bytesPerRow = bytesPerPixel * 1; 
    NSUInteger bitsPerComponent = 8; 
    unsigned char pixelData[4] = { 0, 0, 0, 0 }; 
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
    CGColorSpaceRelease(colorSpace); 
    CGContextSetBlendMode(context, kCGBlendModeCopy); 

    // Draw the pixel we are interested in onto the bitmap context 
    CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height); 
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage); 
    CGContextRelease(context); 

    // Convert color values [0..255] to floats [0.0..1.0] 
    CGFloat red = (CGFloat)pixelData[0]/255.0f; 
    CGFloat green = (CGFloat)pixelData[1]/255.0f; 
    CGFloat blue = (CGFloat)pixelData[2]/255.0f; 
    CGFloat alpha = (CGFloat)pixelData[3]/255.0f; 
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 
} 
+0

Creo que el resultado es incorrecto porque la información alfa del contexto del mapa de bits es * kCGImageAlphaPremultipliedLast *. Sin embargo, cuando recupera el color de píxel, lo trata como el valor no premultiplicado. – Swordsfrog

4

Algunos códigos Swift se basan en la respuesta de Minas. Hemos ampliado en UIImage para que sea accesible en todas partes, y he añadido un poco de lógica simple de adivinar el formato de imagen basado en la zancada de píxeles (1, 3, o 4)

Swift 3:

public extension UIImage { 
    func getPixelColor(point: CGPoint) -> UIColor { 
    guard let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage)) else { 
     return UIColor.clearColor() 
    } 
    let data = CFDataGetBytePtr(pixelData) 
    let x = Int(point.x) 
    let y = Int(point.y) 
    let index = Int(self.size.width) * y + x 
    let expectedLengthA = Int(self.size.width * self.size.height) 
    let expectedLengthRGB = 3 * expectedLengthA 
    let expectedLengthRGBA = 4 * expectedLengthA 
    let numBytes = CFDataGetLength(pixelData) 
    switch numBytes { 
    case expectedLengthA: 
     return UIColor(red: 0, green: 0, blue: 0, alpha: CGFloat(data[index])/255.0) 
    case expectedLengthRGB: 
     return UIColor(red: CGFloat(data[3*index])/255.0, green: CGFloat(data[3*index+1])/255.0, blue: CGFloat(data[3*index+2])/255.0, alpha: 1.0) 
    case expectedLengthRGBA: 
     return UIColor(red: CGFloat(data[4*index])/255.0, green: CGFloat(data[4*index+1])/255.0, blue: CGFloat(data[4*index+2])/255.0, alpha: CGFloat(data[4*index+3])/255.0) 
    default: 
     // unsupported format 
     return UIColor.clearColor() 
    } 
    } 
} 

Actualizado para la Swift 4:

func getPixelColor(_ image:UIImage, _ point: CGPoint) -> UIColor { 
    let cgImage : CGImage = image.cgImage! 
    guard let pixelData = CGDataProvider(data: (cgImage.dataProvider?.data)!)?.data else { 
     return UIColor.clear 
    } 
    let data = CFDataGetBytePtr(pixelData)! 
    let x = Int(point.x) 
    let y = Int(point.y) 
    let index = Int(image.size.width) * y + x 
    let expectedLengthA = Int(image.size.width * image.size.height) 
    let expectedLengthRGB = 3 * expectedLengthA 
    let expectedLengthRGBA = 4 * expectedLengthA 
    let numBytes = CFDataGetLength(pixelData) 
    switch numBytes { 
    case expectedLengthA: 
     return UIColor(red: 0, green: 0, blue: 0, alpha: CGFloat(data[index])/255.0) 
    case expectedLengthRGB: 
     return UIColor(red: CGFloat(data[3*index])/255.0, green: CGFloat(data[3*index+1])/255.0, blue: CGFloat(data[3*index+2])/255.0, alpha: 1.0) 
    case expectedLengthRGBA: 
     return UIColor(red: CGFloat(data[4*index])/255.0, green: CGFloat(data[4*index+1])/255.0, blue: CGFloat(data[4*index+2])/255.0, alpha: CGFloat(data[4*index+3])/255.0) 
    default: 
     // unsupported format 
     return UIColor.clear 
    } 
} 
+0

Pregunta a los demás ya que no estoy tan seguro. Pensaría que si solo hay 1 byte por píxel, sería el valor blanco, no el valor alfa. ¿Pueden otros confirmar? – BridgeTheGap

+0

Puede ser cualquiera; tienes que hacer esa llamada de juicio. La imagen podría ser una imagen en escala de grises, en cuyo caso el valor sería blanco, pero también podría ser una máscara de transparencia, en cuyo caso sería alfa. Diría que las máscaras de transparencia son probablemente más comunes hoy en día que las imágenes en escala de grises, por lo que la decisión de usar alfa está justificada. Personalmente, creo que esto podría mejorarse en la instancia específica, ya que no es eficiente hacer todo este código cada vez que se prueba un píxel al iterar una gran cantidad de píxeles. – Ash

+0

n.b. puede averiguar si una imagen es una máscara usando la propiedad 'isMask' de' CGImage'. – Ash

Cuestiones relacionadas