¿Cómo crear dinámicamente una imagen UII de color 1x1 en el iPhone?


120

Me gustaría crear un UIImage 1x1 dinámicamente basado en un UIColor.

Sospecho que esto se puede hacer rápidamente con Quartz2d, ​​y estoy estudiando detenidamente la documentación tratando de comprender los fundamentos. Sin embargo, parece que hay muchas trampas potenciales: no identificar correctamente la cantidad de bits y bytes por cosas, no especificar las banderas correctas, no liberar datos no utilizados, etc.

¿Cómo se puede hacer esto de forma segura con Quartz 2d (u otra forma más sencilla)?

Respuestas:


331

Puedes usar CGContextSetFillColorWithColory CGContextFillRectpara esto:

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

C objetivo

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

19
Bonito :-) Recomendaría poner este método en una categoría como método de clase, luego se puede agregar a un proyecto de manera simple e invocar usando una línea como [UIImage imageWithColor: [UIColor redColor]].

7
En caso de que esté creando estas imágenes en un bucle o usando un tamaño mayor, una optimización sería usar un lienzo opaco solo si el color tiene alfa. Así:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique

proporcione la versión rápida
fnc12

¿Hay alguna manera de hacer que el rápido sea un inicializador personalizado?
Antzi

1
¿Por qué está UIGraphicsGetCurrentContext()regresando nil? Edit : lo tengo, estaba pasando 0por el rect's width.
Iulian Onofrei

9

Aquí hay otra opción basada en el código de Matt Stephen. Crea una imagen de color sólido de tamaño variable de modo que pueda reutilizarla o cambiar su tamaño (por ejemplo, usarla como fondo).

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

Ponlo en una categoría UIImage y cambia el prefijo.


6

Usé la respuesta de Matt Steven muchas veces, así que hice una categoría para ella:

@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

5

Usando el último UIGraphicsImageRenderer de Apple, el código es bastante pequeño:

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

0

Para mí, un inicio de conveniencia se siente más ordenado en 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)
    }

}

-7

Ok, esto no será exactamente lo que quieres, pero este código dibujará una línea. Puedes adaptarlo para hacer un punto. O al menos obtén un poco de información.

Hacer la imagen 1x1 parece un poco extraño. Los trazos recorren la línea, por lo que un trazo de 1.0 a 0.5 debería funcionar. Solo juega.

- (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();
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.