En Quartz 2D, ¿Es posible enmascarar una imagen mediante la eliminación de todo, pero el canal de color que desea?

StackOverflow https://stackoverflow.com/questions/913719

Pregunta

Así que traté de usar la función de cuarzo CGImageCreateWithMaskingColors, pero él único problema es que las máscaras de la gama de colores que están seleccionando.

Quiero enmascarar todo, pero la gama de colores estoy seleccionando. Por ejemplo, yo quiero mostrar todos los colores rojos en una imagen, pero quitar los otros canales (verde y azul).

Estoy haciendo esto en Objective-C y yo soy un novato ejemplos por favor, así que me da:)

Cualquier ayuda es muy apreciada.

¿Fue útil?

Solución

utilizan estos methods.i ellos encuentran en uno de los SO mensajes.

-(void)changeColor
{
    UIImage *temp23=Image;//Pass your image here
    CGImageRef ref1=[self createMask:temp23];
    const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
    CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
    UIImage *resultedimage=[UIImage imageWithCGImage:New];
    EditImageView.image = resultedimage;
    [EditImageView setNeedsDisplay];
}

-(CGImageRef)createMask:(UIImage*)temp
{


    CGImageRef ref=temp.CGImage;
    int mWidth=CGImageGetWidth(ref);
    int mHeight=CGImageGetHeight(ref);
    int count=mWidth*mHeight*4;
    void *bufferdata=malloc(count);

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4, colorSpaceRef, kCGImageAlphaPremultipliedFirst); 

    CGRect rect = {0,0,mWidth,mHeight};
    CGContextDrawImage(cgctx, rect, ref); 
    bufferdata = CGBitmapContextGetData (cgctx);

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferdata, mWidth*mHeight*4, NULL);
    CGImageRef savedimageref = CGImageCreate(mWidth,mHeight, 8, 32, mWidth*4, colorSpaceRef, bitmapInfo,provider , NULL, NO, renderingIntent);
    CFRelease(colorSpaceRef);
    return savedimageref;
}

A continuación, llamar al método changeColor en un evento de botones de clic y ver el resultado

Otros consejos

He encontrado la respuesta a mi problema anterior, Siga el código anterior de Rahul con algunos cambios para establecer su propio color,

-(void)changeColor
{
    UIImage *temp23=Image;//Pass your image here
    CGImageRef ref1=[self createMask:temp23];
    const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
    CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
    UIImage *resultedimage=[UIImage imageWithCGImage:New];
    EditImageView.image = resultedimage;
    [EditImageView setNeedsDisplay];
}

-(CGImageRef)createMask:(UIImage*)temp
{
   CGImageRef ref=temp.CGImage;
   int mWidth=CGImageGetWidth(ref);
   int mHeight=CGImageGetHeight(ref);
   int count=mWidth*mHeight*4;
   void *bufferdata=malloc(count);

   CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
   CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
   CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

   CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4,colorSpaceRef, kCGImageAlphaPremultipliedLast); 
   CGRect rect = {0,0,mWidth,mHeight};  
   CGContextDrawImage(cgctx, rect, ref); 
   CGContextSaveGState(cgctx);  
   CGContextSetBlendMode(cgctx, kCGBlendModeColor); 
   CGContextSetRGBFillColor (cgctx, 1.0, 0.0, 0.0, 1.0);
   CGContextFillRect(cgctx, rect);


   bufferdata = CGBitmapContextGetData (cgctx);
   const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
   CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferdata, mWidth*mHeight*4, NULL);
   CGImageRef savedimageref = CGImageCreate(mWidth,mHeight, 8, 32, mWidth*4, colorSpaceRef, bitmapInfo,provider , NULL, NO, renderingIntent);
   CFRelease(colorSpaceRef);
   return savedimageref;
}

Hmmm ...

puedo estar perdiendo algo, pero no creo que las respuestas proporcionadas se aplican a la pregunta. La segunda respuesta se acerca a la marca, pero contiene código espuria que tiene poco que ver con la solución.

El método createMask hace una copia de la imagen asumiendo alfa original en LSB posición. El changeColor realiza una llamada de enmascaramiento que no se va a hacer mucho a una imagen RGB - básicamente sólo el negro va a ser enmascarada (es decir, tripletes RGB en el rango / combinaciones de (1,1,2) a (3, 2,1)).

Estoy adivinando que el desplazamiento hacia el rojo que se observa es debido al parámetro

kCGImageAlphaPremultipliedFirst

en la línea

CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4, colorSpaceRef, kCGImageAlphaPremultipliedFirst);

debido al tratamiento inadecuado del canal alfa. Si en el método changeColor modifica el bloque

CGImageRef ref1=[self createMask:temp23];
const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
UIImage *resultedimage=[UIImage imageWithCGImage:New];
EditImageView.image = resultedimage;

ser

CGImageRef ref1=[self createMask:temp23];
UIImage *resultedimage=[UIImage imageWithCGImage:ref];
EditImageView.image = resultedimage;

verá ninguna diferencia en la pantalla. Cambio de la constante CGBitmapInfo a kCGImageAlphaPremultipliedLast debe mostrar la imagen correctamente mediante uno de los bloques de código de seguridad.

La siguiente respuesta se hace un poco más cerca de lo que el PO pide, pero en términos de su efecto visual, los datos no reales. Aquí el código pertinente en createMask es

CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4,colorSpaceRef, kCGImageAlphaPremultipliedLast);

que muestra la imagen correctamente, seguido por

CGContextSetBlendMode(cgctx, kCGBlendModeColor); 
CGContextSetRGBFillColor (cgctx, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(cgctx, rect);

y luego la lógica para la construcción de la imagen. La lógica mezcla se superpone a un tinte rojo en la imagen original, la consecución de un efecto similar como el canal alfa fuera de lugar en la respuesta original. Esto todavía no es realmente lo que el PO pide, que es para enmascarar uno o más canales, no mezclar los colores.

Esto realmente equivale a establecer los valores de los canales de los colores que no son deseados a cero. He aquí un ejemplo para devolver sólo el canal rojo como las solicitudes OP; el supuesto es que el formato de píxel es ABGR:

- (CGImageRef) redChannel:(CGImageRef)image 
{
    CGDataProviderRef provider = CGImageGetDataProvider(image);
    NSMutableData* data = (id)CGDataProviderCopyData(provider);

    int width = CGImageGetWidth(image);
    int height = CGImageGetHeight(image);

    [data autorelease];

    // get a mutable reference to the image data
    uint32_t* dwords = [data mutableBytes];

    for (size_t idx = 0; idx < width*height; idx++) {
        uint32_t* pixel = &dwords[idx];
        // perform a logical AND of the pixel with a mask that zeroes out green and blue pixels
        *pixel &= 0x000000ff;
    }

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // now create a new image using the masked original data
    CGDataProviderRef iprovider = CGDataProviderCreateWithData(NULL, dwords, width*height*4, NULL);
    CGImageRef savedimageref = CGImageCreate(width, height, 8, 32, width*4, colorSpaceRef, bitmapInfo, iprovider, NULL, NO, renderingIntent);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(iprovider);

    return savedimageref;
}

Un buen resumen de las operaciones a nivel de bits se puede encontrar aquí .

Como se señala aquí , es posible que tenga que cambiar la estructura de la máscara en función de la LSB / MSB orden de los bits en el píxel. Este ejemplo supone 32 bits píxeles de una norma iPhone PNG.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top