Как я могу нарисовать изображение программно на iPhone?

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

alt text

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

Последующие действия: Я бы поставил код для этого в моем ImageView drawRect: метод, правильно?

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

Обновление: Подклассификация UIImageView с помощью кода Ramin.

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

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

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

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

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

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

Для тех из вас, кто просто учится в 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
}

Ответ 1

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

Ответ 2

В 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

Ответ 3

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

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

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

Ответ 4

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

Я назвал свой класс 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

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Например:

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. 

Ответ 11

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

Ответ 12

У меня есть библиотека, которую я открываю для этого: ios-image-filters