如何使用alpha通道仅对UIImage的一部分着色 - PNG(替换颜色)?

时间:2015-09-28 11:39:54

标签: ios objective-c swift uiimage uicolor

我有这个透明的图像:

enter image description here

我的目标是改变“我!”零件颜色。要么仅为图像的最后3个着色,要么用新颜色替换蓝色。

换色后的预期结果:

enter image description here

不幸的是,这对我没用。要更改特定的颜色,我尝试了这个:LINK,但正如文档所说,这只适用于没有Alpha通道!

然后我尝试了这个:LINK,但这实际上什么也没做,没有色彩或任何东西。

是否有其他方法只为颜色的一部分着色或只是替换特定的颜色?

我知道我可以将图像分成两部分,但我希望还有另一种方法。

3 个答案:

答案 0 :(得分:4)

事实证明它非常复杂 - 你认为你可以通过CoreGraphics混合模式一次性完成它,但是从相当广泛的实验中我没有发现这样的方法不会破坏alpha通道或者着色。我着手解决的问题是:

  1. 从图像的灰度/ alpha版本开始而不是彩色图像:在您不想要着色的区域中为黑色,在您执行的区域中为白色
  2. 使用图片的尺寸
  3. 创建图像上下文
  4. 用黑色填充上下文
  5. 将图像绘制到上下文中
  6. 从该背景中获取新图片(让我们称之为“黑白图像”)
  7. 清除上下文(以便您可以再次使用)
  8. 使用您希望图像的有色部分的颜色填充上下文
  9. 使用“乘法”混合模式
  10. 将黑白图像绘制到上下文中
  11. 使用“目标处于”混合模式
  12. 将原始图像绘制到上下文中
  13. 从上下文中获取最终图片
  14. 这可行的原因是混合模式的组合。你正在做的是创建一个完全不透明的黑白图像(步骤5),然后将它乘以你的最终颜色(步骤8),这将为你提供一个完全不透明的黑色和你的最终彩色图像。然后,您拍摄原始图像,该图像仍然具有其Alpha通道,并使用“目标输入”混合模式绘制它,该模式采用来自黑色和您的彩色图像的颜色以及来自原始图像的Alpha通道。结果是带有原始亮度值和alpha通道的着色图像。

    <强>目标C

    - (UIImage *)createTintedImageFromImage:(UIImage *)originalImage color:(UIColor *)desiredColor {
        CGSize imageSize = originalImage.size;
        CGFloat imageScale = originalImage.scale;
        CGRect contextBounds = CGRectMake(0, 0, imageSize.width, imageSize.height);
    
        UIGraphicsBeginImageContextWithOptions(imageSize, NO /* not opaque */, imageScale); // 2
        [[UIColor blackColor] setFill]; // 3a
        UIRectFill(contextBounds); // 3b
        [originalImage drawAtPoint:CGPointZero]; // 4
        UIImage *imageOverBlack = UIGraphicsGetImageFromCurrentImageContext(); // 5
        CGContextClear(UIGraphicsGetCurrentImageContext()); // 6
        [desiredColor setFill]; // 7a
        UIRectFill(contextBounds); // 7b
        [imageOverBlack drawAtPoint:CGPointZero blendMode:kCGBlendModeMultiply alpha:1]; // 8
        [originalImage drawAtPoint:CGPointZero blendMode:kCGBlendModeDestinationIn alpha:1]; // 9
        finalImage = UIGraphicsGetImageFromCurrentContext(); // 10
        UIGraphicsEndImageContext();
    
        return finalImage;
    }
    

    Swift 4

    func createTintedImageFromImage(originalImage: UIImage, desiredColor: UIColor) -> UIImage {
        let imageSize = originalImage.size
        let imageScale = originalImage.scale
        let contextBounds = CGRect(origin: .zero, size: imageSize)
    
        UIGraphicsBeginImageContextWithOptions(imageSize, false /* not opaque */, imageScale) // 2
    
        defer { UIGraphicsEndImageContext() }
    
        UIColor.black.setFill() // 3a
        UIRectFill(contextBounds) // 3b
        originalImage.draw(at: .zero) // 4
        guard let imageOverBlack = UIGraphicsGetImageFromCurrentImageContext() else { return originalImage } // 5
        desiredColor.setFill() // 7a
        UIRectFill(contextBounds) // 7b
    
        imageOverBlack.draw(at: .zero, blendMode: .multiply, alpha: 1) // 8
        originalImage.draw(at: .zero, blendMode: .destinationIn, alpha: 1) // 9
    
        guard let finalImage = UIGraphicsGetImageFromCurrentImageContext() else { return originalImage } // 10
    
        return finalImage
    }
    

答案 1 :(得分:2)

有很多方法可以做到这一点。

核心图像过滤器是一种很好的方法。由于您要更改的部分是唯一颜色,因此您可以使用Core图像CIHueAdjust过滤器将色调从蓝色移至红色。只有你想要改变的词有任何颜色,所以它会发生变化。

如果您的图像中包含各种颜色但仍想替换所有图像中的颜色,您可以使用CIColorCube将蓝色像素映射为红色而不影响其他颜色。上周在这个板上有一个线程,使用CIColorCube的示例代码强制一种颜色到另一种颜色。在CIColorCube上搜索并查找最新的帖子,您应该能够找到它。

如果您想将更改限制在屏幕的特定区域,您可能会想出一系列核心图像过滤器,这些过滤器会将您的更改限制在目标区域。

您还可以切出要更改的部分,使用各种技术对其进行颜色编辑,然后将其合并在一起。

答案 2 :(得分:0)

另一种方法是使用CoreImage过滤器 - ColorCube。 遇到这个问题时为自己制作类别。它适用于NSImage,但我认为在更新后应该适用于UIImage https://github.com/braginets/NSImage-replace-color