Como criar uma UIImage colorida 1x1 no iPhone dinamicamente?

120

Gostaria de criar uma UIImage 1x1 dinamicamente com base em um UIColor.

Suspeito que isso possa ser feito rapidamente com o Quartz2d, ​​e estou analisando a documentação tentando entender os fundamentos. No entanto, parece que existem muitas armadilhas em potencial: não identificar o número de bits e bytes por itens corretamente, não especificar os sinalizadores corretos, não liberar dados não utilizados etc.

Como isso pode ser feito com segurança com o Quartz 2d (ou outra maneira mais simples)?

Ian Terrell
fonte

Respostas:

331

Você pode usar CGContextSetFillColorWithColore CGContextFillRectpara isso:

Rápido

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!
    }
}

Objetivo-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
fonte
19
Bom :-) Eu recomendaria colocar esse método em uma categoria como um método de classe, então ele pode ser adicionado a um projeto de forma simples e invocado usando uma linha como [UIImage imageWithColor: [UIColor redColor]].
7
Caso você esteja criando essas imagens em loop ou usando um tamanho maior, uma otimização seria usar uma tela opaca somente se a cor tiver alfa. Assim:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique
forneça a versão rápida
fnc12
Existe uma maneira de tornar o rápido um inicializador personalizado?
Antzi
1
Por que está UIGraphicsGetCurrentContext()retornando nil? Edit : Eu entendi, eu estava passando 0para o rect's width.
Iulian Onofrei 27/08/2015
9

Aqui está outra opção baseada no código de Matt Stephen. Ele cria uma imagem em cores sólidas redimensionável, de forma que você possa reutilizá-la ou alterar seu tamanho (por exemplo, usá-la como pano de fundo).

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

Coloque-o em uma categoria UIImage e altere o prefixo.

Ben Lachman
fonte
6

Eu usei a resposta de Matt Steven muitas vezes, então fiz uma categoria para ela:

@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
fonte
5

Usando o UIGraphicsImageRenderer mais recente da Apple, o código é bem pequeno:

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
fonte
0

Para mim, um iniciante de conveniência se sente melhor em 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
fonte
-7

Ok, isso não será exatamente o que você deseja, mas esse código traçará uma linha. Você pode adaptá-lo para fazer uma observação. Ou pelo menos obtenha algumas informações.

Tornar a imagem 1x1 parece um pouco estranha. Traçados percorrem a linha, portanto, um traçado de largura 1,0 a 0,5 deve funcionar. Apenas brinque.

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