Jak odcień obrazu programowo na iOS?

Chciałbym odcień obrazu z odniesieniem kolorów. Wyniki powinny wyglądać jak tryb mieszania Wielokrotnego w Photoshopie, gdzie białe zostaną zastąpione tint :

alt text

Będę stale zmieniać wartość koloru.

Kontynuacja: umieściłbym kod, aby to zrobić w metodzie Drawrect: ImageView, prawda?

Jak zawsze, fragment kodu bardzo by pomógł w moim zrozumieniu, w przeciwieństwie do link.

Update: Subclassing a UIImageView with the code Ramin suggested.

Umieszczam to w viewDidLoad: of my view controller:

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

Widzę obraz, ale nie jest zabarwiony. Próbowałem również załadować inne obrazy, ustawić obraz w IB i wywołać setNeedsDisplay: w moim kontrolerze widoku.

Update: drawRect: nie jest wywoływany.

Ostatnia aktualizacja: znalazłem stary projekt, który miał skonfigurowany imageView właściwie, żebym mógł przetestować kod Ramina i działa jak urok!

Ostatnia aktualizacja:

Dla tych z Was, którzy dopiero uczą się podstawowej Grafiki, oto najprostsza rzecz, która mogłaby zadziałać.

W podklasowanym 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
}
Author: Cœur, 2009-07-12

13 answers

Najpierw będziesz chciał podklasować UIImageView i nadpisać metodę drawRect. Twoja klasa potrzebuje właściwości uicolor (nazwijmy ją overlayColor) do utrzymywania koloru mieszania i niestandardowego ustawiacza, który wymusza ponowne rysowanie po zmianie koloru. Coś takiego:

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

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

W metodzie drawRect najpierw musisz narysować obraz, a następnie nałożyć go na prostokąt wypełniony żądanym kolorem wraz z odpowiednim trybem mieszania, coś takiego:

- (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);
}

Zwykle w celu optymalizacji rysunek ograniczyłbyś rzeczywisty rysunek tylko do obszaru przekazanego do drawRect, ale ponieważ obraz tła musi być przerysowany za każdym razem, gdy zmienia się kolor, prawdopodobnie całość będzie wymagała odświeżenia.

Aby go użyć, Utwórz instancję obiektu, a następnie ustaw właściwość image (odziedziczoną po UIImageView) na obrazek i overlayColor na wartość UIColor (poziomy mieszania można dostosować zmieniając wartość alfa przekazywanego koloru).

 45
Author: Ramin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-17 16:50:17

W iOS7 wprowadzono właściwość Tintcolor w UIImageView i renderingMode w UIImage. Aby odcień UIImage na iOS7, wszystko, co musisz zrobić, to:

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
 77
Author: Toland Hon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-01 20:18:11

Chciałem odcień obrazu z alfą i stworzyłem następującą klasę. Proszę dać mi znać, jeśli znajdziesz jakieś problemy z nim.

Nazwałem swoją klasę CSTintedImageView i dziedziczy ona z UIView, ponieważ UIImageView nie wywołuje metody drawRect:, Jak wspomniano w poprzednich odpowiedziach. Ustawiłem wyznaczony inicjalizator podobny do tego znalezionego w klasie UIImageView.

Użycie:

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
 26
Author: Stunner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-22 00:11:10

Tylko szybkie wyjaśnienie (po kilku badaniach na ten temat). Apple doc tutaj wyraźnie stwierdza, że:

Klasa UIImageView jest zoptymalizowana do rysowania swoich obrazów na wyświetlaczu. UIImageView nie wywołuje metody drawRect: swoich podklas. Jeśli twoja podklasa musi zawierać własny kod rysunku, powinieneś podklasować klasę UIView.

Więc nawet nie trać czasu na próbę nadpisania tej metody w UIImageView podklasie. Zacznij od UIView.

 26
Author: mattorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-27 03:36:40

To może być bardzo przydatne: PhotoshopFramework jest jedną z potężnych bibliotek do manipulowania obrazami w Objective-C. został on opracowany, aby przynieść te same funkcje, które użytkownicy Adobe Photoshop są znane. Przykłady: Ustawianie kolorów za pomocą RGB 0-255, stosowanie plików mieszanych, transformacje...

Jest open source, oto link do projektu: https://sourceforge.net/projects/photoshopframew/

 5
Author: SEQOY Development Team,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-22 20:44:16
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
 4
Author: gngrwzrd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-07 04:25:44

Oto inny sposób na zaimplementowanie przyciemniania obrazów, zwłaszcza jeśli używasz już QuartzCore do czegoś innego. To była moja odpowiedź na podobne pytanie .

Import QuartzCore:

#import <QuartzCore/QuartzCore.h>

Utwórz przezroczystą warstwę i dodaj ją jako podwarstwę dla obrazu, który chcesz odcień:

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

Dodaj QuartzCore do listy frameworków projektów (jeśli go jeszcze nie ma), w przeciwnym razie pojawią się błędy kompilatora:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"
 3
Author: lekksi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:23

Dla tych z Was, którzy próbują podklasować klasę UIImageView i utkną przy "drawRect: nie jest wywoływane", zwróć uwagę, że powinieneś podklasować klasę UIView, ponieważ dla klas UIImageView, metoda "drawRect:" nie jest wywoływana. Czytaj więcej tutaj: drawRect nie jest wywoływany w mojej podklasie UIImageView

 2
Author: pierre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:17

Jedyną rzeczą, o której mogę myśleć, byłoby stworzenie prostokątnego, w większości przezroczystego widoku z pożądanym kolorem i ułożenie go nad widokiem obrazu, dodając go jako podgląd podrzędny. Nie jestem pewien, czy to naprawdę odcień obrazu w sposób można sobie wyobrazić choć, nie jestem pewien, jak można włamać się do obrazu i selektywnie zastąpić niektóre kolory z innymi... brzmi ambitnie.

Na przykład:

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];

Dokumentacja dla 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. 
 0
Author: Tim Bowen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-13 02:26:08

Możesz również rozważyć buforowanie złożonego obrazu dla wydajności i po prostu renderowanie go w drawRect:, a następnie zaktualizowanie go, jeśli brudna flaga jest rzeczywiście brudna. Chociaż możesz go często zmieniać, mogą się zdarzyć przypadki, w których pojawiają się losowania i nie jesteś brudny, więc możesz po prostu odświeżyć z pamięci podręcznej. Jeśli pamięć jest bardziej problemem niż wydajność, możesz to zignorować:)

 0
Author: Steve Riggins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-13 16:21:24

Mam bibliotekę, którą otwieram do tego: ios-image-filters

 0
Author: esilver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-27 07:42:37

Dla 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
Author: yazh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-01 11:03:58

Zrobiłem makra w tym celu:

#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];\
}

Aby użyć, po prostu zadzwoń:

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];

Podczas usuwania odcienia wystarczy wywołać:

removeTint(yourView);
 0
Author: Albert Renshaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-21 04:17:10