Question

J'ai une image en niveaux de gris que je souhaite utiliser pour dessiner des contrôles Cocoa. L'image a différents niveaux de gris. Où il est le plus sombre, je veux qu’il dessine une teinte spécifiée plus sombre. Je veux que ce soit transparent là où l'image source est blanche.

En gros, je souhaite reproduire le comportement de tintColor observé dans UINavigationBar sur iPhone.

Jusqu'à présent, j'ai exploré plusieurs options:

  • Dessinez la teinte sur l'image en niveaux de gris avec la composition SourceOver - > Cela nécessite une teinte non opaque - > Le résultat est beaucoup plus sombre que souhaité

  • Utilisez un CIFilter CIMultiplyCompositing pour teinter l'image - > Je ne peux pas [CIImage drawAtPoint: fromRect: operation: fraction:] pour dessiner seulement une partie de l'image. La même chose fonctionne bien avec NSImage - > J'ai des chutes occasionnelles que je n'arrive pas à comprendre.

  • Transformez l’image en niveaux de gris en masque. C'est à dire. Le noir devrait être opaque. Le blanc devrait être transparent. Gray devrait avoir des valeurs alpha intermédiaires. - > Cela semblerait être la meilleure solution - > Malgré tous mes efforts, je ne peux pas y arriver.

Était-ce utile?

La solution 3

- (NSImage *)imageTintedWithColor:(NSColor *)tint 
{
    if (tint != nil) {
        NSSize size = [self size];
        NSRect bounds = { NSZeroPoint, size };
        NSImage *tintedImage = [[NSImage alloc] initWithSize:size];

        [tintedImage lockFocus];

        CIFilter *colorGenerator = [CIFilter filterWithName:@"CIConstantColorGenerator"];
        CIColor *color = [[[CIColor alloc] initWithColor:tint] autorelease];

        [colorGenerator setValue:color forKey:@"inputColor"];

        CIFilter *monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome"];
        CIImage *baseImage = [CIImage imageWithData:[self TIFFRepresentation]];

        [monochromeFilter setValue:baseImage forKey:@"inputImage"];     
        [monochromeFilter setValue:[CIColor colorWithRed:0.75 green:0.75 blue:0.75] forKey:@"inputColor"];
        [monochromeFilter setValue:[NSNumber numberWithFloat:1.0] forKey:@"inputIntensity"];

        CIFilter *compositingFilter = [CIFilter filterWithName:@"CIMultiplyCompositing"];

        [compositingFilter setValue:[colorGenerator valueForKey:@"outputImage"] forKey:@"inputImage"];
        [compositingFilter setValue:[monochromeFilter valueForKey:@"outputImage"] forKey:@"inputBackgroundImage"];

        CIImage *outputImage = [compositingFilter valueForKey:@"outputImage"];

        [outputImage drawAtPoint:NSZeroPoint
                        fromRect:bounds
                       operation:NSCompositeCopy
                        fraction:1.0];

        [tintedImage unlockFocus];  

        return [tintedImage autorelease];
    }
    else {
        return [[self copy] autorelease];
    }
}

- (NSImage*)imageCroppedToRect:(NSRect)rect
{
    NSPoint point = { -rect.origin.x, -rect.origin.y };
    NSImage *croppedImage = [[NSImage alloc] initWithSize:rect.size];

    [croppedImage lockFocus];
    {
        [self compositeToPoint:point operation:NSCompositeCopy];
    }
    [croppedImage unlockFocus];

    return [croppedImage autorelease];
}

Autres conseils

La solution ci-dessus n'a pas fonctionné pour moi. Mais cette solution beaucoup plus facile fonctionne très bien pour moi

- (NSImage *)imageTintedWithColor:(NSColor *)tint
{
    NSImage *image = [self copy];
    if (tint) {
        [image lockFocus];
        [tint set];
        NSRect imageRect = {NSZeroPoint, [image size]};
        NSRectFillUsingOperation(imageRect, NSCompositeSourceAtop);
        [image unlockFocus];
    }
    return image;
}

Une implémentation rapide de la réponse de bluebamboo:

func tintedImage(_ image: NSImage, tint: NSColor) -> NSImage {
    guard let tinted = image.copy() as? NSImage else { return image }
    tinted.lockFocus()
    tint.set()

    let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
    NSRectFillUsingOperation(imageRect, .sourceAtop)

    tinted.unlockFocus()
    return tinted
}

Version Swift sous forme d'extension:

extension NSImage {
    func tintedImageWithColor(color:NSColor) -> NSImage {
        let size        = self.size
        let imageBounds = NSMakeRect(0, 0, size.width, size.height)
        let copiedImage = self.copy() as! NSImage

        copiedImage.lockFocus()
        color.set()
        NSRectFillUsingOperation(imageBounds, .CompositeSourceAtop)
        copiedImage.unlockFocus()

        return copiedImage
    }
}

Le filtre CIMultiplyCompositing est certainement le moyen de le faire. En cas de plantage, pouvez-vous poster une trace de pile? J'utilise beaucoup CIFilters et je n'ai pas de problème de plantage.

//assume inputImage is the greyscale CIImage you want to tint

CIImage* outputImage = nil;

//create some green
CIFilter* greenGenerator = [CIFilter filterWithName:@"CIConstantColorGenerator"];
CIColor* green = [CIColor colorWithRed:0.30 green:0.596 blue:0.172];
[greenGenerator setValue:green forKey:@"inputColor"];
CIImage* greenImage = [greenGenerator valueForKey:@"outputImage"];

//apply a multiply filter
CIFilter* filter = [CIFilter filterWithName:@"CIMultiplyCompositing"];
[filter setValue:greenImage forKey:@"inputImage"];
[filter setValue:inputImage forKey:@"inputBackgroundImage"];
outputImage = [filter valueForKey:@"outputImage"];

[outputImage drawAtPoint:NSZeroPoint fromRect:NSRectFromCGRect([outputImage extent]) operation:NSCompositeCopy fraction:1.0];

Je souhaitais teinter une image avec une teinte alpha, sans voir apparaître les couleurs d'origine de l'image. Voici comment vous pouvez le faire:

extension NSImage {
    func tinting(with tintColor: NSColor) -> NSImage {
        guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return self }

        return NSImage(size: size, flipped: false) { bounds in
            guard let context = NSGraphicsContext.current()?.cgContext else { return false }

            tintColor.set()
            context.clip(to: bounds, mask: cgImage)
            context.fill(bounds)

            return true
        }
    }
}

Pour un grain plus fin, vous pouvez utiliser une approche de couleur polynomiale, en utilisant l'approche que j'ai suggérée dans ce qui suit: Comment puis-je afficher le NSProgressIndicator en rotation dans une couleur différente?

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