In Quartz 2D, E 'possibile mascherare un'immagine rimuovendo tutto, ma il canale di colore che si desidera?
-
06-09-2019 - |
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.
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.