Come creare dinamicamente un UIImage 1x1 colorato su iPhone?


120

Vorrei creare un UIImage 1x1 dinamicamente basato su un UIColor.

Sospetto che questo possa essere fatto rapidamente con Quartz2d, ​​e sto esaminando attentamente la documentazione cercando di ottenere una comprensione dei fondamenti. Tuttavia, sembra che ci siano molte potenziali insidie: non identificare correttamente il numero di bit e byte per cose, non specificare i flag giusti, non rilasciare dati inutilizzati, ecc.

Come può essere fatto in sicurezza con Quartz 2d (o un altro modo più semplice)?

Risposte:


331

Puoi usare CGContextSetFillColorWithColore CGContextFillRectper questo:

veloce

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

Objective-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;
}

19
Bello :-) Consiglierei di mettere questo metodo in una categoria come metodo di classe, quindi può essere aggiunto in un progetto semplicemente e invocato usando una riga come [UIImage imageWithColor: [UIColor redColor]].

7
Nel caso in cui stai creando queste immagini in un ciclo o utilizzando una dimensione più grande, un'ottimizzazione sarebbe quella di utilizzare una tela opaca solo se il colore ha alfa. In questo modo:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique

si prega di fornire la versione rapida
fnc12

C'è un modo per rendere quello rapido un inizializzatore personalizzato invece?
Antzi

1
Perché sta UIGraphicsGetCurrentContext()tornando nil? Edit : ho capito, stavo passando 0per rect's width.
Iulian Onofrei

9

Ecco un'altra opzione basata sul codice di Matt Stephen. Crea un'immagine a tinta unita ridimensionabile in modo che tu possa riutilizzarla o cambiarne le dimensioni (ad esempio usarla per uno sfondo).

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

Mettilo in una categoria UIImage e cambia il prefisso.


6

Ho usato la risposta di Matt Steven molte volte, quindi ho creato una categoria per questo:

@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 l'ultimo UIGraphicsImageRenderer di Apple il codice è piuttosto piccolo:

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

Per me, un inizio di comodità sembra più ordinato in 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, questo non sarà esattamente quello che vuoi, ma questo codice disegnerà una linea. Puoi adattarlo per fare un punto. O almeno ottenere un po 'di informazioni da esso.

Rendere l'immagine 1x1 sembra un po 'strano. I tratti percorrono la linea, quindi un tratto di larghezza 1.0 a 0.5 dovrebbe funzionare. Gioca e basta.

- (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();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.