从代码(PaintCode)绘制的视图是像素化的,缩放时非常像素化

Posted

技术标签:

【中文标题】从代码(PaintCode)绘制的视图是像素化的,缩放时非常像素化【英文标题】:Views drawn from code (PaintCode) are pixelated, very pixelated when scaled 【发布时间】:2017-03-23 14:02:47 【问题描述】:

我正在构建一个应用程序,它将使用代码(从 PaintCode 输出)绘制的视图覆盖到照片上。我添加了手势识别器来旋转和缩放用代码绘制的视图。

顶部绘制的视图有一些轻微的像素化。如果我对图像进行任何旋转或缩放(甚至稍微放大一点),就会出现更多像素化。

图片对比如下:

无旋转或缩放:

少量旋转/缩放:

这是我用来输出合成视图的 UIView 扩展:

extension UIView 

    func printViewToImage() -> UIImage 
        let format = UIGraphicsImageRendererFormat()
        format.scale = 2.0

        let renderer = UIGraphicsImageRenderer(bounds: self.bounds, format: format)
        return renderer.image  rendererContext in
            self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
        
    

即使我将比例设置为 4.0 之类的,也没有区别。

这是我用于缩放/旋转手势识别器的代码:

@IBAction func handlePinch(recognizer: UIPinchGestureRecognizer) 
    guard let view = recognizer.view else 
        return
    

    view.transform = view.transform.scaledBy(x: recognizer.scale, y: recognizer.scale)
    recognizer.scale = 1


@IBAction func handleRotate(recognizer: UIRotationGestureRecognizer) 
    guard let view = recognizer.view else 
        return
    

    view.transform = view.transform.rotated(by: recognizer.rotation)
    recognizer.rotation = 0

我已经尝试在 PaintCode (3000x3000) 中使画布非常大,并且没有区别,所以我认为与此无关。

如何绘制/导出这些视图以使其不被像素化?

编辑:下面是一些绘图代码的样子...

public dynamic class func drawCelebrateDiversity(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 3000, height: 3000), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) 
    //// General Declarations
    let context = UIGraphicsGetCurrentContext()!

    //// Resize to Target Frame
    context.saveGState()
    let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 3000, height: 3000), target: targetFrame)
    context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY)
    context.scaleBy(x: resizedFrame.width / 3000, y: resizedFrame.height / 3000)


    //// Bezier 13 Drawing
    let bezier13Path = UIBezierPath()
    bezier13Path.move(to: CGPoint(x: 2915.18, y: 2146.51))
    bezier13Path.addCurve(to: CGPoint(x: 2925.95, y: 2152.38), controlPoint1: CGPoint(x: 2919.93, y: 2147.45), controlPoint2: CGPoint(x: 2924.05, y: 2147.91))

【问题讨论】:

有没有一种使用 PaintCode 的方法可以让您完全避免光栅化? 嘿,只是一个简短的问题,因为您定义了一个静态比例(设置为 2)。您是否为此考虑了 [UIScreen mainScreen].scale ?我认为您的光栅不适合视网膜分辨率?只是粗略的猜测。 @ChrisDroukas 据我了解,PaintCode 使用坐标进行绘图,但未光栅化。在上面添加一点绘图功能... @Lepidopteron 例如,如果我将比例设置为 4.0,输出会更大,但像素化看起来是一样的。 您需要缩放 UIGraphicsImageRenderer 的边界。可能是屏幕比例的倍数 【参考方案1】:

在缩放 UIView(或自定义 CALayers)时,您应该设置它们的 contentsScale 以匹配所需的内容密度。 UIViews 将它们的层 contentsScale 设置为屏幕比例(视网膜上为 2),您需要将其与通过变换所做的额外比例相乘。

view.layer.contentsScale = UIScreen.main.scale * gesture.scale;

即使绘图代码与分辨率无关,屏幕上的所有内容也必须在某个时候转换为位图。 UIView分配大小为bounds.size * contentsScale的位图,然后调用-drawRect:/draw(_ rect:)方法。

在绘制的视图上设置contentsScale 很重要,即使该视图没有缩放(但它的某些父视图是缩放的)。一种常见的解决方案是在缩放视图的所有子层上递归设置contentsScale

– PaintCode 支持

【讨论】:

感谢您的回复!出于某种原因,view.layer.contentsScale = UIScreen.main.scale * recognizer.scale 在手势识别器功能中对我不起作用。根据你的解释,我做了一些实验,view.contentScaleFactor = view.contentScaleFactor * recognizer.scale 工作得很好——不管它有多大的比例都很清晰。我也尝试过使用view.contentScaleFactor = UIScreen.main.scale * recognizer.scale,但是没有用。 @aaronfalls 这可能是因为您在每次更改后使用 recognizer.scale = 1 重置了比例值。我不会那样做的。

以上是关于从代码(PaintCode)绘制的视图是像素化的,缩放时非常像素化的主要内容,如果未能解决你的问题,请参考以下文章

使用 PaintCode 自定义 UiProgressView

PaintCode 鼠标绘图转CGPath代码

从 PaintCode 强制自定义 NSView 重绘

如何访问使用 Paintcode 生成的 UIView 自定义类中的图层?

Objective C - 从这个 PaintCode 代码创建 UIImage

如何从 UICollectionView 的另一个类中的函数加载图像?我正在使用油漆代码