Как динамически создать цветной UIImage 1x1 на iPhone?

120

Я хотел бы динамически создать 1x1 UIImage на основе UIColor.

Я подозреваю, что это можно быстро сделать с помощью Quartz2d, ​​и я изучаю документацию, пытаясь понять основы. Однако похоже, что существует множество потенциальных ловушек: неправильное определение количества бит и байтов для каждого объекта, неправильное указание флагов, невыполнение неиспользуемых данных и т. Д.

Как это можно безопасно сделать с помощью Quartz 2d (или другим более простым способом)?

Ян Террелл
источник

Ответы:

331

Для этого можно использовать CGContextSetFillColorWithColorи CGContextFillRect:

стриж

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
Хороший :-) Я бы порекомендовал поместить этот метод в категорию как метод класса, тогда его можно будет просто добавить в проект и вызывать с помощью строки вроде [UIImage imageWithColor: [UIColor redColor]].
7
Если вы создаете эти изображения в цикле или используете больший размер, оптимизация будет заключаться в использовании непрозрачного холста, только если у цвета есть альфа. Как это:const CGFloat alpha = CGColorGetAlpha(color.CGColor); const BOOL opaque = alpha == 1; UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
hpique
пожалуйста, предоставьте быструю версию
fnc12
Есть ли способ вместо этого сделать быстрый инициализатором?
Antzi
1
Почему UIGraphicsGetCurrentContext()возвращается nil? Edit : Я получил его, я проходил 0на rect«с width.
Юлиан Онофрей
9

Вот еще один вариант, основанный на коде Мэтта Стивена. Он создает однотонное изображение с изменяемым размером, так что вы можете повторно использовать его или изменить его размер (например, использовать его для фона).

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

Поместите его в категорию UIImage и измените префикс.

Бен Лахман
источник
6

Я много раз использовал ответ Мэтта Стивена, поэтому сделал для него категорию:

@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
источник
5

Используя последний UIGraphicsImageRenderer от Apple, код довольно небольшой:

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
источник
0

Мне кажется, что в Swift удобнее использовать init.

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

Хорошо, это будет не совсем то, что вы хотите, но этот код проведет линию. Вы можете адаптировать его, чтобы подчеркнуть свою точку зрения. Или, по крайней мере, получить от него немного информации.

Создание изображения 1x1 кажется немного странным. Обводки идут по линии, поэтому подойдет обводка шириной 1,0 и 0,5. Просто поиграйте.

- (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();
}
Кори Флойд
источник