iOSでプログラムによって画像に色を付けるにはどうすればよいですか?


87

画像にカラーリファレンスを適用します。結果は、Photoshopの乗算ブレンドモードのようになります。このモードでは、色合いに置き換えられます。

代替テキスト

カラー値を継続的に変更します。

フォローアップ:これを行うためのコードをImageViewのdrawRect:メソッドに挿入しますよね?

いつものように、リンクとは対照的に、コードスニペットは私の理解に大きく役立ちます。

更新:Raminが提案したコードでUIImageViewをサブクラス化。

私はこれを私のビューコントローラの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
}

私が座っていた古いdrawRectコードに投稿する前にスニペットを追加しましたが、うまくいきました。[super viewDidLoad]を呼び出さずに試す(または上に移動する)ことができます。また、このオブジェクトを割り当てている誰もがバニラUIImageViewではなく派生バージョンを割り当てていることを確認します(つまり、nibやアロケーターなどでロードされている場合)。
Ramin、

上記が機能しない場合の別の提案:UIImageViewをサブクラス化する代わりに、プレーンなUIViewをサブクラス化し、overlayColorと、設定可能な「image」と呼ばれるUIImageプロパティの両方を追加します。次に、drawRectをそこに配置します。drawRectコードは、 'image'の値がUIImageViewからのものか、定義したプロパティからのものかは関係ありません。
ラミン

画像にアルファが含まれている場合、これは失敗しませんか?画像の描かれた部分のみに色を付けたい場合はどうすればよいですか?(UIButtonと同じように?)
Sunil Chauhan

回答:


45

最初に、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から継承)を画像とoverlayColorUIColor値に設定します(ブレンドレベルは、渡す色のアルファ値を変更することで調整できます)。


元のリクエストに添付されたフォローアップの提案(上記)。
ラミン

CGContextSaveGState(context);を追加する必要があります。ブレンドモードを変更する前に、またはgstackアンダーフローを取得します。
willc2 2009

ドー、ありがとう。コピー/貼り付けエラー。コードスニペットで修正しました。
ラミン

10
(ここの別の回答でも説明されています) 特別な考慮事項UIImageViewクラスは、そのイメージをディスプレイに描画するように最適化されています。UIImageViewは、drawRect:サブクラスを呼び出しません。サブクラスでカスタム描画コードが必要な場合は、UIViewを基本クラスとして使用することをお勧めします。この手段は、あなたはUIImageViewをサブクラスとのdrawRectは、呼び出されることを期待することはできませんすべてで
ジョニー

こんにちは、残念ながら私はコードを試してみましたが、うまくいきませんでした:/。下の回答を@mpstxで参照してください。これは、drawRectがUIImageViewから呼び出されず、代わりにUIView(UIImageを使用)を使用する必要があることを示しています。
jklp 2013年

77

iOS7では、UIImageViewにtintColorプロパティを、UIImageにrenderingModeを導入しました。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を使うための最良かつ最も簡単な方法です。ただし、このコードは、元の質問が探していた「乗算」ブレンドモードではなく、Photoshopで100%不透明な「オーバーレイ」ブレンドモードを使用しているかのように色合いを適用します。
スマイリーボー2014年

26

画像をアルファで着色したかったので、次のクラスを作成しました。問題がありましたらお知らせください。

以前の返信で述べたように、私は自分のクラスに名前を付けましたが、CSTintedImageViewそれはメソッドを呼び出さないUIViewので継承します。クラスにあるものと同様の指定イニシャライザを設定しました。UIImageViewdrawRect: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、2012年

この回答を使おうとすると、背景(透明になるはずの領域)が黒になります。私がここで間違っていることを知っていますか?
livingtech 2013年

気にしないで!(ストーリーボードに背景色を設定しました!D'oh!)このソリューションは素晴らしいです!!!
livingtech 2013年

2
このソリューションは適切に機能しますが、最初にイメージをレンダリングしてから、kCGBlendModeColorで上部の色を塗りつぶすことで、より良い結果が得られました。
ジェレミーフラー

drawRect:メソッドは、実際にはこのソリューションの「肉」です。残りは好み/スタイルの問題です。ありがとう!私のために働いた!
horseshoe7

26

簡単な説明です(このトピックに関する調査の後)。ここのApple文書明確に次のように述べています:

UIImageViewクラスは、ディスプレイにその画像を描画するために最適化されています。そのサブクラスUIImageViewdrawRect:メソッドを呼び出しません。サブクラスにカスタム描画コードを含める必要がある場合は、UIView代わりにクラスをサブクラス化する必要があります。

したがって、UIImageViewサブクラスでそのメソッドをオーバーライドしようとする時間を無駄にしないでください。UIView代わりに開始します。


9
ああ、どうやって私がこれを6か月前に知っていたらいいのか。彼らは、72ポイントタイプ、赤の点滅タグで警告を配置する必要があります。
willc2

私が知っていることを知っています...私はそれをいじる半日を失いました。
mattorb 2010年

おかげで@mpstx ...また、そのドキュメント行を引用符で囲んで回答に入れてください... Appleはドキュメントでも同じようにすべき
でした

5

これは非常に便利です。PhotoshopFrameworkは、Objective-Cで画像を操作するための強力なライブラリの1つです。これは、Adobe Photoshopユーザーが使い慣れているのと同じ機能を提供するために開発されました。例:RGB 0〜255を使用して色を設定し、ブレンドファイラー、変換を適用する...

オープンソースです、ここにプロジェクトリンクがあります:https//sourceforge.net/projects/photoshopframew/


2
面白そうに見えますが、アドビの弁護士がそれを知ったときに、名前を何に変更しますか?
クリストファージョンソン

1
後でわかります。とにかく商品ではなく、ある種の「コードネーム」です。また、内部ライブラリです。
SEQOY開発チーム、

ライブラリを提案し(たとえそれが少しの自己宣伝であっても)、車輪を再発明するためのステップを与えないための+1。
Tim

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 2015

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をプロジェクトのフレームワークリストに追加します(まだない場合)。そうしないと、次のようなコンパイラエラーが発生します。

Undefined symbols for architecture i386: "_OBJC_CLASS_$_CALayer"

2

UIImageViewクラスのサブクラス化を試みて「drawRect:が呼び出されていない」で行き詰まっている場合、UIImageViewクラスの場合は「drawRect:」メソッドが呼び出されないため、代わりにUIViewクラスをサブクラス化する必要があることに注意してください。続きを読む:UIImageViewのサブクラスでdrawRectが呼び出されない


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 2009

0

また、パフォーマンスのために合成画像をキャッシュし、drawRect:でレンダリングすることを検討することもできます。その後、ダーティフラグが実際にダーティである場合は、更新します。頻繁に変更しているかもしれませんが、描画が行われていてダーティではない場合があるので、単にキャッシュから更新できます。メモリがパフォーマンスよりも問題である場合は、これを無視できます:)


これは、基礎となるCALayerが自動的に行うことです。ビュー図面を手動でキャッシュする必要はありません。
Dennis


0

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

私はこの目的のためにマクロを作りました:

#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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.