对于黑白文本
如果您使用.normal
合成操作,您肯定会得到与使用.hardLight
. 您的图片显示了.hardLight
操作的结果。
.normal
操作是经典OVER
运算,公式为:(Image1 * A1) + (Image2 * (1 – A1))。
这是一个预乘文本 (RGB*A),因此在这种特殊情况下,RGB 模式取决于 A 的不透明度。文本图像的 RGB 可以包含任何颜色,包括黑色。如果 A=0(黑色 alpha)和 RGB=0(黑色)并且你的图像是预乘的——整个图像是完全透明的,如果 A=1(白色 alpha)和 RGB=0(黑色)——图像是不透明的黑色的。
如果您在使用.normal
操作时文本没有 alpha,我会得到ADD
op: Image1 + Image2。
为了得到你想要的,你需要设置一个合成操作到.hardLight
.
.hardLight
合成操作作为.multiply
如果文本图像的 alpha 小于 50%(A < 0.5,图像几乎是透明的)
公式.multiply
:Image1 * Image2
.hardLight
合成操作作为.screen
如果文本图像的 alpha 大于或等于 50%(A >= 0.5,则图像是半透明的)
公式 1 .screen
:(Image1 + Image2) – (Image1 * Image2)
公式 2 .screen
:1 – (1 – Image1) * (1 – Image2)
.screen
操作的结果比 更柔和.plus
,并且它允许保持 alpha 不大于 1(plus
操作添加 Image1 和 Image2 的 alpha,因此如果您有两个 alpha,您可能会得到 alpha = 2)。.screen
合成操作有利于制作反射。

func editImage() {
print("Drawing image with \(selectedOpacity) alpha")
let text = "hello world"
let backgroundCGImage = #imageLiteral(resourceName: "background").cgImage!
let backgroundImage = CIImage(cgImage: backgroundCGImage)
let imageRect = backgroundImage.extent
//set up transparent context and draw text on top
let colorSpace = CGColorSpaceCreateDeviceRGB()
let alphaInfo = CGImageAlphaInfo.premultipliedLast.rawValue
let bitmapContext = CGContext(data: nil, width: Int(imageRect.width), height: Int(imageRect.height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: alphaInfo)!
bitmapContext.draw(backgroundCGImage, in: imageRect)
bitmapContext.setAlpha(CGFloat(selectedOpacity))
bitmapContext.setTextDrawingMode(.fill)
//TRY THREE COMPOSITING OPERATIONS HERE
bitmapContext.setBlendMode(.hardLight)
//bitmapContext.setBlendMode(.multiply)
//bitmapContext.setBlendMode(.screen)
//white text
bitmapContext.textPosition = CGPoint(x: 15 * UIScreen.main.scale, y: (20 + 60) * UIScreen.main.scale)
let displayLineTextWhite = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 58 * UIScreen.main.scale)]))
CTLineDraw(displayLineTextWhite, bitmapContext)
//black text
bitmapContext.textPosition = CGPoint(x: 15 * UIScreen.main.scale, y: 20 * UIScreen.main.scale)
let displayLineTextBlack = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 58 * UIScreen.main.scale)]))
CTLineDraw(displayLineTextBlack, bitmapContext)
let outputImage = bitmapContext.makeImage()!
topImageView.image = UIImage(cgImage: outputImage)
}
因此,要重新创建此合成操作,您需要以下逻辑:
//rgb1 – text image
//rgb2 - background
//a1 - alpha of text image
if a1 >= 0.5 {
//use this formula for compositing: 1–(1–rgb1)*(1–rgb2)
} else {
//use this formula for compositing: rgb1*rgb2
}
我使用合成应用程序 The Foundry NUKE 11 重新创建了一个图像。这里的 Offset=0.5 是 Add=0.5。
我使用属性Offset=0.5
是因为transparency=0.5
它是一种pivot point
合成.hardLight
操作。


彩色文本
.sourceAtop
如果除了黑白文本之外还有橙色(或任何其他颜色)文本,则需要使用合成操作。应用您让 Swift 使用背景图像的亮度来确定要显示的内容.sourceAtop
的方法案例。.setBlendMode
或者,您可以使用CISourceAtopCompositing
核心图像过滤器而不是CISourceOverCompositing
.
bitmapContext.setBlendMode(.sourceAtop)
或者
let compositingFilter = CIFilter(name: "CISourceAtopCompositing")
.sourceAtop
运算公式如下:(Image1 * A2) + (Image2 * (1 – A1))。如您所见,您需要两个 Alpha 通道:A1 是文本的 Alpha,A2 是背景图像的 Alpha。
bitmapContext.textPosition = CGPoint(x: 15 * UIScreen.main.scale, y: (20 + 60) * UIScreen.main.scale)
let displayLineTextOrange = CTLineCreateWithAttributedString(NSAttributedString(string: text, attributes: [.foregroundColor: UIColor.orange, .font: UIFont.systemFont(ofSize: 58 * UIScreen.main.scale)]))
CTLineDraw(displayLineTextOrange, bitmapContext)

