CATextLayer на пикселизированном тексте видео

Я создаю видео из изображений и добавляю к ним наложение. Проблема в том, что я пытаюсь добавить CATextLayer в видео. Текст пикселизирован, взгляните на изображение

изображение

Это код, используемый для генерации CATextLayer:

private func generateTextLayer(for text: String, at frame: CGRect, in layer: CALayer) -> CATextLayer {
    let textLayer = CATextLayer()

    textLayer.frame = frame.integral
    textLayer.contentsScale = UIScreen.main.scale

    textLayer.isWrapped = true
    textLayer.isHidden = true

    textLayer.foregroundColor = UIColor.white.cgColor
    textLayer.backgroundColor = UIColor.clear.cgColor

    let fontHeight = resolution.fontHeight
    textLayer.font = UIFont.systemFont(ofSize: fontHeight)
    textLayer.fontSize = fontHeight

    textLayer.string = text

    textLayer.truncationMode = .end
    textLayer.alignmentMode = .center

    textLayer.contentsScale = UIScreen.main.scale

    layer.addSublayer(textLayer)

    return textLayer
}

И этот код используется для генерации CALayer с изображением:

private func generateImageLayer(for image: CGImage?, at frame: CGRect, in layer: CALayer) -> CALayer {
    let imageLayer = CALayer()
    imageLayer.frame = frame.integral

    imageLayer.contents = image
    imageLayer.contentsGravity = .resizeAspectFill

    imageLayer.isHidden = true

    imageLayer.backgroundColor = UIColor.clear.cgColor

    layer.addSublayer(imageLayer)

    return imageLayer
}

Слой изображения скрыт из-за анимации различных слоев изображения в сгенерированном видео. Это код, используемый для генерации слоя:

    let size = backgroundTrack.naturalSize.applying(backgroundTrack.preferredTransform)

    let parentlayer = CALayer()
    parentlayer.frame = CGRect(origin: .zero, size: size).integral
    parentlayer.backgroundColor = UIColor.black.cgColor
    parentlayer.isOpaque = true

    let backgroundVideoLayer = CALayer()
    backgroundVideoLayer.frame = parentlayer.bounds
    backgroundVideoLayer.backgroundColor = UIColor.black.cgColor
    backgroundVideoLayer.isOpaque = true

    parentlayer.addSublayer(backgroundVideoLayer)

    var currentTime: Double = 0
    for source in videoSources {

        // This will generate blurred background layer
        let blurrLayer = generateImageLayer(for: source.blurredImage, at: backgroundVideoLayer.bounds, in: backgroundVideoLayer)
        blurrLayer.contentsGravity = .resizeAspectFill

        // Adds image to blurrLayer
        if let image = source.image { 
            let frame = calculateFrame(for: image.size)
            let imageLayer = generateImageLayer(for: image.cgImage, at: frame, in: blurrLayer)
            imageLayer.isHidden = false

            Animations.fadeInOut(layer: blurrLayer, beginTime: currentTime, duration: duration.value)
        }

        // Adds CATextLayer 
        if let text = source.title {
            let frame = parentlayer.bounds.offsetBy(dx: 0, dy: 100)

            let titleLayer = generateTextLayer(for: text, at: frame, in: parentlayer)

            Animations.fadeInOut(layer: titleLayer, beginTime: currentTime, duration: duration.value)
        }

        currentTime += duration.value
    }

Я попытался установить rasterizationScale в UIScreen.main.scale, shouldRasterize в true, contentScale в UIScreen.main.scale, всевозможные варианты, даже пытался сделать снимок UILabel и установить его как изображение (даже сохранил изображение локально и проверил его, качество было хорошим ), но в результате снова получается пикселизированное письмо.

Animate fadeInOut состоит из трех анимаций, одна из которых устанавливает для скрытого параметра значение true или false, а другая добавляет анимацию раскрытия CATransition для перехода между слоями при входе и выходе.

    static func fadeInOut(layer: CALayer, beginTime: Double, duration: Double, skipEntry: Bool = false) {
    let t = beginTime < 1 ? -0.0001 : beginTime
    let d = beginTime < 1 ? duration + 0.0001 : duration - 0.0001

    if !skipEntry {
        let entryTransition = CATransition()

        entryTransition.beginTime = t
        entryTransition.duration = 0.5

        entryTransition.type = CATransitionType.reveal
        entryTransition.subtype = CATransitionSubtype.fromTop

        entryTransition.isRemovedOnCompletion = false
        layer.add(entryTransition, forKey: "entry")
    }

    let exitTransition = CATransition()

    exitTransition.beginTime = d - 0.5
    exitTransition.duration = 0.5

    exitTransition.startProgress = 1
    exitTransition.endProgress = 0

    exitTransition.type = CATransitionType.reveal
    exitTransition.subtype = CATransitionSubtype.fromTop

    exitTransition.isRemovedOnCompletion = false
    layer.add(exitTransition, forKey: "exit")

    let fadeInOutAnimation = CABasicAnimation(keyPath: "hidden")
    fadeInOutAnimation.fromValue = false
    fadeInOutAnimation.toValue = false

    fadeInOutAnimation.beginTime = t
    fadeInOutAnimation.duration = d

    fadeInOutAnimation.isRemovedOnCompletion = false
    layer.add(fadeInOutAnimation, forKey: "opacity")
}

Прежде чем пометить мой вопрос как уже просмотренный и ответный, я потратил много времени, пытаясь найти возможные результаты в Google, и пробовал много вещей, но результаты все те же.


person Baki    schedule 16.04.2020    source источник
comment
Также я попытался установить целую кучу параметров для родительских слоев, но это не дало никакого успеха.   -  person Baki    schedule 16.04.2020
comment
Попробуйте установить для textLayer.backgroundColor черный цвет вместо прозрачного. Пикселизация может быть проблемой из-за прозрачности.   -  person hlozancic    schedule 16.04.2020
comment
Тоже пробовал, не помогает   -  person Baki    schedule 16.04.2020


Ответы (2)


Попробуйте поиграть со свойством .contentsScale. Я думаю, что видео отображается в масштабе videoComposition, а не в UIScreen.main.scale.

person Максим Котляр    schedule 19.05.2020

Поэтому, чтобы получить изображение или текст хорошего качества при создании видео, нужно обратить внимание на contentScale, чтобы установить его равным 1. Другой проблемой, с которой я столкнулся, была проблема с некоторыми кадрами, где UIImageView или UITextField могли масштабировать все, чтобы выглядеть четким. в то время как contentMode позаботится обо всем, работая с логикой видео для создания видео, разработчик должен уделять этому особое внимание.

Под этим я подразумеваю, что если изображение больше кадра слоя, изображение уменьшится, но будет выглядеть пиксельным. Предоставив слою ту же рамку, что и изображение, изображение будет хорошо выглядеть. Это особенно заметно на изображениях с водяными знаками, где мы поместили изображение в активы с размером 1x, 2x и 3x. После получения этого изображения с помощью UIImage (с именем: «my_watermark») оно будет загружать 3-кратное измерение, а нам нужно было 1-кратное измерение для видео из-за масштаба видео == 1. Удаление 2-кратного и 3-кратного измерения решило эту проблему.

Когда мы узнали об этом, мы продолжили те же тесты для CATextLayer, поэтому установка contentScale в 1 и забота о кадре сделали свое дело.

Видео, созданное по этой логике, имело хорошее качество как текста, так и изображения внутри. На самом деле самой большой проблемой было время, необходимое для проверки результатов вывода после игры с настройками, где создание видео занимало некоторое время, а затем перенос его на больший экран для проверки занимал много времени.

Надеюсь, этот ответ поможет кому-то!

person Baki    schedule 21.05.2020