如何在iPhone中着色透明的PNG图像?

我知道可以通过在其上绘制CGContextFillRect并设置混合模式来对矩形图像着色。 但是,我不知道如何做一个透明的图像,如图标色调。 它必须是可能的,因为SDK自己在这样的标签栏上执行它自己。 任何人都可以提供一个片段?

更新:

自从我原本提出这个问题以来,已经有很多很棒的build议。 一定要仔细阅读所有答案,找出最适合自己的方式。

更新(2015年4月30日):

使用iOS 7.0,我现在可以做到以下几点,这将满足我原来的问题的需要。 但是,如果你有更复杂的情况,请检查所有的答案。

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

更新:这是使用下面的代码Swift UIColor扩展的要点 。


如果你有一个灰度图像,并希望白色成为着色kCGBlendModeMultiply是要走的路。 用这种方法,你不能有比你的着色颜色更亮点。

相反,如果您有一个非灰度图像或者您有应该保留的高光和阴影 ,混合模式kCGBlendModeColor是要走的路。 白色将保持白色,黑色将保持黑色,因为图像的亮度被保留。 此模式仅用于着色 – 与Photoshop的Color层混合模式相同(免责声明:可能会发生稍微不同的结果)。

请注意,在iOS和Photoshop中均无法正确着色alpha像素 – 半透明黑色像素不会保持黑色。 我更新了下面的答案来解决这个问题,花了相当长的时间才知道。

您也可以使用其中一种混合模式kCGBlendModeSourceIn/DestinationIn而不是CGContextClipToMask

如果你想创build一个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); 

如果你不关心亮度,因为你刚刚得到了一个应该用一种颜色着色的alpha通道的图像,你可以用更有效的方式来实现:

 // 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); 

玩的开心!

我使用这种方法取得了最大的成功,因为我尝试过的其他方法导致了某些颜色组合的半透明像素的扭曲颜色。 在性能方面,这应该也会好一些。

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

经过search,到目前为止,我所得到的最佳解决scheme是使用混合模式和剪贴蒙版的组合来实现对透明PNG进行着色/着色:

 CGContextSetBlendMode (context, kCGBlendModeMultiply); CGContextDrawImage(context, rect, myIconImage.CGImage); CGContextClipToMask(context, rect, myIconImage.CGImage); CGContextSetFillColorWithColor(context, tintColor); CGContextFillRect(context, rect); 

我可以通过使用kCGBlendModeOverlay获得非常接近Apple导航栏中的色调的结果。 以优秀@fabb答案和结合@omz方法在这篇文章中https://stackoverflow.com/a/4684876/229019我带着这个解决scheme,拿着我期待的结果:;

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

这里有一个例子用几何透明度着色几个灰度图像:

渲染示例

  • 第一行是苹果工具栏着色[UIColor orangeColor]。
  • 第二行是以几种颜色着色的相同梯度,以清晰的颜色(=实际梯度)开始,以相同的橙色结束。
  • 第三个是带透明度的简单圆圈(亚麻是背景色)
  • 第四行是一个复杂的黑暗嘈杂的纹理

你可以创build一个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; } 

在iOS7中,他们在UIImageView上引入了tintColor属性,在UIImage上引入了renderingMode。 在https://stackoverflow.com/a/19125120/1570970查看我的示例;

请注意,在fabb接受的答案中,用于制作UIImage的“周围”代码给了我视网膜屏幕上图像的错误分辨率。 要修复,请更改:

UIGraphicsBeginImageContext(myIconImage.size);

至:

UIGraphicsBeginImageContextWithOptions(myIconImage.size,NO,0.0);

最后一个设置为0.0的参数是比例尺,根据Apple文档:“如果指定值为0.0,比例因子设置为设备主屏幕的比例因子”。

没有权限评论,编辑似乎有点粗鲁,所以我在一个答案中提到这一点。 以防万一遇到同样的问题。

在iOS 7.0中,你也可以通过这个来为一个基本的UIImageView着色:

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

UIImageView(或任何视图)有一个背景颜色是RGBA。 阿尔法在颜色可能做你所需要的,而不发明新的东西。

不是我的工作,但我已经成功地使用了这种方法:

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

我想在我的自定义UIButton子类中遮蔽我的图像视图,其他解决scheme没有做我想要的。 我需要变暗图像颜色的“色调”。 以下是如何使用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,而不是重新创build。

首先,我要感谢fabb为他的卓越解决scheme,它帮助我完成了我的任务,以色彩半透明的图标。 因为我需要C#(Monotouch)的解决scheme,所以我不得不翻译他的代码。 这是我想出来的。 只要复制粘贴到您的代码,并添加你的半透明的图像和你的完成。

所以再次所有的信用去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); 

没有答案会帮助我在堆栈溢出:我们的devise师绘制各种forms的UI元素,各种alpha值(和“alpha-holes”)。 在大多数情况下,这是带有alpha通道的32位PNG文件,它包含黑白像素(所有可能的强度)。 在devise这样的图片后,我必须得到这个有色的结果:白色像素 – 更多的颜色,黑暗的像素 – 更less。 而这一切都是针对alpha通道的。 而我为我的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; }