Jak dynamicznie stworzyć kolorowy obraz 1x1 UIImage na iPhonie?

120

Chciałbym dynamicznie stworzyć 1x1 UIImage w oparciu o UIColor.

Podejrzewam, że można to szybko zrobić za pomocą Quartz2d i wsuwam się w dokumentację, próbując zrozumieć podstawy. Wygląda jednak na to, że istnieje wiele potencjalnych pułapek: niepoprawna identyfikacja liczby bitów i bajtów na rzecz, niewłaściwe określenie odpowiednich flag, nieudostępnianie nieużywanych danych itp.

Jak można to bezpiecznie zrobić za pomocą Quartz 2d (lub w inny prostszy sposób)?

Ian Terrell
źródło

Odpowiedzi:

331

Możesz użyć CGContextSetFillColorWithColori CGContextFillRectdo tego:

Szybki

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

Cel 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
źródło
19
Fajny :-) Poleciłbym umieścić tę metodę w kategorii jako metodę klasową, a następnie można ją w prosty sposób dodać do projektu i wywołać za pomocą linii takiej jak [UIImage imageWithColor: [UIColor redColor]].
7
Jeśli tworzysz te obrazy w pętli lub używasz większego rozmiaru, optymalizacją byłoby użycie nieprzezroczystego płótna tylko wtedy, gdy kolor ma alfa. W ten sposób:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique
proszę dostarczyć wersję szybką
fnc12
Czy istnieje sposób, aby zamiast tego szybki był niestandardowym inicjatorem?
Antzi
1
Dlaczego UIGraphicsGetCurrentContext()wraca nil? Edycja : mam to, przechodziłem 0przez rects width.
Iulian Onofrei
9

Oto inna opcja oparta na kodzie Matta Stephena. Tworzy skalowalny obraz w jednolitym kolorze, tak że możesz go użyć ponownie lub zmienić jego rozmiar (np. Użyj go jako tła).

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

Umieść go w kategorii UIImage i zmień prefiks.

Ben Lachman
źródło
6

Wiele razy korzystałem z odpowiedzi Matta Stevena, więc stworzyłem dla niej kategorię:

@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
źródło
5

Korzystając z najnowszego UIGraphicsImageRenderer firmy Apple, kod jest dość mały:

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
źródło
0

Dla mnie wygoda, którą init wydaje się schludniejszy w 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
źródło
-7

Ok, to nie będzie dokładnie to, czego chcesz, ale ten kod narysuje linię. Możesz to dostosować, aby uzyskać jakiś punkt. Albo przynajmniej zdobądź z niego trochę informacji.

Tworzenie obrazu 1x1 wydaje się trochę dziwne. Pociągnięcia przesuwają się po linii, więc pociągnięcie o szerokości 1,0 i 0,5 powinno działać. Po prostu pobaw się.

- (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
źródło