Представления, нарисованные из кода (PaintCode), пикселизированы, очень пикселизированы при масштабировании.

Я создаю приложение, которое накладывает изображения, нарисованные с помощью кода (вывод из 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))

person aaronfalls    schedule 23.03.2017    source источник
comment
Есть ли подход с PaintCode, который позволит вам полностью избежать растеризации?   -  person Chris Droukas    schedule 23.03.2017
comment
Эй, небольшой вопрос, так как у вас определена статическая шкала (установлена ​​на 2). Учитываете ли вы для этого [UIScreen mainScreen].scale? Мне кажется, ваш растр не подходит к разрешению ретины? Просто грубое предположение, т.   -  person Lepidopteron    schedule 23.03.2017
comment
@ChrisDroukas Насколько я понимаю, PaintCode использует координаты для рисования, но не растрирует. Добавление функции рисования выше...   -  person aaronfalls    schedule 23.03.2017
comment
@Lepidopteron Если я установлю масштаб, например, на 4,0, результат будет больше, но пикселизация будет такой же.   -  person aaronfalls    schedule 23.03.2017
comment
Вам нужно масштабировать границы вашего UIGraphicsImageRenderer. Вероятно, раз масштаб экрана   -  person Leo Dabus    schedule 23.03.2017
comment
Вы пытались растеризовать слой вида? view.layer.shouldRasterize = true   -  person Lepidopteron    schedule 23.03.2017
comment
@LeoDabus Спасибо за ответ. В начале расширения UIView я создаю UIGraphicsImageRendererFormat, устанавливаю для этого масштаба значение 2 и передаю его в средство визуализации. Я только что попытался установить масштаб на 6, и пикселизация такая же. Есть ли другой способ масштабировать границы UIGraphicsImageRenderer?   -  person aaronfalls    schedule 23.03.2017
comment
@Lepidopteron Спасибо, я попробовал это (установив его в viewDidLoad), но результаты не менее пикселизированы.   -  person aaronfalls    schedule 23.03.2017
comment
Используете ли вы где-нибудь UIGraphicsBeginImageContext* вместо UIGraphicsBeginImageContextWithOptions с правильными параметрами? Потому что это привело бы к коэффициенту масштабирования, равному 1, вместо того, чтобы коэффициент корректировался в соответствии с масштабом дисплея. Подробно посмотрите здесь: заголовок stackoverflow.com/questions/4334233/   -  person Lepidopteron    schedule 23.03.2017
comment
@Lepidopteron Я только что искал в проекте и нигде не использую UIGraphicsBeginImageContext.   -  person aaronfalls    schedule 23.03.2017
comment
Пикселизация видна в живом просмотре или только после создания изображения? Используете ли вы метод рисования или метод изображения из PaintCode? Используете ли вы shouldRasterize в любом из этих представлений?   -  person Tricertops    schedule 24.03.2017
comment
И просто очевидная проверка: создается ли оверлей в PaintCode с использованием изображения или с использованием путей Безье?   -  person Tricertops    schedule 24.03.2017
comment
@Tricertops Наложение создается с использованием путей Безье (методы рисования из выходных данных PaintCode, а не изображений). Я не звоню в shouldRasterize, должен ли я звонить кому-то из них?   -  person aaronfalls    schedule 24.03.2017
comment
@aaronfalls Нет, не включайте растеризацию, но у нее есть собственный масштаб растеризации, который может быть установлен неправильно. Кажется, я знаю, в чем проблема, я напишу ответ.   -  person Tricertops    schedule 24.03.2017


Ответы (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

person Tricertops    schedule 24.03.2017
comment
Спасибо за ответ! У меня почему-то view.layer.contentsScale = UIScreen.main.scale * recognizer.scale не работала функция распознавания жестов. Основываясь на вашем объяснении, я немного поэкспериментировал, и view.contentScaleFactor = view.contentScaleFactor * recognizer.scale работает отлично — четко, независимо от масштаба. Я также пытался использовать view.contentScaleFactor = UIScreen.main.scale * recognizer.scale, но это не сработало. - person aaronfalls; 24.03.2017
comment
@aaronfalls Вероятно, это потому, что вы сбрасываете значение масштаба после каждого изменения, используя recognizer.scale = 1. Я бы не стал этого делать. - person Tricertops; 03.05.2017