ДЛЯ ЧЕРНО-БЕЛОГО ТЕКСТА
Если вы используете операцию композитинга .normal
, вы определенно получите не такой результат, как при использовании .hardLight
. На вашей картинке показан результат .hardLight
операции.
.normal
операция является классической OVER
операцией с формулой: (Изображение1 * A1) + (Изображение2 * (1 – A1)).
Вот предварительно умноженный текст (RGB * A), поэтому шаблон RGB зависит от непрозрачности A в этом конкретном случае. RGB текстового изображения может содержать любой цвет, в том числе и черный. Если A=0 (черный альфа-канал) и RGB=0 (черный цвет) и ваше изображение предварительно умножено – все изображение полностью прозрачно, если A=1 (белый альфа-канал) и RGB=0 (черный цвет) – изображение непрозрачно чернить.
Если ваш текст не имеет альфа-канала при использовании операции .normal
, я получу операцию ADD
: Изображение1 + Изображение2.
Чтобы получить то, что вы хотите, вам нужно настроить операцию композитинга на .hardLight
.
.hardLight
операция композитинга работает как .multiply
если альфа текстового изображения менее 50 процентов (A ‹ 0,5, изображение почти прозрачное)
Формула для .multiply
: Изображение1 * Изображение2
.hardLight
операция композитинга работает как .screen
если альфа текстового изображения больше или равна 50 процентам (A >= 0,5, изображение полупрозрачное)
Формула 1 для .screen
: (Изображение1 + Изображение2) – (Изображение1 * Изображение2)
Формула 2 для .screen
: 1 – (1 – Изображение1) * (1 – Изображение2)
Операция .screen
имеет гораздо более мягкий результат, чем .plus
, и позволяет сохранить альфу не больше 1 (операция plus
добавляет альфы Image1 и Image2, так что вы можете получить 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. Смещение = 0,5, здесь Add = 0,5.
Я использовал свойство Offset=0.5
, потому что transparency=0.5
является операцией композитинга pivot point
из .hardLight
.
ДЛЯ ЦВЕТНОГО ТЕКСТА
Вам нужно использовать операцию композитинга .sourceAtop
, если у вас есть текст ОРАНЖЕВОГО (или любого другого цвета) в дополнение к черно-белому тексту. Применяя .sourceAtop
случай метода .setBlendMode
, вы заставляете Swift использовать яркость фонового изображения, чтобы определить, что показывать. В качестве альтернативы вы можете использовать базовый фильтр изображения CISourceAtopCompositing
вместо CISourceOverCompositing
.
bitmapContext.setBlendMode(.sourceAtop)
or
let compositingFilter = CIFilter(name: "CISourceAtopCompositing")
.sourceAtop
операция имеет следующую формулу: (Изображение1 * A2) + (Изображение2 * (1 – A1)). Как видите, вам нужны два альфа-канала: A1 — это альфа-канал для текста, а A2 — альфа-канал для фонового изображения.
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)
person
Andy Fedoroff
schedule
06.03.2018