Em Quartz 2D, é possível mascarar uma imagem, removendo tudo, mas o canal de cor que você quer?

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

Pergunta

Então, eu tentei usar a função Quartz CGImageCreateWithMaskingColors, mas único problema é que ele mascara a gama de cores que você está selecionando.

Eu quero mascarar tudo, mas a cor variam eu estou selecionando. Por exemplo, eu quero mostrar todas as cores vermelhas em uma imagem, mas remover os outros canais (verde e azul).

Estou fazendo isso em Objective-C e eu sou um noob por isso, dar-me exemplos:)

Qualquer ajuda é muito apreciada.

Foi útil?

Solução

usar estes methods.i os encontrou em uma das mensagens-lo.

-(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;
}

, em seguida, chamar o método changecolor em um botões de clique evento e ver o resultado

Outras dicas

Eu encontrei a resposta para o meu problema acima, siga o código acima de Rahul com algumas alterações para definir a sua própria cor,

-(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 ...

Eu pode estar faltando alguma coisa, mas eu não acredito que as respostas fornecidas aplicam-se a questão. A segunda resposta fica mais perto da marca, mas contém código espúria que tem pouco a ver com a solução.

O método createMask faz uma cópia da imagem assumindo alpha original na LSB posição. Os executa changeColor uma chamada de mascaramento que não vai fazer muito para uma imagem RGB - basicamente apenas preto vai ser mascarados (ou seja, tripletos RGB na gama / combinações de (1,1,2) a (3, 2,1)).

Eu estou supondo que o desvio para o vermelho que está sendo observado é devido ao parâmetro

kCGImageAlphaPremultipliedFirst

na linha

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

devido a tratamento inadequado do canal alfa. Se no método changeColor você modificar o bloco

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;

Você verá nenhuma diferença no visor. Alterar a constante CGBitmapInfo para kCGImageAlphaPremultipliedLast deve exibir a imagem corretamente utilizando um dos blocos de código acima.

A próxima resposta fica um pouco mais perto do que o OP pede, mas sua em termos de efeito visual, os dados não reais. Aqui o código pertinente no createMask é

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

que exibe a imagem corretamente, seguido por

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

e, em seguida, a lógica para a construção da imagem. A lógica mistura sobrepõe uma tonalidade vermelho na imagem original, se conseguir um efeito semelhante ao do canal alfa deslocada na resposta original. Isso ainda não é realmente o que o OP pede, que é para mascarar um ou mais canais, não misturar cores.

Este realmente equivale a definir os valores de canal para as cores que não são desejados para zero. Aqui está um exemplo para devolver apenas o canal vermelho como as solicitações do OP; o pressuposto é que o formato do pixel é 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;
}

Um resumo bem de operações bit a bit pode ser encontrada aqui .

Como está fora pontas aqui , você pode precisar alterar a estrutura da máscara, dependendo da LSB MSB ordenação / dos bits no pixel. Este exemplo assume 32 bits pixels a partir de um iPhone PNG padrão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top