如何使用 alpha 通道 - PNG(替换颜色)仅对 UIImage 的一部分着色?
How to tint only one part of the UIImage with alpha channel - PNG (replacing color)?
我有这张透明图片:
我的目标是改变 "ME!" 部件的颜色。只对图像的最后 3 部分着色,或者用新颜色替换蓝色。
换色后的预期效果:
不幸的是,这两个都不适合我。要更改特定颜色,我尝试了以下方法:LINK,但正如文档所述,这仅在没有 alpha 通道的情况下有效!
然后我尝试了这个:LINK,但这实际上什么也没做,没有色调或任何东西。
是否有任何其他方法可以只对颜色的一部分着色或只替换特定颜色?
我知道我可以将图像分成两部分,但我希望有另一种方法。
有很多方法可以做到这一点。
我想到核心图像过滤器是一个不错的选择。由于您要更改的部分是一种独特的颜色,因此您可以使用 Core image CIHueAdjust 过滤器将色调从蓝色变为红色。只有您要更改的字词有任何颜色,所以这就是它会更改的全部内容。
如果您有一张包含各种颜色的图像,但仍想替换图像中的所有颜色,您可以使用 CIColorCube 将蓝色像素映射到红色,而不影响其他颜色。上周这个板上有一个线程,其中包含使用 CIColorCube 将一种颜色强制转换为另一种颜色的示例代码。在 CIColorCube 上搜索并查找最新的 post,您应该能够找到它。
如果您想将更改限制在屏幕的特定区域,您可能会想出一系列核心图像过滤器,将您的更改限制在目标区域。
您也可以切出要更改的部分,使用各种技术对其进行颜色编辑,然后将其重新组合在一起。
事实证明它出奇地复杂——你认为你可以使用 CoreGraphics 混合模式一次完成它,但是从相当广泛的实验中我还没有找到这样一种不会破坏 alpha 通道的方法或着色。我找到的解决方案是:
- 从图像的 grayscale/alpha 版本开始,而不是彩色版本:您不想着色的区域为黑色,您想要着色的区域为白色
- 使用图像尺寸创建图像上下文
- 用黑色填充上下文
- 将图像绘制到上下文中
- 从该上下文中获取新图像(我们称其为“the-image-over-black”)
- 清除上下文(以便您可以再次使用它)
- 使用您希望图像着色部分的颜色填充上下文
- 使用“乘法”混合模式将黑色图像绘制到上下文中
- 使用“destination in”混合模式将原始图像绘制到上下文中
- 从上下文中获取最终图像
之所以可行,是因为混合模式的组合。您正在做的是创建一个完全不透明的黑白图像(第 5 步),然后将其乘以您的最终颜色(第 8 步),这将为您提供一个完全不透明的黑白图像和您的最终彩色图像.然后,您获取仍然具有其 alpha 通道的原始图像,并使用“目标输入”混合模式绘制它,该混合模式从黑白图像中获取颜色,并从原始图像中获取 alpha 通道。结果是具有原始亮度值和 alpha 通道的着色图像。
Objective-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
}
另一种方法是使用 CoreImage 滤镜 - ColorCube。
遇到这个问题时为自己制作类别。它适用于 NSImage,但我认为在更新后应该适用于 UIImage
https://github.com/braginets/NSImage-replace-color
我有这张透明图片:
我的目标是改变 "ME!" 部件的颜色。只对图像的最后 3 部分着色,或者用新颜色替换蓝色。
换色后的预期效果:
不幸的是,这两个都不适合我。要更改特定颜色,我尝试了以下方法:LINK,但正如文档所述,这仅在没有 alpha 通道的情况下有效!
然后我尝试了这个:LINK,但这实际上什么也没做,没有色调或任何东西。
是否有任何其他方法可以只对颜色的一部分着色或只替换特定颜色?
我知道我可以将图像分成两部分,但我希望有另一种方法。
有很多方法可以做到这一点。
我想到核心图像过滤器是一个不错的选择。由于您要更改的部分是一种独特的颜色,因此您可以使用 Core image CIHueAdjust 过滤器将色调从蓝色变为红色。只有您要更改的字词有任何颜色,所以这就是它会更改的全部内容。
如果您有一张包含各种颜色的图像,但仍想替换图像中的所有颜色,您可以使用 CIColorCube 将蓝色像素映射到红色,而不影响其他颜色。上周这个板上有一个线程,其中包含使用 CIColorCube 将一种颜色强制转换为另一种颜色的示例代码。在 CIColorCube 上搜索并查找最新的 post,您应该能够找到它。
如果您想将更改限制在屏幕的特定区域,您可能会想出一系列核心图像过滤器,将您的更改限制在目标区域。
您也可以切出要更改的部分,使用各种技术对其进行颜色编辑,然后将其重新组合在一起。
事实证明它出奇地复杂——你认为你可以使用 CoreGraphics 混合模式一次完成它,但是从相当广泛的实验中我还没有找到这样一种不会破坏 alpha 通道的方法或着色。我找到的解决方案是:
- 从图像的 grayscale/alpha 版本开始,而不是彩色版本:您不想着色的区域为黑色,您想要着色的区域为白色
- 使用图像尺寸创建图像上下文
- 用黑色填充上下文
- 将图像绘制到上下文中
- 从该上下文中获取新图像(我们称其为“the-image-over-black”)
- 清除上下文(以便您可以再次使用它)
- 使用您希望图像着色部分的颜色填充上下文
- 使用“乘法”混合模式将黑色图像绘制到上下文中
- 使用“destination in”混合模式将原始图像绘制到上下文中
- 从上下文中获取最终图像
之所以可行,是因为混合模式的组合。您正在做的是创建一个完全不透明的黑白图像(第 5 步),然后将其乘以您的最终颜色(第 8 步),这将为您提供一个完全不透明的黑白图像和您的最终彩色图像.然后,您获取仍然具有其 alpha 通道的原始图像,并使用“目标输入”混合模式绘制它,该混合模式从黑白图像中获取颜色,并从原始图像中获取 alpha 通道。结果是具有原始亮度值和 alpha 通道的着色图像。
Objective-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
}
另一种方法是使用 CoreImage 滤镜 - ColorCube。 遇到这个问题时为自己制作类别。它适用于 NSImage,但我认为在更新后应该适用于 UIImage https://github.com/braginets/NSImage-replace-color