मैं iOS पर प्रोग्रामेटिक रूप से टिंट कैसे करूंगा?


87

मैं एक रंग संदर्भ के साथ एक छवि टिंट करना चाहूंगा। परिणाम फ़ोटोशॉप में मल्टीप्लाई ब्लेंडिंग मोड की तरह दिखना चाहिए, जहां सफेद को टिंट के साथ बदल दिया जाएगा :

वैकल्पिक शब्द

मैं लगातार रंग मूल्य बदल रहा हूँ।

फॉलो अप: मैं अपने ImageView के ड्राअर में यह करने के लिए कोड डालूँगा: विधि, है ना?

हमेशा की तरह, एक लिंक स्निपेट मेरी समझ में बहुत मदद करेगा, एक लिंक के विपरीत।

अद्यतन: UIImageView कोड Ramin सुझाए गए कोड के साथ ।

मैंने इसे अपने व्यू कंट्रोलर में डाल दिया:

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

मैं छवि देख रहा हूं, लेकिन यह रंगा नहीं जा रहा है। मैंने अन्य छवियों को लोड करने की कोशिश की, छवि को आईबी में सेट किया, और सेटनएड्सडिसप्ले को कॉल किया: मेरे विचार नियंत्रक में।

अपडेट : ड्राअरक्ट: नहीं कहा जा रहा है।

अंतिम अद्यतन: मुझे एक पुरानी परियोजना मिली, जिसमें एक छवि दृश्य ठीक से सेट किया गया था ताकि मैं रामिन के कोड का परीक्षण कर सकूं और यह एक आकर्षण की तरह काम करे!

अंतिम, अंतिम अद्यतन:

आप में से जो लोग अभी कोर ग्राफिक्स के बारे में सीख रहे हैं, उनके लिए यहां सबसे सरल बात है जो संभवतः काम कर सकती है।

आपके उपवर्ग में:

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

मैंने कुछ पुराने ड्राअर कोड को पोस्ट करने से पहले स्निपेट को जोड़ा था जो मैंने आसपास बैठे थे और यह ठीक काम किया। [[सुपर व्यूडीडलड] कॉल (या इसे ऊपर ले जाना) के बिना इसे आज़माना चाहते हैं। यह सुनिश्चित करने के लिए डबल-चेक करें कि जो कोई भी इस ऑब्जेक्ट को आवंटित कर रहा है वह व्युत्पन्न संस्करण को आवंटित नहीं कर रहा है न कि वेनिला UIImageView (यानी यदि यह एक निब में लोड होता है, तो आवंटनकर्ता, आदि)।
रामिन

यदि उपर्युक्त कार्य नहीं करता है तो एक और सुझाव: UIImageView को उप-वर्ग करने के बजाय एक सादे UIView को उप-वर्गित करें और ओवरलेकॉन्लर और UIImage गुण दोनों को जोड़ें, जिसे 'इमेज' कहा जाता है जिसे आप सेट कर सकते हैं। फिर ड्रॉअर को वहां रखें। दराज कोड यह परवाह नहीं करता है कि 'छवि' मूल्य UIImageView से आता है या आपके द्वारा परिभाषित संपत्ति से।
रामिन

यह विफल नहीं होगा अगर छवि अल्फा के साथ है? क्या होगा अगर मैं छवि के केवल खींचे गए हिस्से को टिंट करना चाहूंगा? (ठीक यूबूटॉन की तरह?)
सुनील चौहान

जवाबों:


45

पहले आप UIImageView को उप-वर्ग करना चाहते हैं और ड्राअर विधि को ओवरराइड करेंगे। आपकी कक्षा को मिश्रण रंग और एक कस्टम सेटर को पकड़ने के लिए एक UIColor संपत्ति (चलो इसे ओवरलेकर कहते हैं) की आवश्यकता है जो रंग बदलने पर एक लाल रंग को मजबूर करता है। कुछ इस तरह:

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

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

ड्राअर विधि में आप पहले चित्र बनाना चाहते हैं, फिर इसे ठीक आयत के साथ रंग के साथ भरी आयत के साथ ओवरले करें, कुछ इस तरह से:

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

आमतौर पर ड्राइंग को ऑप्टिमाइज़ करने के लिए आप वास्तविक ड्रॉइंग को केवल उस क्षेत्र तक सीमित कर देते हैं, जो ड्रॉइरेक्ट में पास हो जाता है, लेकिन चूंकि बैकग्राउंड की छवि को हर बार फिर से रंगना पड़ता है, इसलिए रंग बदलने की संभावना है कि पूरी चीज़ को ताज़ा करने की आवश्यकता होगी।

इसका उपयोग करने के लिए ऑब्जेक्ट का एक उदाहरण बनाएं, फिर imageचित्र पर और overlayColorUIColor मान के लिए संपत्ति (UIImageView से विरासत में मिली) सेट करें (आपके द्वारा नीचे दिए गए रंग के अल्फा मान को बदलकर मिश्रण स्तरों को समायोजित किया जा सकता है)।


मूल अनुरोध (ऊपर) से जुड़े अनुवर्ती सुझाव।
रामिन

CGContextSaveGState (संदर्भ) जोड़ना चाहिए; ब्लेंड मोड बदलने से पहले या आपको एक gstack अंडरफ्लो मिलता है।
विल्क 2

डी'ओह, धन्यवाद। कॉपी / पेस्ट त्रुटि। मैंने इसे कोड स्निपेट में तय किया है।
रामिन

10
(जैसा कि यहां एक अन्य जवाब में भी कहा गया है) विशेष विचार UIImageView वर्ग अपनी छवियों को डिस्प्ले में खींचने के लिए अनुकूलित है। UIImageView ड्रॉबैक को कॉल नहीं करेगा: एक उपवर्ग। यदि आपके उपवर्ग को कस्टम ड्रॉइंग कोड की आवश्यकता है, तो यह अनुशंसा की जाती है कि आप आधार वर्ग के रूप में यूआईवाईईवी का उपयोग करें। इसका मतलब है आप UIImageView subclass नहीं कर सकते हैं और उम्मीद करते हैं drawRect, के नाम से जाना सब पर
जॉनी

नमस्ते, दुर्भाग्य से मैंने कोड की कोशिश की और यह काम नहीं किया: /। @Mpstx द्वारा नीचे दिया गया उत्तर देखें, जो कहता है कि ड्राअरेक्ट को UIImageView से नहीं बुलाया जाएगा और इसके बजाय, आपको एक UIView (UIImage के साथ) का उपयोग करना चाहिए, जिसने मेरे लिए ठीक काम किया।
जर्कल्प

77

IOS7 में, उन्होंने UIImageView और प्रतिपादन पर UMmageView पर tintColor संपत्ति पेश की है। IOS7 पर UIImage टिंट करने के लिए, आपको बस इतना करना है:

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

18
यह निश्चित रूप से iOS 7 पर जाने का सबसे अच्छा और आसान तरीका है अगर यह आपके द्वारा खोजा जाने वाला टिंट व्यवहार है। लेकिन यह कोड एक टिंट लागू करता है जैसे कि आप फ़ोटोशॉप में एक 100% अपारदर्शी "ओवरले" सम्मिश्रण मोड का उपयोग कर रहे थे, न कि "गुणा" सम्मिश्रण मोड में मूल प्रश्न की तलाश थी।
स्माइबॉर्ग

26

मैं अल्फा के साथ एक छवि टिंट करना चाहता था और मैंने निम्न वर्ग बनाया। कृपया मुझे बताएं कि क्या आपको इसके साथ कोई समस्या है।

मैं अपने वर्ग में नामित किया है 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

2
धन्यवाद। यह इस सवाल का पहला समाधान था जिसने वास्तव में छवि पारदर्शिता का ठीक से समर्थन किया।
TheTRON

जब मैं इस उत्तर का उपयोग करने की कोशिश करता हूं, तो मेरी पृष्ठभूमि (जो क्षेत्र पारदर्शी होना चाहिए) उसके बजाय काला है। क्या आप जानते हैं कि मैं यहां क्या गलत कर सकता था?
6:13

कोई बात नहीं! (मैं स्टोरीबोर्ड में एक पृष्ठभूमि रंग सेट था! D'oh!) यह समाधान कमाल है !!!
जून को 'लाइवटेक

2
यह समाधान अच्छी तरह से काम करता है, हालांकि मैंने पहले छवि को प्रस्तुत करके बेहतर परिणाम प्राप्त किए, फिर शीर्ष पर रंग को kCGBlendModeColor के साथ भर दिया।
जेरेमी फुलर

दोष: विधि वास्तव में इस समाधान का "मांस" है। बाकी स्वाद / शैली का मामला है। धन्यवाद! मेरे लिए काम किया!
घोड़े की नाल

26

बस एक त्वरित स्पष्टीकरण (इस विषय पर कुछ शोध के बाद)। Apple डॉक यहाँ स्पष्ट रूप से बताता है कि:

UIImageViewवर्ग प्रदर्शन करने के लिए अपने छवियों आकर्षित करने के लिए अनुकूलित है। अपने उपवर्गों UIImageViewकी drawRect:विधि को नहीं कहते हैं । यदि आपके उपवर्ग में कस्टम ड्राइंग कोड को शामिल करने की आवश्यकता है, तो आपको UIViewइसके बजाय कक्षा को उप- वर्ग करना चाहिए ।

इसलिए किसी भी समय उपविधि में उस विधि को ओवरराइड करने का प्रयास करने में बर्बाद न करें UIImageViewUIViewइसके बजाय शुरू करें ।


9
ओह, काश मैं यह छह महीने पहले जानता होता। उन्हें 72 बिंदु प्रकार में चेतावनी डालनी चाहिए, ब्लिंक टैग के साथ लाल।
विच 2

मुझे पता है आपका मतलब है ... मैं इसके साथ खिलवाड़ करते हुए एक आधा दिन खो दिया।
20

धन्यवाद @mpstx ... इसके अलावा उद्धरण में जवाब में कि प्रलेखन लाइन डाल ... एप्पल दस्तावेज में ही किया जाना चाहिए ... :-)
Krishnabhadra

5

यह बहुत उपयोगी हो सकता है: PhotoshopFramework एक शक्तिशाली पुस्तकालय है जो ऑब्जेक्ट-सी पर छवियों को हेरफेर करने के लिए है। यह उन्हीं कार्यक्षमताओं को लाने के लिए विकसित किया गया था जो Adobe Photoshop उपयोगकर्ता परिचित हैं। उदाहरण: RGB 0-255 का उपयोग करके रंग सेट करें, ब्लेंड फिलर्स, ट्रांसफॉर्मेशन लागू करें ...

खुला स्रोत है, यहाँ परियोजना लिंक है: https://sourceforge.net/projects/photoshopframew/


2
दिलचस्प लग रहा है, लेकिन जब आप एडोब के वकीलों को इसके बारे में पता लगाते हैं, तो आप क्या नाम बदलने जा रहे हैं?
क्रिस्टोफर जॉनसन

1
हम बाद में पता करेंगे। वैसे भी एक वाणिज्यिक उत्पाद नहीं है, किसी प्रकार का "कोडनेम" है। एक आंतरिक पुस्तकालय भी है।
SEQOY विकास दल

एक पुस्तकालय का सुझाव देने के लिए +1 (भले ही यह थोड़ा आत्म-प्रचार हो), और पहिया को सुदृढ़ करने के लिए कदम नहीं दे रहा है।
टिम

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 के लिए पृष्ठभूमि छवि के रूप में, और आपके कोड ने चाल चली। धन्यवाद।
ncerezo

3

यहां इमेज टिंटिंग को लागू करने का एक और तरीका है, खासकर यदि आप पहले से ही किसी और चीज के लिए क्वार्ट्जकोर का उपयोग कर रहे हैं। इसी तरह के सवाल के लिए मेरा जवाब था ।

आयात क्वार्ट्जकोर:

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

अपनी परियोजनाओं के फ्रेमवर्क सूची में क्वार्ट्जकोर जोड़ें (यदि यह पहले से ही नहीं है), अन्यथा आपको इस तरह के कंपाइलर त्रुटियां मिलेंगी:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"

2

आप में से जो एक UIImageView वर्ग को उपवर्गित करने का प्रयास करते हैं और "drawRect: is not बुलाया जा रहा है" पर अटक जाते हैं, ध्यान दें कि आपको इसके बजाय एक UIView वर्ग को उप-वर्ग करना चाहिए, क्योंकि UIImageView वर्गों के लिए, "drawRect:" विधि नहीं कहा जाता है। यहाँ और पढ़ें: UIImageView के मेरे उपवर्ग में आह्वान नहीं किया जा रहा है


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. 

लगता है कि कोर ग्राफिक्स झुकने वाले मोड को लागू करने में सक्षम हैं। कैसे, सवाल है।
विलक 2

0

इसके अलावा, आप प्रदर्शन के लिए कंपोज़िट की गई इमेज को कैशिंग करने पर विचार कर सकते हैं और इसे केवल ड्रॉर में रेंडर कर सकते हैं :, फिर इसे अपडेट किया अगर एक गंदा झंडा वास्तव में गंदा है। जब आप इसे अक्सर बदल रहे हैं, तो ऐसे मामले भी हो सकते हैं जहां ड्रॉ आ रहे हैं (आप गंदे नहीं हैं, इसलिए आप बस कैश से ताज़ा कर सकते हैं। यदि मेमोरी प्रदर्शन से अधिक समस्या है, तो आप इसे अनदेखा कर सकते हैं :)


यही अंतर्निहित काइलेयर स्वचालित रूप से आपके लिए करता है। ड्राइंग को मैन्युअल रूप से कैश करने की आवश्यकता नहीं है।
डेनिस मुनसी


0

स्विफ्ट 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

मैंने इस उद्देश्य के लिए मैक्रोज़ बनाया:

#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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.