Wie erstelle ich dynamisch ein farbiges 1x1 UIImage auf dem iPhone?

120

Ich möchte ein 1x1 UIImage dynamisch basierend auf einer UIColor erstellen.

Ich vermute, dass dies mit Quartz2d schnell erledigt werden kann, und ich stöbere in der Dokumentation, um die Grundlagen zu verstehen. Es sieht jedoch so aus, als gäbe es viele potenzielle Fallstricke: die Anzahl der Bits und Bytes pro Sache nicht richtig zu identifizieren, die richtigen Flags nicht anzugeben, nicht verwendete Daten nicht freizugeben usw.

Wie kann dies sicher mit Quartz 2d (oder einem anderen einfacheren Weg) gemacht werden?

Ian Terrell
quelle

Antworten:

331

Sie können CGContextSetFillColorWithColorund CGContextFillRectdafür verwenden:

Schnell

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

Ziel 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
quelle
19
Schön :-) Ich würde empfehlen, diese Methode als Klassenmethode in eine Kategorie einzufügen. Dann kann sie einfach in ein Projekt eingefügt und mit einer Zeile wie aufgerufen werden [UIImage imageWithColor: [UIColor redColor]].
7
Wenn Sie diese Bilder in einer Schleife erstellen oder eine größere Größe verwenden, besteht eine Optimierung darin, eine undurchsichtige Leinwand nur dann zu verwenden, wenn die Farbe Alpha enthält. So:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique
Bitte geben Sie eine schnelle Version an
fnc12
Gibt es eine Möglichkeit, den schnellen stattdessen zu einem benutzerdefinierten Initialisierer zu machen?
Antzi
1
Warum UIGraphicsGetCurrentContext()kehrt ich zurück nil? Bearbeiten : Ich habe es, ich war vorbei 0für die rect‚s width.
Iulian Onofrei
9

Hier ist eine weitere Option, die auf dem Code von Matt Stephen basiert. Es wird ein anpassbares Vollfarbbild erstellt, sodass Sie es wiederverwenden oder seine Größe ändern können (z. B. als Hintergrund verwenden).

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

Fügen Sie es in eine UIImage-Kategorie ein und ändern Sie das Präfix.

Ben Lachman
quelle
6

Ich habe die Antwort von Matt Steven viele Male verwendet, also habe ich eine Kategorie dafür erstellt:

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

Mit Apples neuestem UIGraphicsImageRenderer ist der Code ziemlich klein:

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

Für mich fühlt sich ein Convenience-Init in Swift ordentlicher an.

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
quelle
-7

Ok, das wird nicht genau das sein, was Sie wollen, aber dieser Code wird eine Linie ziehen. Sie können es anpassen, um einen Punkt zu machen. Oder zumindest ein paar Infos davon.

Das Bild 1x1 zu machen scheint etwas seltsam. Striche fahren auf der Linie, daher sollte ein Strich mit einer Breite von 1,0 bei 0,5 funktionieren. Spielen Sie einfach herum.

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