Comment créer dynamiquement une UIImage 1x1 colorée sur l'iPhone?

120

Je voudrais créer une UIImage 1x1 dynamiquement basée sur un UIColor.

Je soupçonne que cela peut être fait rapidement avec Quartz2d, ​​et je me penche sur la documentation pour essayer de comprendre les principes de base. Cependant, il semble qu'il existe de nombreux pièges potentiels: ne pas identifier correctement le nombre de bits et d'octets par chose, ne pas spécifier les bons indicateurs, ne pas libérer les données inutilisées, etc.

Comment cela peut-il être fait en toute sécurité avec Quartz 2d (ou un autre moyen plus simple)?

Ian Terrell
la source

Réponses:

331

Vous pouvez utiliser CGContextSetFillColorWithColoret CGContextFillRectpour cela:

Rapide

extension UIImage {
    class func image(with color: UIColor) -> UIImage {
        let rect = CGRectMake(0.0, 0.0, 1.0, 1.0)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()

        CGContextSetFillColorWithColor(context, color.CGColor)
        CGContextFillRect(context, rect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return image
    }
}

Swift3

extension UIImage {
    class func image(with color: UIColor) -> UIImage {
        let rect = CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 1, height: 1))
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()!

        context.setFillColor(color.cgColor)
        context.fill(rect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return image!
    }
}

Objectif c

+ (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

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

    return image;
}
Matt Stevens
la source
19
Belle :-) Je recommanderais de mettre cette méthode dans une catégorie en tant que méthode de classe, puis elle peut être ajoutée simplement dans un projet et appelée en utilisant une ligne comme [UIImage imageWithColor: [UIColor redColor]].
7
Si vous créez ces images en boucle ou utilisez une taille plus grande, une optimisation consisterait à utiliser un canevas opaque uniquement si la couleur a un alpha. Comme ça:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique
veuillez fournir la version rapide
fnc12
Existe-t-il un moyen de faire du swift un initialiseur personnalisé à la place?
Antzi
1
Pourquoi UIGraphicsGetCurrentContext()returnin nil? Edit : je l'ai eu, je passais 0pour le rect's width.
Iulian Onofrei
9

Voici une autre option basée sur le code de Matt Stephen. Il crée une image de couleur unie redimensionnable de telle sorte que vous puissiez la réutiliser ou modifier sa taille (par exemple, l'utiliser pour un arrière-plan).

+ (UIImage *)prefix_resizeableImageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 3.0f, 3.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

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

    image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(1, 1, 1, 1)];

    return image;
}

Mettez-le dans une catégorie UIImage et changez le préfixe.

Ben Lachman
la source
6

J'ai utilisé la réponse de Matt Steven à plusieurs reprises, alors j'ai créé une catégorie pour cela:

@interface UIImage (mxcl)
+ (UIImage *)squareImageWithColor:(UIColor *)color dimension:(int)dimension;
@end

@implementation UIImage (mxcl)
+ (UIImage *)squareImageWithColor:(UIColor *)color dimension:(int)dimension {
    CGRect rect = CGRectMake(0, 0, dimension, dimension);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

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

    return image;
}
@end
mxcl
la source
5

En utilisant le dernier UIGraphicsImageRenderer d'Apple, le code est assez petit:

import UIKit

extension UIImage {
    static func from(color: UIColor) -> UIImage {
        let size = CGSize(width: 1, height: 1)
        return UIGraphicsImageRenderer(size: size).image(actions: { (context) in
            context.cgContext.setFillColor(color.cgColor)
            context.fill(.init(origin: .zero, size: size))
        })
    }
}
bitwit
la source
0

Pour moi, un init pratique me semble plus soigné dans Swift.

extension UIImage {

    convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {

        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContext(rect.size)
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }

        context.setFillColor(color.cgColor)
        context.fill(rect)

        guard let image = context.makeImage() else {
            return nil
        }
        UIGraphicsEndImageContext()

        self.init(cgImage: image)
    }

}
Mark Bridges
la source
-7

Ok, ce ne sera pas exactement ce que vous voulez, mais ce code dessinera une ligne. Vous pouvez l'adapter pour faire valoir un point. Ou du moins en tirer quelques informations.

Faire l'image 1x1 semble un peu bizarre. Les traits chevauchent la ligne, donc un trait de largeur 1,0 à 0,5 devrait fonctionner. Jouez simplement.

- (void)drawLine{

UIGraphicsBeginImageContext(CGSizeMake(320,300));

CGContextRef ctx = UIGraphicsGetCurrentContext();

float x = 0;
float xEnd = 320;
float y = 300;

CGContextClearRect(ctx, CGRectMake(5, 45, 320, 300));

CGContextSetGrayStrokeColor(ctx, 1.0, 1.0);

CGContextSetLineWidth(ctx, 1);
CGPoint line[2] = { CGPointMake(x,y), CGPointMake(xEnd, y) };

CGContextStrokeLineSegments(ctx, line, 2);

UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}
Corey Floyd
la source