Несколько дней я боролся за проект по раскрашиванию UIImage. Идея состоит в том, что приложение загрузит набор изображений, которые мне придется раскрасить значениями, полученными из веб-службы. Какие-то темы, если хотите.
Дизайнер, с которым я работаю, предоставил мне фоновое изображение для всех своих значений Photoshop.
Первая проблема заключается в том, что Photoshop использует HSL, а iOS использует HSB. Итак, первой задачей было перевести значения из Photoshop.
Photoshop HSL: -28 (диапазон -180 => +180), 100 (диапазон -100 => +100), 25 (диапазон -100 => +100).
К счастью, я нашел в Интернете код, вот он.
//adapted from https://gist.github.com/peteroupc/4085710
- (void)convertLightnessToBrightness:(CGFloat)lightness withSaturation:(CGFloat)saturation completion:(void (^)(CGFloat, CGFloat))completion
{
if (!completion)
return; //What's the point of calling this method without a completion block!
CGFloat brightness = 0.0f;
CGFloat saturationOut = 0.0f;
if (lightness > 0.0f)
{
CGFloat lumScale = (1.0f - MAX((lightness - 0.5f), 0.0f) * 2.0f);
lumScale = ((lumScale == 0) ? 0 : (1.0f / lumScale));
CGFloat lumStart = MAX(0.0f, (lumScale - 0.5f));
CGFloat lumDiv = (lumScale - lumStart);
lumDiv = (lumStart + (saturation * lumDiv));
saturationOut = ((lumDiv == 0) ? 0.0f : (saturation / lumDiv));
brightness = (lightness + (1.0f - lightness) * saturation);
}
NSLog(@"saturation: %0.2f - brightness: %0.2f", saturationOut, brightness);
completion(saturationOut, brightness);
}
Используя онлайн-конвертер, я убедился, что этот метод возвращает хорошие значения.
Мне нужно было изменить диапазоны (H: 0-> 360, S: 0-> 100, L: 0-> 100)
Итак, HSL 152, 100, 62 дает HSB 152, 76, 100. И метод возвращает 75 для насыщенности и 100 для яркости, так что все в порядке.
Затем мне нужно было применить эти значения к изображению, поэтому вот код, который нужно изменить ...
ОТТЕНОК:
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0f * M_PI)
- (void)colorize:(UIImage *)input hue:(CGFloat)hueDegrees completion:(void(^)(UIImage *outputHue))completion
{
if (!completion)
return; //What's the point of calling this method without a completion block!
CGFloat hue = DEGREES_TO_RADIANS(hueDegrees);
NSLog(@"degress: %0.2f | radian: %0.2f", hueDegrees, hue);
CIImage *inputImage = [CIImage imageWithCGImage:input.CGImage];
//---
CIFilter *hueFilter = [CIFilter filterWithName:@"CIHueAdjust" keysAndValues:kCIInputImageKey, inputImage, nil];
[hueFilter setDefaults];
[hueFilter setValue:[NSNumber numberWithFloat:hue] forKey:kCIInputAngleKey];
//---
CIImage *outputImage = [hueFilter outputImage];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *outputUIImage = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);
completion(outputUIImage);
}
НАСЫЩЕНИЕ:
- (void)colorize:(UIImage *)input saturation:(CGFloat)saturation completion:(void(^)(UIImage *outputSaturation))completion
{
if (!completion)
return; //What's the point of calling this method without a completion block!
NSLog(@"saturation: %0.2f", saturation);
CIImage *inputImage = [CIImage imageWithCGImage:input.CGImage];
//---
CIFilter *saturationFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues:kCIInputImageKey, inputImage, nil];
[saturationFilter setDefaults];
[saturationFilter setValue:[NSNumber numberWithFloat:saturation] forKey:@"inputSaturation"];
//---
CIImage *outputImage = [saturationFilter outputImage];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *outputUIImage = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);
completion(outputUIImage);
}
Яркость:
- (void)colorize:(UIImage *)input brightness:(CGFloat)brightness completion:(void(^)(UIImage *outputBrightness))completion
{
if (!completion)
return; //What's the point of calling this method without a completion block!
NSLog(@"brightness: %0.2f", brightness);
CIImage *inputImage = [CIImage imageWithCGImage:input.CGImage];
//---
CIFilter *brightnessFilter = [CIFilter filterWithName:@"CIColorControls" keysAndValues:kCIInputImageKey, inputImage, nil];
[brightnessFilter setDefaults];
[brightnessFilter setValue:[NSNumber numberWithFloat:brightness] forKey:@"inputBrightness"];
//---
CIImage *outputImage = [brightnessFilter outputImage];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *outputUIImage = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);
completion(outputUIImage);
}
И все вместе:
CGFloat hue = -28.0f; //152 in 360° range (180 - 28 = 152)
CGFloat saturation = 1.0f; //((100 + 100.0f) / 200.0f)
CGFloat lightness = 0.625f; //((25 + 100.0f) / 200.0f)
[self convertLightnessToBrightness:ligthness withSaturation:saturation completion:^(CGFloat saturationOut, CGFloat brightness) {
//saturarationOut = 0.75f and brigthness = 1.0f
[self colorize:input hue:hue completion:^(UIImage *outputHue) {
[self colorize:outputHue saturation:saturationOut completion:^(UIImage *outputSaturation) {
[self colorize:outputSaturation brightness:brightness completion:completion];
}];
}];
}];
Последний блок завершения просто применяет выходное изображение к просмотру изображения. Вот результаты:
Базовое изображение
Раскрашивание (только оттенок)
Colorize (оттенок и насыщенность)
Раскрашивание (оттенок, насыщенность и яркость)
Ожидаемый результат
Как видите, итоговое изображение полностью белое (яркость 100%).
Я полностью потерялся здесь, я пробовал много комбинаций (применяя H, S и B в каждом порядке), я пробовал другие библиотеки, такие как iOS-Image-Filters, но безуспешно. Я также прочитал здесь много вопросов о переполнении стека.
Ссылки:
- Справочник по базовому фильтру изображений
- Настройка основного фильтра изображения CIHueAdjust
- Как программно изменить оттенок UIImage?
- iOS: значения для CIFilter (Hue) из Photoshop
Как кому-нибудь удалось применить значение HSL / HSB к UIImages?