CreateCGImage CoreImageContext, производящий неправильный CGRect - PullRequest
0 голосов
/ 16 января 2020

Код:

enum GradientDirection {
    case up
    case left
    case upLeft
    case upRight
}

extension SKTexture {
    convenience init(size: CGSize, color1: CIColor, color2: CIColor, direction: GradientDirection = .up) {
        let coreImageContext = CIContext(options: nil)
        let gradientFilter = CIFilter(name: "CILinearGradient")
        gradientFilter!.setDefaults()

        var startVector:CIVector
        var endVector:CIVector

        switch direction {
        case .up:
            startVector = CIVector(x: size.width/2, y: 0)
            endVector = CIVector(x: size.width/2, y: size.height)
        case .left:
            startVector = CIVector(x: size.width, y: size.height/2)
            endVector = CIVector(x: 0, y: size.height/2)
        case .upLeft:
            startVector = CIVector(x: size.width, y: 0)
            endVector = CIVector(x: 0, y: size.height)
        case .upRight:
            startVector = CIVector(x: 0, y: 0)
            endVector = CIVector(x: size.width, y: size.height)

        }
        gradientFilter!.setValue(startVector, forKey: "inputPoint0")
        gradientFilter!.setValue(endVector, forKey: "inputPoint1")
        gradientFilter!.setValue(color1, forKey: "inputColor0")
        gradientFilter!.setValue(color2, forKey: "inputColor1")

        let imgRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        let cgimg = coreImageContext.createCGImage(gradientFilter!.outputImage!, from: imgRect)!

        print("cgimg: ",  cgimg) // *** Observer this output ***** 103.0 width and height

        self.init(cgImage: cgimg)
    }
}

Инициализатор вызова:

// e.g. CGSize(width: 102.69999694824219, height: 102.69999694824219)
let textureSize = CGSize(width: self.frame.width, height: self.frame.height)
let shapeTexture = SKTexture(size: textureSize, color1: bottomColor, color2: topColor, direction: .upRight)

Передача width/height: 102.69999694824219, выдача shapeTexture с width/height: 103. Похоже, что coreImageContext.createCGImage округляет 102.69999694824219 до 103.0.

Это приводит к незначительным неожиданным выводам. Как я могу обойти это округление? Или есть какой-то другой способ создания градиентного изображения для узлов?

Подробнее Код:

class BubbleNode: SKShapeNode {

    private var backgroundNode: SKCropNode!
    var label: SKLabelNode!

    private var state: BubbleNodeState!

    private let BubbleAnimationDuration = 0.2
    private let BubbleIconPercentualInset = 0.4

    var model: BubbleModel! {
        didSet {
            self.label.text = model.name
        }
    }

    override init() {
        super.init()
    }

    convenience init(withRadius radius: CGFloat) {
        self.init()
        self.init(circleOfRadius: radius)
        state = .normal
        self.configure()
    }

    private func configure() {
        self.name = "mybubble"

        physicsBody = SKPhysicsBody(circleOfRadius: 4 + self.path!.boundingBox.size.width / 2.0)

        physicsBody!.isDynamic = true
        physicsBody!.affectedByGravity = false
        physicsBody!.allowsRotation = false
        physicsBody!.mass = 0.3
        physicsBody!.friction = 0.0
        physicsBody!.linearDamping = 3

        backgroundNode = SKCropNode()
        backgroundNode.isUserInteractionEnabled = false
        backgroundNode.position = CGPoint.zero
        backgroundNode.zPosition = 0
        self.addChild(backgroundNode)

        label = SKLabelNode(fontNamed: "")
        label.preferredMaxLayoutWidth = self.frame.size.width - 16
        label.numberOfLines = 0
        label.position = CGPoint.zero
        label.fontColor = .white
        label.fontSize = 10
        label.isUserInteractionEnabled = false
        label.verticalAlignmentMode = .center
        label.horizontalAlignmentMode = .center
        label.zPosition = 2
        self.addChild(label)
    }

    func addGradientNode(withRadius radius: CGFloat) {
        let gradientNode = SKShapeNode(path: self.path!)
        gradientNode.zPosition = 1
        gradientNode.fillColor = .white
        gradientNode.strokeColor = .clear

        let bottomColor = CIColor(red: 0.922, green: 0.256, blue: 0.523, alpha: 1)
        let topColor = CIColor(red: 0.961, green: 0.364, blue: 0.155, alpha: 1)

        let textureSize = CGSize(width: self.frame.width, height: self.frame.height)
        let shapeTexture = SKTexture(size: textureSize, color1: bottomColor, color2: topColor, direction: .upRight)

        gradientNode.fillTexture = shapeTexture

        self.addChild(gradientNode)

        print("path: ", self.path!)
        print("textureSize: ", textureSize)
        print("shapeTexture: ", shapeTexture)
    }
}

1 Ответ

1 голос
/ 16 января 2020

Любое изображение / текстура всегда будет иметь целочисленные размеры, поскольку в памяти нет подпикселей. Таким образом, фреймворки, такие как Core Image, всегда округляют заданный размер до следующего целочисленного значения.

В отличие от этого, frame представления дается в точках , которые необходимо умножить в представлении contentScaleFactor, чтобы получить фактический размер в пикселях (который вы должны использовать для генерации градиента). UIKit также допускает субпиксельные размеры кадра, но под капотом он также округляется при рендеринге видов на экран.

...