En Quartz 2D, est-il possible de masquer une image en supprimant tout, mais le canal de couleur que vous voulez?

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

Question

J'ai donc essayé d'utiliser la fonction Quartz CGImageCreateWithMaskingColors, mais il seul problème est qu'il masque la gamme de couleurs que vous sélectionnez.

Je veux masquer tout, mais la gamme de couleurs je choisissais. Par exemple, je veux montrer toutes les couleurs rouges dans une image, mais retirer les autres canaux (vert et bleu).

Je fais cela en Objective-C et je suis un noob donc s'il vous plaît me donner des exemples:)

Toute aide est grandement appréciée.

Était-ce utile?

La solution

utiliser ces methods.i les a trouvés dans l'un des SO messages.

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

puis appeler la méthode de changeColor sur un bouton cliquez sur l'événement et voir le résultat

Autres conseils

J'ai trouvé la réponse à mon problème ci-dessus, suivez le code ci-dessus Rahul avec quelques modifications pour définir votre propre couleur,

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

Je peux manquer quelque chose, mais je ne crois pas que les réponses fournies appliquent à la question. La deuxième réponse se rapproche de la marque, mais il contient le code parasite qui a peu à voir avec la solution.

La méthode de createMask fait une copie de l'image originale en supposant alpha en position de LSB. Le changeColor effectue un appel de masquage qui ne va pas faire grand-chose à une image RVB - essentiellement que le noir va être masqué (c.-à-triplets RVB dans la gamme / combinaisons de (1,1,2) à (3, 2,1)).

Je suppose que le décalage vers le rouge qui est observée est due au paramètre

kCGImageAlphaPremultipliedFirst

dans la ligne

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

en raison d'un mauvais traitement de la couche alpha. Si la méthode de changeColor vous modifiez le bloc

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;

être

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

vous ne verrez aucune différence dans l'affichage. Modification de la constante CGBitmapInfo à kCGImageAlphaPremultipliedLast devrait afficher l'image en utilisant correctement l'un des blocs de code ci-dessus.

La réponse suivante devient un peu plus proche de ce que l'OP demande, mais en termes de son effet visuel, pas de données réelles. Voici le code pertinent dans createMask est

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

qui affiche l'image correctement, suivi de

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

et la logique pour la construction de l'image. La logique de fusion se superpose à une teinte rouge sur l'image originale, obtenir un effet similaire à celui du canal alpha déplacée dans la réponse initiale. Ceci est encore vraiment pas ce que l'OP demande, ce qui est de masquer un ou plusieurs canaux, pas mélanger les couleurs.

Cela revient vraiment à la définition des valeurs de canal pour les couleurs qui ne sont pas souhaitées à zéro. Voici un exemple pour revenir juste le canal rouge comme les demandes OP; l'hypothèse est que le format du pixel est 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 bon résumé des opérations binaires sont disponibles ici .

Comme indiqué ici , vous devrez peut-être modifier la structure du masque en fonction de l'ordre LSB / MSB des bits du pixel. Cet exemple suppose 32 pixels de bits à partir d'une norme iPhone PNG.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top