74

CGContextFillRect を描画し、ブレンド モードを設定することで、長方形の画像に色を付けることができることを知っています。ただし、アイコンなどの透明な画像に色合いを付ける方法がわかりません。SDK がそのようなタブバーでそれを行うため、可能である必要があります。誰かがスニペットを提供できますか?

アップデート:

私が最初に尋ねて以来、この問題に対して多くの素晴らしい提案がありました。すべての回答をよく読んで、自分に最も適したものを見つけてください。

更新 (2015 年 4 月 30 日):

iOS 7.0 では、次のことを実行できるようになりました。これにより、元の質問のニーズが満たされます。しかし、もっと複雑なケースがある場合は、すべての回答を確認してください。

UIImage *iconImage = [[UIImage imageNamed:@"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
4

13 に答える 13

165

更新:以下のコードを使用したSwiftUIColor拡張機能の要点は次のとおりです。


グレースケール画像があり、白を着色色にしたい場合は、これが最適kCGBlendModeMultiplyな方法です。この方法では、ハイライトを色合いよりも明るくすることはできません。

逆に、グレースケール以外の画像がある場合、または保存する必要のあるハイライトシャドウがある場合は、ブレンドモードkCGBlendModeColorが最適です。画像の明るさが維持されるため、白は白のまま、黒は黒のままになります。このモードは、色付けのために作成されたものです。これは、Photoshopのレイヤーブレンドモードと同じColorです(免責事項:結果がわずかに異なる場合があります)。

アルファピクセルの色付けは、iOSでもPhotoshopでも正しく機能しないことに注意してください。半透明の黒いピクセルは黒のままではありません。その問題を回避するために以下の回答を更新しました。見つけるのにかなり長い時間がかかりました。

kCGBlendModeSourceIn/DestinationInの代わりにブレンドモードの1つを使用することもできますCGContextClipToMask

を作成する場合UIImageは、次の各コードセクションを次のコードで囲むことができます。

UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, myIconImage.scale); // for correct resolution on retina, thanks @MobileVet
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextTranslateCTM(context, 0, myIconImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGRect rect = CGRectMake(0, 0, myIconImage.size.width, myIconImage.size.height);

// image drawing code here

UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

透明な画像を次のように着色するためのコードは次のkCGBlendModeColorとおりです。

// draw black background to preserve color of transparent pixels
CGContextSetBlendMode(context, kCGBlendModeNormal);
[[UIColor blackColor] setFill];
CGContextFillRect(context, rect);

// draw original image
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// tint image (loosing alpha) - the luminosity of the original image is preserved
CGContextSetBlendMode(context, kCGBlendModeColor);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

画像に半透明のピクセルがない場合は、次の方法で逆にすることもできますkCGBlendModeLuminosity

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// replace luminosity of background (ignoring alpha)
CGContextSetBlendMode(context, kCGBlendModeLuminosity);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

明るさを気にしない場合は、色で着色する必要があるアルファチャネルのある画像を取得しただけなので、より効率的な方法でそれを行うことができます。

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

またはその逆:

// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);

楽しむ!

于 2011-09-11T11:12:23.867 に答える
21

私が試した他の方法では、特定の色の組み合わせで半透明のピクセルの色が歪んでいたため、この方法で最も成功しました。これにより、パフォーマンス面でも少し改善されるはずです。

+ (UIImage *) imageNamed:(NSString *) name withTintColor: (UIColor *) tintColor {

    UIImage *baseImage = [UIImage imageNamed:name];

    CGRect drawRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);

    UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, baseImage.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // draw original image
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGContextDrawImage(context, drawRect, baseImage.CGImage);

    // draw color atop
    CGContextSetFillColorWithColor(context, tintColor.CGColor);
    CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
    CGContextFillRect(context, drawRect);

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}
于 2014-03-20T09:21:37.453 に答える
18

周りを検索した後、私がこれまでに得た最善の解決策は、ブレンドモードとクリッピングマスクの組み合わせを使用して、透明なPNGの色付け/着色を実現することです。

CGContextSetBlendMode (context, kCGBlendModeMultiply);

CGContextDrawImage(context, rect, myIconImage.CGImage);

CGContextClipToMask(context, rect, myIconImage.CGImage);

CGContextSetFillColorWithColor(context, tintColor);

CGContextFillRect(context, rect);
于 2010-08-19T18:13:35.350 に答える
16

kCGBlendModeOverlayを使用すると、Appleナビゲーションバーの色合いに非常に近い結果を得ることができます。この投稿では、優れた@fabbの回答を取り、@ omzアプローチを組み合わせています。https://stackoverflow.com/a/4684876/229019期待した結果を保持するこのソリューションが付属しています。

- (UIImage *)tintedImageUsingColor:(UIColor *)tintColor;
{
    UIGraphicsBeginImageContextWithOptions (self.size, NO, [[UIScreen mainScreen] scale]);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    // draw original image
    [self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];

    // tint image (loosing alpha). 
    // kCGBlendModeOverlay is the closest I was able to match the 
    // actual process used by apple in navigation bar 
    CGContextSetBlendMode(context, kCGBlendModeOverlay);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    // mask by alpha values of original image
    [self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tintedImage;
}

いくつかのグレースケール画像を透明度で着色する例を次に示します。

レンダリングされた例

  • 最初の行は、[UIColororangeColor]で着色されたアップルツールバーです。
  • 2行目は、クリアカラー(=実際のグラデーション)で始まり、同じオレンジで終わるいくつかの色で着色された同じグラデーションです。
  • 3つ目は透明度のある単純な円です(リネンは背景色です)
  • 4行目は複雑で暗いノイズの多いテクスチャです
于 2012-03-29T15:15:27.760 に答える
8

iOS7では、UIImageViewにtintColorプロパティ、UIImageにrenderingModeを導入しました。https://stackoverflow.com/a/19125120/1570970で私の例を参照してください。

于 2013-10-01T20:21:58.340 に答える
8

UIImage カテゴリを作成して、次のようにすることができます。

- (instancetype)tintedImageWithColor:(UIColor *)tintColor {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect rect = (CGRect){ CGPointZero, self.size };
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    [self drawInRect:rect];

    CGContextSetBlendMode(context, kCGBlendModeSourceIn);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    UIImage *image  = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
于 2013-09-26T10:46:02.837 に答える
3

fabbが受け入れた回答では、UIImageを作成するための「周囲の」コードにより、網膜画面上の画像の解像度が間違っていることに注意してください。修正するには、次を変更します。

UIGraphicsBeginImageContext(myIconImage.size);

に:

UIGraphicsBeginImageContextWithOptions(myIconImage.size, NO, 0.0);

0.0 に設定されている最後のパラメーターはスケールであり、Apple のドキュメントによると:

「値 0.0 を指定すると、倍率はデバイスのメイン画面の倍率に設定されます」。

コメントする許可がありません。編集は少し失礼に思えるので、回答でこれについて言及します。誰かがこの同じ問題に遭遇した場合に備えて。

于 2013-07-11T13:08:12.300 に答える
3

iOS 7.0 では、これを実行して基本的な UIImageView を着色することもできます。

UIImage *iconImage = [[UIImage imageNamed:@"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
于 2015-04-30T11:50:50.170 に答える
2

UIImageView (or any view for that matter) has a background color which is RGBA. The alpha in the color may do what you need without inventing something new.

于 2010-08-18T18:56:12.753 に答える
1

私の仕事ではありませんが、このアプローチをうまく使用しました:

http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage

于 2012-03-14T07:46:47.210 に答える
1

スタック オーバーフローについての回答はありません。当社のデザイナーは、さまざまな形式、さまざまなアルファ値 (および「アルファ ホール」) を使用して UI 要素を描画します。ほとんどの場合、これはアルファ チャンネルを持つ 32 ビット PNG ファイルで、白黒のピクセル (可能なすべての強度) で構成されます。そのような写真を着色した後、私はこの着色された結果を得る必要がありました: 白いピクセル - より多く着色され、暗いピクセル - より少なく。そして、これはすべてアルファチャンネルの観点からです。そして、UIImage カテゴリにこのメソッドを書きました。高効率ではないかもしれませんが、時計として機能します:)

- (UIImage *)imageTintedWithColor:(UIColor *)color {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextSetBlendMode(context, kCGBlendModeCopy);
    [color setFill];
    CGContextFillRect(context, rect);

    [self drawInRect:rect blendMode:kCGBlendModeXOR alpha:1.0];

    CGContextSetBlendMode(context, kCGBlendModeXOR);
    CGContextFillRect(context, rect);

    [self drawInRect:rect blendMode:kCGBlendModeMultiply alpha:1.0];

    UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return coloredImage;
}
于 2016-01-26T15:32:10.230 に答える
1

カスタム UIButton サブクラスで画像ビューをシェーディングしたかったのですが、他のソリューションでは望み通りの結果が得られませんでした。画像の色を「濃く」する必要がありました。CoreImage を使用して明るさを変更する方法は次のとおりです。

ボタンを押すと陰影付きのカスタム ボタン

  1. プロジェクトのライブラリに CoreImage.framework を必ず追加してください。(バイナリをライブラリにリンク)

  2. UIImage シェードメソッド

    - (UIImage *)shadeImage:(UIImage *)image {
     CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage];
    
     CIContext *context = [CIContext contextWithOptions:nil];
    
     CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"
                                  keysAndValues:kCIInputImageKey, inputImage,
                        @"inputBrightness", [NSNumber numberWithFloat:-.5], nil];
     CIImage *outputImage = [filter outputImage];
    
     CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
     UIImage *newImage = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation];
     CGImageRelease(cgImage);
    
     return newImage;
    }
    
  3. コンテキストを再作成するのではなく、ivar としてコンテキストのコピーを保存する必要があります。

于 2013-07-24T16:51:38.063 に答える
0

まず、半透明のアイコンに色を付けるという私のタスクを達成するのに役立った彼の並外れたソリューションに対して、fabb に感謝したいと思います。C# (Monotouch) のソリューションが必要だったので、彼のコードを翻訳する必要がありました。これが私が思いついたものです。これをコピーしてコードに貼り付け、半透明の画像を追加して完了です。

したがって、すべてのクレジットは fabb に送られます。これは、C# ユーザーをキックスタートするためのものです :)

//TINT COLOR IMAGE
UIImageView iImage = new UIImageView(new RectangleF(12, 14, 24,24));
iImage.ContentMode = UIViewContentMode.ScaleAspectFit;
iImage.Image = _dataItem.Image[0] as UIImage;

UIGraphics.BeginImageContextWithOptions(iImage.Bounds.Size, false, UIScreen.MainScreen.Scale);
CGContext context = UIGraphics.GetCurrentContext();

context.TranslateCTM(0, iImage.Bounds.Size.Height);
context.ScaleCTM(1.0f, -1.0f);

RectangleF rect = new RectangleF(0,0, iImage.Bounds.Width, iImage.Bounds.Height);

// draw black background to preserve color of transparent pixels
context.SetBlendMode(CGBlendMode.Normal);
UIColor.Black.SetFill();
context.FillRect(rect);

// draw original image
context.SetBlendMode(CGBlendMode.Normal);
context.DrawImage(rect, iImage.Image.CGImage);

// tint image (loosing alpha) - the luminosity of the original image is preserved
context.SetBlendMode(CGBlendMode.Color);
UIColor.Orange.SetFill();
context.FillRect(rect);

// mask by alpha values of original image
context.SetBlendMode(CGBlendMode.DestinationIn);
context.DrawImage(rect, iImage.Image.CGImage);

UIImage coloredImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();

iImage = new UIImageView(coloredImage);
iImage.Frame = new RectangleF(12, 14, 24,24);
//END TINT COLOR IMAGE

cell.Add(iImage);
于 2013-01-15T10:08:27.147 に答える