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

Dej*_*dar 4 objective-c uiimage uicolor ios swift

我有这个透明图像:

在此处输入图片说明

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

换色后的预期效果:

在此处输入图片说明

不幸的是,两者都不适合我。要更改特定颜色,我试过这个:LINK,但正如文档所说,这只适用于没有 alpha 通道!

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

有没有其他方法可以只着色颜色的一部分或只替换特定颜色?

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

Noa*_*oon 5

事实证明,结果出奇地复杂——你可能认为你可以通过 CoreGraphics 混合模式一次性完成,但从相当广泛的实验中,我还没有找到一种不会破坏 alpha 通道或着色的方法。我登陆的解决方案是这样的:

  1. 从图像的灰度/alpha 版本而不是彩色图像开始:您不想着色的区域为黑色,您需要着色的区域为白色
  2. 使用图像的尺寸创建图像上下文
  3. 用黑色填充上下文
  4. 将图像绘制到上下文中
  5. 从该上下文中获取新图像(我们称之为“黑色图像”)
  6. 清除上下文(以便您可以再次使用它)
  7. 用您希望图像着色部分的颜色填充上下文
  8. 使用“乘法”混合模式将黑色图像绘制到上下文中
  9. 使用“destination in”混合模式将原始图像绘制到上下文中
  10. 从上下文中获取最终图像

这样做的原因是混合模式的组合。您正在做的是创建一个完全不透明的黑白图像(第 5 步),然后将其乘以您的最终颜色(第 8 步),这将为您提供一个完全不透明的黑色和您的最终颜色图像. 然后,您获取仍然具有 Alpha 通道的原始图像,并使用“destination in”混合模式绘制它,该模式从黑白图像中获取颜色,从原始图像中获取 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;
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特 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
}
Run Code Online (Sandbox Code Playgroud)