CoreImageContext 的 CreateCGImage 产生错误的 CGRect
Posted
技术标签:
【中文标题】CoreImageContext 的 CreateCGImage 产生错误的 CGRect【英文标题】:CoreImageContext's CreateCGImage producing wrong CGRect 【发布时间】:2020-01-16 14:03:46 【问题描述】:代码:
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)
【问题讨论】:
与您的问题无关,但为什么不简单地frame.size
?
@LeoDabus - 抱歉没有找到你
顺便说一句,一个接一个地调用两个init
s 不是一个好主意。你真的应该只需要在那里打电话给self.init(circleOfRadius: radius)
。
你是对的,但是这是一种奇怪的弥补方式。您可以尝试删除该初始化,但会引发错误。看到一些类似的帖子,因此来实现。
【参考方案1】:
任何图像/纹理将始终具有整数大小,因为内存中没有子像素。所以像 Core Image 这样的框架总是会将给定的大小四舍五入到下一个整数值。
相比之下,视图的frame
以points 的形式给出,需要乘以视图的contentScaleFactor
才能得到实际的像素大小(您应该使用它来生成您的坡度)。 UIKit 还允许亚像素帧大小,但在底层,它也会在将视图渲染到屏幕时四舍五入。
【讨论】:
有什么方法可以让我的渐变图像获得准确的尺寸? 嗯,图像需要有谨慎的(整数)像素大小——没有半像素。我认为更多的是视图框架有点偏离。你怎么得到那些奇怪的数字?你在应用仿射变换吗? 我添加了一些更相关的代码,这些代码创建了一个具有给定半径的 Shape 节点。 我明白你的意思,如果没有变通办法,我应该专注于创建一个带有圆角矩形的节点,以免碰到图像的圆角吗?self.path!.boundingBox
是什么?这听起来像是代替frame
的好选择。您还可以使用创建节点的半径来确定渐变纹理的大小。以上是关于CoreImageContext 的 CreateCGImage 产生错误的 CGRect的主要内容,如果未能解决你的问题,请参考以下文章
[原创] Delphi Create(Application) 和 Create(nil) 的区别
android的MediaPlayer.create方法怎么用
delphi7中create(nil)与create(self)区别
link_to :action => 'create' 去索引而不是 'create'