74 votes

Comment teindre une image au format PNG transparent iPhone?

Je sais que c'est possible de la teinte d'une image rectangulaire, en dessinant un CGContextFillRect dessus et en réglant le mode de fusion. Cependant, je ne peux pas comprendre comment le faire d'une teinte sur une image transparente comme une icône. Il doit être possible depuis le SDK est-il lui-même sur l'onglet-barres. Quelqu'un serait-il en mesure de fournir un extrait de code?

Mise à JOUR:

Beaucoup de suggestions ont été avancées pour ce problème depuis que j'ai initialement demandé. Assurez-vous de lire toutes les réponses à comprendre ce qui vous convient le mieux.

165voto

fabb Points 3471

Si vous avez une image en niveaux de gris et souhaitez devenir blanc la teinte de couleur, kCGBlendModeMultiply est le chemin à parcourir. Avec cette méthode, vous ne pouvez pas avoir faits saillants plus claire que votre teinte de couleur.

Au contraire, si vous disposez soit d'une non-image en niveaux de gris, OU que vous avez faits saillants et les ombres qui doit être préservé, le mode de fusion kCGBlendModeColor est le chemin à parcourir. Le blanc va rester blanc et noir va rester noir comme la luminosité de l'image est préservée. Ce mode est faite pour teinter - c'est la même que Photoshop Color mode de fusion des calques (avertissement: légèrement différents résultats peuvent se produire).

Notez que la teinture alpha-pixels ne fonctionne pas correctement ni iOS, ni dans Photoshop - demi-transparents les pixels noirs ne voudrais pas rester noir. J'ai mis à jour la réponse ci-dessous pour contourner ce problème, il a fallu un temps assez long à trouver.

Vous pouvez également utiliser l'un des modes de fusion kCGBlendModeSourceIn/DestinationIn au lieu de CGContextClipToMask.

Si vous souhaitez créer un UIImage, des sections de code peut être entouré par le code suivant:

UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, [[UIScreen mainScreen] scale]); // for correct resolution on retina, thanks @MobileVet
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextTranslateCTM(context, 0, myIconImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGRect rect = CGRectMake(0, 0, myIconImage.size.width, myIconImage.size.height);

// image drawing code here

UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Voici donc le code pour colorer une image transparente avec kCGBlendModeColor:

// draw black background to preserve color of transparent pixels
CGContextSetBlendMode(context, kCGBlendModeNormal);
[[UIColor blackColor] setFill];
CGContextFillRect(context, rect);

// draw original image
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// tint image (loosing alpha) - the luminosity of the original image is preserved
CGContextSetBlendMode(context, kCGBlendModeColor);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

Si votre image n'a pas de demi-pixels transparents, vous pouvez aussi le faire dans l'autre sens avec des kCGBlendModeLuminosity:

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// replace luminosity of background (ignoring alpha)
CGContextSetBlendMode(context, kCGBlendModeLuminosity);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

Si vous n'avez pas de soins pour la luminosité, que vous avez juste obtenu une image avec un canal alpha qui devrait être teintées d'une couleur, vous pouvez le faire d'une façon plus efficace:

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

ou l'inverse:

// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);

Amusez-vous!

21voto

cania Points 347

J'ai eu le plus de succès avec cette méthode, parce que les autres j'ai essayé causé déformée couleurs de pixels semi-transparents pour certaines couleurs combinaisons. Cela devrait aussi être un peu mieux du côté de la performance.

+ (UIImage *) imageNamed:(NSString *) name withTintColor: (UIColor *) tintColor {

    UIImage *baseImage = [UIImage imageNamed:name];

    CGRect drawRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);

    UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, baseImage.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // draw original image
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGContextDrawImage(context, drawRect, baseImage.CGImage);

    // draw color atop
    CGContextSetFillColorWithColor(context, tintColor.CGColor);
    CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
    CGContextFillRect(context, drawRect);

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}

18voto

anna Points 1041

Après avoir cherché partout, la meilleure solution que j'ai parcouru à ce jour est d'utiliser une combinaison de mode de fusion et le masque d'écrêtage pour atteindre colorisation/teinte d'une image PNG transparente:

CGContextSetBlendMode (context, kCGBlendModeMultiply);

CGContextDrawImage(context, rect, myIconImage.CGImage);

CGContextClipToMask(context, rect, myIconImage.CGImage);

CGContextSetFillColorWithColor(context, tintColor);

CGContextFillRect(context, rect);

16voto

tozevv Points 350

Je peux obtenir des résultats très proches de la teinte dans la Pomme de la barre de navigation en utilisant kCGBlendModeOverlay. Prendre excelent @fabb réponse et en combinant @omz approche dans ce post http://stackoverflow.com/a/4684876/229019 je suis venu avec cette solution, qui organise les résultats que j'attendais:

- (UIImage *)tintedImageUsingColor:(UIColor *)tintColor;
{
    UIGraphicsBeginImageContextWithOptions (self.size, NO, [[UIScreen mainScreen] scale]);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    // draw original image
    [self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];

    // tint image (loosing alpha). 
    // kCGBlendModeOverlay is the closest I was able to match the 
    // actual process used by apple in navigation bar 
    CGContextSetBlendMode(context, kCGBlendModeOverlay);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    // mask by alpha values of original image
    [self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tintedImage;
}

Voici un exemple de teinture à plusieurs niveaux de gris des images avec transparence:

Rendered Example:

  • La première ligne est la pomme de la barre d'outils teinté [UIColor orangeColor].
  • La deuxième ligne est la même teinté dégradé de plusieurs couleurs, en commençant par couleur claire (= le véritable gradient) et se terminant avec le même orange.
  • Le troisième est un simple cercle avec de la transparence (le linge de maison est la couleur d'arrière-plan)
  • La quatrième ligne est un complexe sombre, bruyant texture

8voto

Kamil Kocemba Points 724

Vous pouvez créer une UIImage catégorie et de faire comme ceci:

- (instancetype)tintedImageWithColor:(UIColor *)tintColor {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect rect = (CGRect){ CGPointZero, self.size };
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    [self drawInRect:rect];

    CGContextSetBlendMode(context, kCGBlendModeSourceIn);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    UIImage *image  = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X