Comment colorer des icônes au runtime en Objective-C sur iOS

Ecrit par le Mercredi 10 Juillet 2013

Comment colorer des icônes au runtime en Objective-C sur iOS
GoodBarber vous permet de créer de belles applications, à votre image, en quelques clics. Parmi les centaines de nouveautés de la V2, nous avons mis en place un système vous permettant de colorer vos icônes de TabBar simplement pour créer de jolis effets.

Nous avons choisi de vous proposer un large choix d’icônes, mais il était évidemment impossible d’anticiper toutes les possibilités de customisation. Pour des raisons de cohérence, et notamment car nous vous proposons toujours d’utiliser une TabBar au design standard, nous avons choisi de conserver comme base un set d’icônes au format standard (PNG blanc jouant uniquement sur la transparence).

Afin mettre en place un système permettant de colorer les images depuis les applications clientes en fonction des paramètres renseigné (couleur au format hexa), nous avons suivi le raisonnement suivant.

Colorer une image avec CGImageCreateWithMask

Comment colorer des icônes au runtime en Objective-C sur iOS
La fonction la plus adaptée pour colorer une image en fonction d’un masque (notre icône de base en l’occurence) est CGImageCreateWithMask. Cette fonction prend un premier paramètre correspondant à l’image devant être découpée selon le masque (la couleur) et le masque proprement dit (l’icône). Très basiquement, le masque est une image en niveau de gris, dans lequel les pixels blancs sont ignorés, et les pixels noirs sont conservés en opacité selon leur intensité de noir. Il est donc nécessaire de transformer préalablement nos icônes afin qu’elles respectent cette spécification.

Cela se fait en deux étapes : créer un négatif de l’image d’origine (nous savons que les icônes contiennent uniquement des pixels blancs, dont nous voulons qu’il deviennent noirs), et y ajouter un background blanc.
Pour des raisons de commodités d’utilisation, nous avons créé une catégorie d’UIImage.

Créer un négatif de l'image et remplacer la transparence par un fond blanc

Comment colorer des icônes au runtime en Objective-C sur iOS

-(UIImage *) negativeImage

{

    UIGraphicsBeginImageContext(self.size);

    CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy);

    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeDifference);

    CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(),[UIColor whiteColor].CGColor);

    CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, self.size.width, self.size.height));

    UIImage *negativeImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return negativeImage;

}




- (UIImage *) imageWithWhiteBackground

{

    UIImage *negative = [self negativeImage];



    UIGraphicsBeginImageContext(negative.size);

    CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 1, 1, 1, 1);

    CGRect thumbnailRect = CGRectZero;

    thumbnailRect.origin = CGPointZero;

    thumbnailRect.size.width = negative.size.width;

    thumbnailRect.size.height = negative.size.height;



    CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0.0, negative.size.height);

    CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0);

    CGContextFillRect(UIGraphicsGetCurrentContext(), thumbnailRect);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), thumbnailRect, negative.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();



    return newImage;

}


Une fois que nous avons obtenu un masque au bon format, nous pouvons l’appliquer sur une image de couleur pleine (voire éventuellement une texture) grâce à CGImageCreateWithMask.

Appliquer une image de couleur pleine au masque

Comment colorer des icônes au runtime en Objective-C sur iOS

+ (UIImage *) image:(UIImage *)image withMaskColor:(UIColor *)color

{

    UIImage *formattedImage = [image imageWithWhiteBackground];



    CGRect rect = {0, 0, formattedImage.size.width, formattedImage.size.height};

    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);

    [color setFill];

    UIRectFill(rect);

    UIImage *tempColor = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();



    CGImageRef maskRef = [formattedImage CGImage];

    CGImageRef maskcg = CGImageMaskCreate(CGImageGetWidth(maskRef),

    CGImageGetHeight(maskRef),

    CGImageGetBitsPerComponent(maskRef),

    CGImageGetBitsPerPixel(maskRef),

    CGImageGetBytesPerRow(maskRef),

    CGImageGetDataProvider(maskRef), NULL, false);



    CGImageRef maskedcg = CGImageCreateWithMask([tempColor CGImage], maskcg);

    CGImageRelease(maskcg);

    UIImage *result = [UIImage imageWithCGImage:maskedcg];

    CGImageRelease(maskedcg);



    return result;

}


On imaginera facilement comment adapter ce code pour appliquer une texture, sous forme d'image, plutôt qu'un aplât de couleur.

Pour des raisons d’optimisation, il est utile de mettre en cache l’UIImage générée (sur le système de fichiers ou en mémoire) plutôt que d’appeler cette méthode à chaque affichage.

Liens utiles

- Documentation officielle Apple : Bitmap Images and Image Masks dans la documentation iOS
 



Entrez votre adresse email