Как бы я тонировал изображение программно на iOS? - PullRequest
86 голосов
/ 13 июля 2009

Я хотел бы тонировать изображение с помощью цветовой ссылки. Результаты должны выглядеть как режим смешивания Multiply в Photoshop, где белые будут заменены на оттенок :

alt text

Я буду постоянно менять значение цвета.

Продолжение: Я бы поместил код для этого в метод drawRect: метод моего ImageView, верно?

Как всегда, фрагмент кода очень помог бы в моем понимании, в отличие от ссылки.

Обновление: Подкласс UIImageView с предложенным кодом Ramin .

Я поместил это в viewDidLoad: моего контроллера представления:

[self.lena setImage:[UIImage imageNamed:kImageName]];
[self.lena setOverlayColor:[UIColor blueColor]];
[super viewDidLoad];

Я вижу изображение, но оно не тонируется. Я также попытался загрузить другие изображения, установить изображение в IB и вызвать setNeedsDisplay: в моем контроллере представления.

Обновление : drawRect: не вызывается.

Окончательное обновление: Я нашел старый проект, у которого был настроен imageView, чтобы я мог протестировать код Рамина, и он работает как чудо!

Окончательное, окончательное обновление:

Для тех из вас, кто только изучает Core Graphics, вот самая простая вещь, которая могла бы работать.

В вашем подклассе UIView:

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColor(context, CGColorGetComponents([UIColor colorWithRed:0.5 green:0.5 blue:0 alpha:1].CGColor)); // don't make color too saturated

    CGContextFillRect(context, rect); // draw base

    [[UIImage imageNamed:@"someImage.png"] drawInRect: rect blendMode:kCGBlendModeOverlay alpha:1.0]; // draw image
}

Ответы [ 13 ]

76 голосов
/ 02 октября 2013

В iOS7 они ввели свойство tintColor в UIImageView и renderMode в UIImage. Чтобы подкрасить UIImage на iOS7, все, что вам нужно сделать, это:

UIImageView* imageView = …
UIImage* originalImage = …
UIImage* imageForRendering = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
imageView.image = imageForRendering;
imageView.tintColor = [UIColor redColor]; // or any color you want to tint it with
44 голосов
/ 13 июля 2009

Сначала вы захотите создать подкласс UIImageView и переопределить метод drawRect. Вашему классу необходимо свойство UIColor (назовем его overlayColor) для хранения смешанного цвета и пользовательского установщика, который вызывает перерисовку при изменении цвета. Примерно так:

- (void) setOverlayColor:(UIColor *)newColor {
   if (overlayColor)
     [overlayColor release];

   overlayColor = [newColor retain];
   [self setNeedsDisplay]; // fires off drawRect each time color changes
}

В методе drawRect вы сначала захотите нарисовать изображение, а затем наложить его на прямоугольник, заполненный нужным цветом, с соответствующим режимом наложения, что-то вроде этого:

- (void) drawRect:(CGRect)area
{
  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextSaveGState(context);

  // Draw picture first
  //
  CGContextDrawImage(context, self.frame, self.image.CGImage);

  // Blend mode could be any of CGBlendMode values. Now draw filled rectangle
  // over top of image.
  //
  CGContextSetBlendMode (context, kCGBlendModeMultiply);
  CGContextSetFillColor(context, CGColorGetComponents(self.overlayColor.CGColor));      
  CGContextFillRect (context, self.bounds);
  CGContextRestoreGState(context);
}

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

Чтобы использовать его, создайте экземпляр объекта, затем установите для свойства image (унаследованного от UIImageView) изображение, а для overlayColor - значение UIColor (уровни смешивания можно настроить, изменив альфа-значение цвета ты сдаешь).

26 голосов
/ 27 мая 2010

Просто быстрое разъяснение (после некоторых исследований по этой теме). В документе Apple здесь четко указано, что:

Класс UIImageView оптимизирован для отображения своих изображений на дисплее. UIImageView не вызывает метод drawRect: своих подклассов. Если ваш подкласс должен включать пользовательский код для рисования, вы должны вместо этого создать класс UIView.

, поэтому даже не тратьте время на попытки переопределить этот метод в подклассе UIImageView. Вместо этого начните с UIView.

25 голосов
/ 02 декабря 2011

Я хотел подкрасить изображение альфой и создал следующий класс. Пожалуйста, дайте мне знать, если вы обнаружите какие-либо проблемы с ним.

Я назвал свой класс CSTintedImageView, и он наследуется от UIView, поскольку UIImageView не вызывает метод drawRect:, как упоминалось в предыдущих ответах. Я установил назначенный инициализатор, подобный тому, который найден в классе UIImageView.

Использование:

CSTintedImageView * imageView = [[CSTintedImageView alloc] initWithImage:[UIImage imageNamed:@"image"]];
imageView.tintColor = [UIColor redColor];

CSTintedImageView.h

@interface CSTintedImageView : UIView

@property (strong, nonatomic) UIImage * image;
@property (strong, nonatomic) UIColor * tintColor;

- (id)initWithImage:(UIImage *)image;

@end

CSTintedImageView.m

#import "CSTintedImageView.h"

@implementation CSTintedImageView

@synthesize image=_image;
@synthesize tintColor=_tintColor;

- (id)initWithImage:(UIImage *)image
{
    self = [super initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];

    if(self)
    {
        self.image = image;

        //set the view to opaque
        self.opaque = NO;
    }

    return self;
}

- (void)setTintColor:(UIColor *)color
{
    _tintColor = color;

    //update every time the tint color is set
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();    

    //resolve CG/iOS coordinate mismatch
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -rect.size.height);

    //set the clipping area to the image
    CGContextClipToMask(context, rect, _image.CGImage);

    //set the fill color
    CGContextSetFillColor(context, CGColorGetComponents(_tintColor.CGColor));
    CGContextFillRect(context, rect);    

    //blend mode overlay
    CGContextSetBlendMode(context, kCGBlendModeOverlay);

    //draw the image
    CGContextDrawImage(context, rect, _image.CGImage);    
}

@end
5 голосов
/ 23 октября 2009

Это может быть очень полезно: PhotoshopFramework - это мощная библиотека для работы с изображениями в Objective-C. Это было разработано, чтобы принести те же функции, которые знакомы пользователям Adobe Photoshop. Примеры: установка цветов с использованием RGB 0-255, применение фильтров смешивания, преобразования ...

С открытым исходным кодом, вот ссылка на проект: https://sourceforge.net/projects/photoshopframew/

4 голосов
/ 07 февраля 2015
UIImage * image = mySourceImage;
UIColor * color = [UIColor yellowColor];  
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:1];
UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, image.size.width, image.size.height)];
[color setFill];
[path fillWithBlendMode:kCGBlendModeMultiply alpha:1]; //look up blending modes for your needs
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//use newImage for something
3 голосов
/ 14 сентября 2013

Вот еще один способ реализовать тонирование изображения, особенно если вы уже используете QuartzCore для чего-то другого. Это был мой ответ на аналогичный вопрос .

Импорт QuartzCore:

#import <QuartzCore/QuartzCore.h>

Создайте прозрачный CALayer и добавьте его в качестве подслоя для изображения, которое вы хотите подкрасить:

CALayer *sublayer = [CALayer layer];
[sublayer setBackgroundColor:[UIColor whiteColor].CGColor];
[sublayer setOpacity:0.3];
[sublayer setFrame:toBeTintedImage.frame];
[toBeTintedImage.layer addSublayer:sublayer];

Добавьте QuartzCore в список Framework ваших проектов (если его там еще нет), в противном случае вы получите такие ошибки компилятора, как этот:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"
2 голосов
/ 25 ноября 2010

Для тех из вас, кто пытается создать подкласс класса UIImageView и застрял в «drawRect: не вызывается», обратите внимание, что вместо этого вы должны создать подкласс класса UIView, поскольку для классов UIImageView метод «drawRect:» не называется. Подробнее здесь: drawRect не вызывается в моем подклассе UIImageView

1 голос
/ 01 марта 2016

для Swift 2.0,

    let image: UIImage! = UIGraphicsGetImageFromCurrentImageContext()

    imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)

    imgView.tintColor = UIColor(red: 51/255.0, green: 51/255.0, blue: 

51/255.0, alpha: 1.0)
0 голосов
/ 21 июня 2018

Для этого я создал макросы:

#define removeTint(view) \
if ([((NSNumber *)[view.layer valueForKey:@"__hasTint"]) boolValue]) {\
for (CALayer *layer in [view.layer sublayers]) {\
if ([((NSNumber *)[layer valueForKey:@"__isTintLayer"]) boolValue]) {\
[layer removeFromSuperlayer];\
break;\
}\
}\
}

#define setTint(view, tintColor) \
{\
if ([((NSNumber *)[view.layer valueForKey:@"__hasTint"]) boolValue]) {\
removeTint(view);\
}\
[view.layer setValue:@(YES) forKey:@"__hasTint"];\
CALayer *tintLayer = [CALayer new];\
tintLayer.frame = view.bounds;\
tintLayer.backgroundColor = [tintColor CGColor];\
[tintLayer setValue:@(YES) forKey:@"__isTintLayer"];\
[view.layer addSublayer:tintLayer];\
}

Чтобы использовать, просто позвоните:

setTint(yourView, yourUIColor);
//Note: include opacity of tint in your UIColor using the alpha channel (RGBA), e.g. [UIColor colorWithRed:0.5f green:0.0 blue:0.0 alpha:0.25f];

При удалении оттенка просто наберите:

removeTint(yourView);
...