In Quartz 2D, E 'possibile mascherare un'immagine rimuovendo tutto, ma il canale di colore che si desidera?

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

Domanda

Così ho cercato di utilizzare la funzione di quarzo CGImageCreateWithMaskingColors, ma unico problema è che si maschera la gamma di colori si sta selezionando.

Voglio mascherare tutto, ma la gamma di colori che sto selezionando. Per esempio, voglio mostrare tutti i colori rossi in un quadro, ma rimuovere gli altri canali (verde e blu).

Sto facendo questo in Objective-C e io sono un noob quindi vi prego di dare esempi:)

Ogni aiuto è molto apprezzato.

È stato utile?

Soluzione

usano questi methods.i li ha trovati in uno dei SO messaggi.

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

quindi chiamare il metodo ChangeColor su un pulsanti clicca evento e vedere il risultato

Altri suggerimenti

ho trovato la risposta per il mio problema di cui sopra, seguire il codice precedente di Rahul con alcune modifiche per impostare il proprio colore,

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

I può essere manca qualcosa, ma non credo che le risposte fornite si applicano alla domanda. La seconda risposta si avvicina al marchio, ma contiene il codice spuria che ha poco a che fare con la soluzione.

Il metodo createMask esegue una copia del alfa dell'immagine originale assumendo in peso debole. Il ChangeColor esegue una chiamata mascheramento che non sta andando a fare molto per un'immagine RGB - fondamentalmente solo nero sta per essere mascherata (cioè, triplette RGB nell'intervallo / combinazioni di (1,1,2) a (3, 2,1)).

Sono indovinando che lo spostamento rosso che viene osservato è dovuto al parametro

kCGImageAlphaPremultipliedFirst

nella linea

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

a causa di trattamento improprio del canale alfa. Se nel metodo changeColor si modifica il blocco

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;

essere

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

si vedrà alcuna differenza nel display. Cambiando la costante CGBitmapInfo per kCGImageAlphaPremultipliedLast dovrebbe visualizzare l'immagine correttamente utilizzando uno dei blocchi di codice di cui sopra.

La risposta successiva diventa un po 'più vicino a quello del PO chiede, ma la sua in termini di effetto visivo, i dati non attuali. Ecco il codice pertinente in createMask è

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

che visualizza l'immagine correttamente, seguito da

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

e quindi la logica per la costruzione dell'immagine. La logica miscela sovrappone una tinta rossa sull'immagine originale, ottenendo un effetto simile come canale alfa fuori luogo nella risposta originale. Questo ancora realtà non è quello che il PO chiede, che è quello di mascherare uno o più canali, non fondere i colori.

Ciò equivale davvero a impostare i valori del canale per i colori che non sono desiderati a zero. Ecco un esempio per restituire solo il canale rosso come le richieste di OP; l'ipotesi è che il formato del 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;
}

Una buona sintesi delle operazioni bit per bit può essere trovato qui .

Come è sottolineato qui , potrebbe essere necessario modificare la struttura della maschera a seconda della LSB / MSB ordinamento dei bit del pixel. Questo esempio presuppone 32 pixel bit da un iPhone PNG standard.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top