2012-03-13 19 views

Respuesta

3

¿Qué significa restar una imagen? la imagen de muestra dada muestra más de una operación! rojo. digamos que restar la imagen a de la imagen b significa establecer cada pixel en b que intersecta un pixel en a a transparente. para realizar la resta, lo que estamos haciendo en realidad es enmascarar la imagen b en el inverso de la imagen a. entonces, un buen enfoque sería crear una máscara de imagen del canal alfa de la imagen a, luego aplicarla a b. para crear la máscara, haría algo como esto:

// get access to the image bytes 
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 

// create a buffer to hold the mask values 
size_t width = CGImageGetWidth(image.CGImage); 
size_t height = CGImageGetHeight(image.CGImage);  
uint8_t *maskData = malloc(width * height); 

// iterate over the pixel data, reading the alpha value 
uint8_t *alpha = (uint8_t *)CFDataGetBytePtr(pixelData) + 3; 
uint8_t *mask = maskData; 
for (int y = 0; y < height; y++) { 
    for (int x = 0; x < width; x++) { 
     *mask = *alpha; 
     mask++;  
     alpha += 4; // skip to the next pixel 
    } 
} 

// create the mask image from the buffer 
CGDataProviderRef maskProvider = CGDataProviderCreateWithData(NULL, maskData, width * height, NULL); 
CGImageRef maskImage = CGImageMaskCreate(width, height, 8, 8, width, maskProvider, NULL, false); 

// cleanup 
CFRelease(pixelData); 
CFRelease(maskProvider); 
free(maskData); 

whew. luego, para enmascarar la imagen b, todo lo que tiene que hacer es:

CGImageRef subtractedImage = CGImageCreateWithMask(b.CGImage, maskImage); 

hey presto.

+0

buen ejemplo - esto es trabajo para mí. ¡Gracias! –

3

Para obtener esos resultados, use la segunda imagen como máscara cuando dibuje la primera imagen. Para este tipo de dibujo, deberás usar Core Graphics, a.k.a Quartz 2D. La Guía de programación 2D de cuarzo tiene una sección llamada Bitmap Images and Image Masks que debe decirle todo lo que necesita saber.

Estás preguntando por objetos UIImage, pero para usar Core Graphics necesitarás CGImages. Eso no es problema: UIImage proporciona una propiedad CGImage que le permite obtener los datos que necesita con facilidad.

13

Creo que puede lograr esto utilizando el modo de combinación kCGBlendModeDestinationOut. Cree un nuevo contexto, dibuje su imagen de fondo y luego dibuje la imagen de primer plano con este modo de fusión.

UIGraphicsBeginImageContextWithOptions(sourceImage.size, NO, sourceImage.scale) 
[sourceImage drawAtPoint:CGPointZero]; 
[maskImage drawAtPoint:CGPointZero blendMode:kCGBlendModeDestinationOut alpha:1.0f]; 
UIImage *result = UIGraphicsGetImageFromCurrentImageContext() 
UIGraphicsEndImageContext(); 
+0

+1: Aconsejaría que esto ocurra. Mucho más limpio y simple que la respuesta aceptada. – sjwarner

+0

Yo también, muy hábil. – Tark

+1

Sí, esta debería ser la respuesta aceptada. –

0

¡La solución de Kevin Ballard funcionó para mí! En Swift 3.x:

func subtract(source: UIImage, mask: UIImage) -> UIImage? { 
    UIGraphicsBeginImageContextWithOptions(source.size, false, source.scale) 
    source.draw(at: CGPoint.zero) 
    mask.draw(at: CGPoint.zero, blendMode: .destinationOut, alpha: 1.0) 
    let result = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
    return result 
}