Вопрос по image-processing, iphone, cocoa-touch – Как бы я тонировал изображение программно на iPhone?

85

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

alt text

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

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

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

Update: Подкласс UIImageView с кодомRamin предложил.

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

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

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

Update: drawRect: не вызывается.

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

Final, final update:

Для тех из вас, кто только изучает 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
}
Я добавил фрагмент перед публикацией в некоторый старый код drawRect, который у меня был, и он работал нормально. Возможно, захотите попробовать это без вызова [super viewDidLoad] (или переместите его выше). Также дважды проверьте, чтобы убедиться, что тот, кто выделяет этот объект, выделяет производную версию, а не ванильный UIImageView (т.е. если он загружается в кончик, распределитель и т. Д.). Ramin
Другое предложение, если вышеприведенное не работает: вместо создания подкласса UIImageView создайте подкласс простого UIView и добавьте как overlayColor, так и свойство UIImage, называемое «image» apos; что вы можете установить. Затем поместите туда drawRect. Код drawRect не заботится о том, является ли изображение «изображением». значение берется из UIImageView или из свойства, которое вы определили. Ramin
Не получится ли это, если изображение с альфа-каналом? Что делать, если я хочу подкрасить только нарисованную часть изображения? (Так же, как UIButton?) Sunil Chauhan

Ваш Ответ

13   ответов
0

Я сделал макросы для этой цели:

#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);
0

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

Например:

UIImageView *yourPicture = (however you grab the image);
UIView *colorBlock = [[UIView alloc] initWithFrame:yourPicture.frame];
//Replace R G B and A with values from 0 - 1 based on your color and transparency
colorBlock.backgroundColor = [UIColor colorWithRed:R green:G blue:B alpha:A];
[yourPicture addSubView:colorBlock];

Документация для UIColor:

colorWithRed:green:blue:alpha:

Creates and returns a color object using the specified opacity and RGB component values.

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha

Parameters

red    - The red component of the color object, specified as a value from 0.0 to 1.0.

green  - The green component of the color object, specified as a value from 0.0 to 1.0.

blue   - The blue component of the color object, specified as a value from 0.0 to 1.0.



alpha  - The opacity value of the color object, specified as a value from 0.0 to 1.0.

Return Value

The color object. The color information represented by this object is in the device RGB colorspace. 
Core Graphics, кажется, может применять режимы изгиба. Как, это вопрос. willc2
25

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

Я назвал свой класс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
Когда я пытаюсь использовать этот ответ, мой фон (область, которая должна быть прозрачной) вместо этого становится черным. Вы знаете, что я могу здесь делать не так?
Не берите в голову! (У меня был установлен цвет фона в раскадровке! D & apos; о!) Это потрясающее решение !!!
Это решение работает хорошо, хотя я добился лучших результатов, сначала отобразив изображение, а затем закрасив цвет поверх kCGBlendModeColor.
метод drawRect: действительно является «мясом» этого решения. Остальное дело вкуса / стиля. Спасибо! Работал на меня!
Спасибо. Это было первое решение в этом вопросе, которое на самом деле правильно поддерживало прозрачность изображения.
1

Для 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)
2

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

4
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
Мне нужно было подкрасить UIImage, но не использовать его внутри UIImageView, а как фоновое изображение для UINavigationBar, и ваш код сделал свое дело. Благодарю.
75

В 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
Это определенно лучший и самый простой способ перейти на iOS 7if это поведение оттенка, которое вы ищете. Но этот код применяет оттенок, как если бы вы использовали 100% непрозрачный & quot; Overlay & quot; Режим наложения в Photoshop, а не «Умножение» Режим смешивания, оригинальный вопрос искал.
26

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

The UIImageView class is optimized to draw its images to the display. UIImageView does not call the drawRect: method of its subclasses. If your subclass needs to include custom drawing code, you should subclass the UIView class instead.

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

спасибо @mpstx ... Также поместите эту строку документации в ответе в кавычках ... Apple должна была сделать то же самое в документации ... :-)
Я знаю, ты имеешь в виду ... Я потерял полдня, возиться с этим.
О, как бы я хотел знать это шесть месяцев назад. Они должны поставить предупреждение в виде 72 пунктов, красного цвета с меткой мигания. willc2
3

Вот еще один способ реализовать тонирование изображения, особенно если вы уже используете 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"
5

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

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

Мы выясним это позже. В любом случае, не является коммерческим продуктом, это своего рода «кодовое имя». Также есть внутренняя библиотека.
Выглядит интересно, но на что вы собираетесь сменить название, когда об этом узнают юристы Adobe?
+1 за предложение библиотеки (даже если это небольшая самореклама), а не за то, чтобы не изобретать велосипед.
0

У меня есть библиотека с открытым исходным кодом для этого:КСН-изображения фильтры

0

Также вы можете рассмотреть возможность кэширования составного изображения для повышения производительности и его рендеринга в drawRect:, а затем обновите его, если грязный флаг действительно грязный. Хотя вы можете часто его менять, могут быть случаи, когда появляются дро, и вы не пачкаетесь, поэтому вы можете просто обновить данные из кэша. Если память больше важна, чем производительность, вы можете проигнорировать это :)

Это то, что основной CALayer делает для вас автоматически. Нет необходимости кэшировать вид чертежа вручную.
44

Сначала вы захотите создать подкласс 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 (уровни наложения можно регулировать, изменяя альфа-значение цвета, который вы передаете вниз).

(Как также указано в другом ответе здесь)Special Considerations The UIImageView class is optimized to draw its images to the display. UIImageView will not call drawRect: a subclass. If your subclass needs custom drawing code, it is recommended you use UIView as the base class. Это означает, что вы не можете создать подкласс UIImageView и ожидать вызова drawRect,at all.
следует добавить CGContextSaveGState (context); перед изменением режима наложения, или вы получаете недостаточное количество gstack. willc2
О, спасибо. Ошибка копирования / вставки. Я исправил это во фрагменте кода.
Последующие предложения прилагается к первоначальному запросу (выше).
попробовал ваш код, результаты выше. willc2

Похожие вопросы