Как создать изображение указанного c размера из UIView - PullRequest
1 голос
/ 16 апреля 2020

Я работаю над приложением iOS, которое должно позволить пользователям создавать фотографии из Instagram и экспортировать их в Instagram. В основном приложения, такие как «Развернуть», «Звездная история», «Истории Chroma» ... Я подготовил пользовательский интерфейс, в котором пользователь может выбирать из готовых шаблонов и добавлять к ним собственные фотографии с фильтрами, метками и т. Д. c.

Мой вопрос - Каков наилучший способ экспорта созданного UIView в увеличенное изображение? Я имею в виду, как получить наилучшее качество, четкие пиксели надписей и т. Д. c? Поскольку представление шаблона с подпредставлениями (добавленные фотографии, метки ...) занимает + - половину экрана устройства. Но мне нужен больший размер для экспортируемого изображения. В настоящее время я использую:

 func makeImageFromView() -> UIImage {
    let format = UIGraphicsImageRendererFormat()
    let size = CGSize(width: 1080 / format.scale, height: 1920 / format.scale)

    let renderer = UIGraphicsImageRenderer(size: size, format: format)
    let image = renderer.image { (ctx) in
        templateView.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)
    }
    return image
}

Полученное изображение имеет размер 1080 x 1920, но метки не четкие. Нужно ли как-то масштабировать фотографию и размер шрифта, прежде чем переходить к изображению? Спасибо!

1 Ответ

0 голосов
/ 20 апреля 2020

Так что на самом деле да, перед съемкой изображения Мне нужно масштабировать весь вид и его подпредставления . Вот мои выводы (возможно, очевидные вещи, но мне потребовалось время, чтобы осознать это - я буду рад любым улучшениям)

Рендеринг изображения того же размера

Когда вы хотите сделать снимок UIView как изображение, вы можете просто использовать эту функцию. Полученное изображение будет иметь тот же размер, что и вид (масштабируется 2x / 3x в зависимости от фактического устройства)

 func makeImageFrom(_ desiredView: MyView) -> UIImage {
    let size = CGSize(width: desiredView.bounds.width, height: desiredView.bounds.height)
    let renderer = UIGraphicsImageRenderer(size: size)
    let image = renderer.image { (ctx) in
        desiredView.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)
    }
    return image
}

Rendering view to image – same size

Рендеринг изображения другого размера

Но что делать, если вы хотите указать определенный c размер для экспортируемого изображения? Поэтому из моего сценария использования я хотел визуализировать изображение окончательного размера (1080 x 1920), но изображение, которое я хотел захватить, имело меньший размер (в моем случае 275 x 487). Если вы выполняете такой рендеринг без чего-либо, это может привести к потере качества.

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

func makeImageFrom(_ desiredView: MyView) -> UIImage {
    let format = UIGraphicsImageRendererFormat()
    // We need to divide desired size with renderer scale, otherwise you get output size larger @2x or @3x
    let size = CGSize(width: 1080 / format.scale, height: 1920 / format.scale)

    let renderer = UIGraphicsImageRenderer(size: size, format: format)
    let image = renderer.image { (ctx) in
    // remake constraints or change size of desiredView to 1080 x 1920
    // handle it's subviews (update font size etc.)
    // ...
    desiredView.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)
    // undo the size changes
    // ...
    }
    return image
}

Rendering view to image – bigger size

Мой подход

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

Важное примечание!

Вам действительно нужно позаботиться о подпредставлениях. Это означает, что вам нужно увеличить размер шрифта, обновить позицию перемещенных подпредставлений (например, их центр) и т. Д. c.! Вот лишь несколько строк, чтобы проиллюстрировать это:

        // 1. Create bigger view
        let hdView = MyView()
        hdView.frame = CGRect(x: 0, y: 0, width: 1080, height: 1920)

        // 2. Load content according to the original view (desiredView)
        // set text, images...

        // 3. Scale subviews
        // Find out what scale we need
        let scaleMultiplier: CGFloat = 1080 / desiredView.bounds.width // 1080 / 275 = 3.927 ...

        // Scale everything, for examples label's font size
        [label1, label2].forEach { $0.font =  UIFont.systemFont(ofSize: $0.font.pointSize * scaleMultiplier, weight: .bold) }
        // or subview's center
        subview.center = subview.center.applying(.init(scaleX: scaleMultiplier, y: scaleMultiplier))

        // 4. Render image from hdView
        let hdImage = makeImageFrom(hdView)

Rendering view to image – bigger size with second view Отличия качества от реального использования - увеличено до метки: Difference: After / Before

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...