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

ann*_*nna 73 iphone image tint uiimage ios

我知道可以通过在其上绘制CGContextFillRect并设置混合模式来着色矩形图像.但是,我无法弄清楚如何对透明图像(如图标)进行色调处理.它必须是可能的,因为SDK本身就是在tab-bar上自己做的.有人能提供一个片段吗?

更新:

自从我最初提出这个问题以来,已经给出了很多很好的建议.请务必仔细阅读所有答案,找出最适合您的方法.

更新(2015年4月30日):

使用iOS 7.0,我现在可以执行以下操作,这将满足我原始问题的需要.但如果您有更复杂的案例,请查看所有答案.

UIImage *iconImage = [[UIImage imageNamed:@"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
Run Code Online (Sandbox Code Playgroud)

fab*_*abb 164

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


如果你有一个灰度图像,并希望白色成为着色颜色,那kCGBlendModeMultiply就是要走的路.使用此方法,您不能使亮点比着色颜色更亮.

相反,如果你有一张非灰度图像,或者你有亮点阴影应保留,混合模式kCGBlendModeColor是要走的路.白色将保持白色,黑色将保持黑色,因为图像的亮度保持不变.此模式仅用于着色 - 它与Photoshop的Color图层混合模式相同(免责声明:可能会发生略有不同的结果).

请注意,无论是在iOS还是在Photoshop中,着色alpha像素都无法正常工作 - 半透明黑色像素不会保持黑色.我更新了下面的答案来解决这个问题,花了很长时间才找到答案.

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

如果要创建a 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();
Run Code Online (Sandbox Code Playgroud)

所以这是用于着色透明图像的代码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);
Run Code Online (Sandbox Code Playgroud)

如果您的图像没有半透明像素,您也可以采用相反的方式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);
Run Code Online (Sandbox Code Playgroud)

如果您不关心光度,因为您只有一个带有颜色的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);
Run Code Online (Sandbox Code Playgroud)

或者相反:

// 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);
Run Code Online (Sandbox Code Playgroud)

玩得开心!

  • 这很精彩而且彻底......但是它缺少一个确保Retina显示器上的高质量输出的小选项---- UIGraphicsBeginImageContextWithOptions(myIconImage.size,NO,[[UIScreen mainScreen] scale]); (8认同)

小智 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;
}
Run Code Online (Sandbox Code Playgroud)


ann*_*nna 18

周围搜索后,最好的解决方案我来迄今是使用的混合模式和剪贴蒙版的组合来实现着色/着色透明PNG:

CGContextSetBlendMode (context, kCGBlendModeMultiply);

CGContextDrawImage(context, rect, myIconImage.CGImage);

CGContextClipToMask(context, rect, myIconImage.CGImage);

CGContextSetFillColorWithColor(context, tintColor);

CGContextFillRect(context, rect);
Run Code Online (Sandbox Code Playgroud)


toz*_*evv 16

通过使用kCGBlendModeOverlay,我可以在Apple导航栏中获得非常接近色调的结果.在这篇文章/sf/answers/327941351/中采用优秀的@fabb答案并结合@omz方法我带来了这个解决方案,它保留了我期望的结果:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个用透明度着色几个灰度图像的例子:

渲染示例:

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

  • 这对我很有用.我只想添加将第一行更改为:UIGraphicsBeginImageContextWithOptions(self.size,NO,[[UIScreen mainScreen] scale]); 如果适用,允许图像保留视网膜格式. (4认同)

kko*_*dev 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;
}
Run Code Online (Sandbox Code Playgroud)


Tol*_*Hon 8

在iOS7中,他们在UIImageView上引入了tintColor属性,在UIImage上引入了renderingMode.请参阅/sf/answers/1338758431/上的示例