Как преобразовать цвета из одного цветового пространства в другое?

Есть ли способ Cocoa Touch для преобразования цветов из одного цветового пространства в другое?

В конце этого кода:

UIColor *grey = [UIColor colorWithWhite: 0.5 alpha: 1.0];
CGColorRef greyRef = [grey CGColor];
int x = CGColorGetNumberOfComponents(greyRef);

...x это 2.

Причина, по которой мне это нужно, в том, что я пытаюсь скопировать цвета в список цветовых компонентов для CGGradientCreateWithColorComponents, которому нужны все цвета в одном цветовом пространстве. Проблема в том, что серый цвет находится в цветовом пространстве градаций серого, а не в RGB. (Имя ускользает от меня на данный момент, но это не важно.)

CGGradientRef createGradient(NSInteger inCount, NSArray* inColors, CGFloat* inLocations) {
 CGColorSpaceRef theColorspace = CGColorSpaceCreateDeviceRGB( );
 size_t numberOfComponents = 4;
 NSInteger colorSize = numberOfComponents * sizeof( CGFloat );
 CGFloat *theComponents = malloc( inCount * colorSize );
 CGFloat *temp = theComponents;
 for ( NSInteger i = 0; i < inCount; i++ ) {
  UIColor *theColor = [inColors objectAtIndex: i];
  CGColorRef cgColor = [theColor CGColor];
  const CGFloat *components = CGColorGetComponents( cgColor );
  memmove( temp, components, colorSize );
  temp += numberOfComponents;
 }
 CGGradientRef gradient = CGGradientCreateWithColorComponents( theColorspace,
                                               theComponents, inLocations, inCount );
 CGColorSpaceRelease( theColorspace );
 free( theComponents );
 return gradient;
}

Я знаю, что могу искать цвета в цветовом пространстве серого и преобразовывать их. Но это решает только один случай. Глядя на этот вопрос, я думаю, что HSB также обрабатывается. Но я хотел бы написать здесь некоторый код и больше никогда не думать об этом, что означает поддержку не только цветовых пространств, которые существуют сейчас, но и всего, что Apple могла бы добавить в будущем. Мне не повезло?

4 ответа

Решение

Я не уверен, как автоматически конвертировать их, но для определения различных цветовых пространств вы можете получить CGColorSpaceModel из цвета CGColorSpaceRef:

UIColor* color = some color;
CGColorSpaceRef colorSpace = CGColorGetColorSpace([color CGColor]);
CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);

Тогда вы можете сравнить colorSpaceModel с константами, определенными в CoreGraphics/CGColorSpace.h, UIColor-х getRed:green:blue:alpha работает на kCGColorSpaceModelRGB, в то время как getWhite:alpha работает на kCGColorSpaceModelMonochrome,

Обратите внимание, что UIColor который был создан с colorWithHue:saturation:brightness:alpha: на самом деле будет в цветовом пространстве RGB.

В Swift 3 мы можем напрямую использовать

 let colorSpace = uiColor.cgColor.colorSpace
 let csModel = colorSpace.model

чтобы получить модель цветового пространства и цветового пространства от UIColor,

Используйте метод CGColor:

func converted(to _: CGColorSpace, intent: CGColorRenderingIntent, options: CFDictionary?) -> CGColor?

Мне это нужно, чтобы убедиться, что все CGColorбыли в CGColorSpaceCreateDeviceRGB цветовое пространство.

cgColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil)

https://developer.apple.com/documentation/coregraphics/cgcolor/1455493-converted

Для цветов, созданных с использованием [UIColor colorWithRed:green:blue:alpha:], ты можешь использовать UIColor getRed:green:blue:alpha:, описанный в Ссылке класса UIColor. Это часть iOS 5 и более поздних версий.

Если цвет был создан с colorWithWhite:alpha: Вы можете использовать getWhite:alpha: вместо этого, описано в UIColor Class Reference.

Чтобы определить, какое цветовое пространство используется, вы можете использовать CGColorGetColorSpace([color colorSpace]), Но, вероятно, проще просто проверить результат вызова метода, а затем переключиться на следующую попытку. Что-то вроде этого:

if ([color getRed:&red green:&green blue:&blue alpha:&alpha]) {
    // red, green and blue are all valid
} else if if ([color getWhite:&white alpha:&alpha]) {
    red = white; green = white; blue = white;
} else {
    // can't get it
}

Я не знаю, как обращаться с цветовыми константами, такими как [UIColor lightGrayColor]кроме рисования их во временное растровое изображение и обнаружения их. Некоторые из этих цветовых констант на самом деле являются текстурами; Ваш лучший выбор, вероятно, избегать их.

Если вы планируете делать это много, это подходящее использование категории:

@interface UIColor(sf)
- (BOOL)sfGetRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;
@end

@implementation UIColor(sf)
- (BOOL)sfGetRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha {
    if ([self getRed:red green:green blue:blue alpha:alpha]) return YES;
    CGFloat white;
    if ([self getWhite:&white alpha:alpha]) {
        if (red) *red = white;
        if (green) *green = white;
        if (blue) *blue = white;
        return YES;
    }
    return NO;
}
@end

Другой способ преобразовать их - нарисовать их в контекстах и ​​позволить основной графике выполнить преобразование за вас. Смотрите мой ответ на этот вопрос:

Получить значение RGB из пресетов UIColor

Другие вопросы по тегам