1

我正在开发 iOS 应用程序,它应该使用户能够创建 Instagram 故事照片并将它们导出到 Instagram。基本上像Unfold、Stellar、Chroma Stories这样的应用程序......我已经准备好用户界面,用户可以从准备好的模板中进行选择,并向他们添加自己的带有过滤器、标签等的照片。

我的问题是 -将创建的 UIView 导出到更大图像的最佳方法是什么? 我的意思是如何获得最好的质量、清晰的标签像素等?因为带有子视图(添加的照片、标签......)的模板视图占用了设备屏幕的 +- 一半。但我需要更大的尺寸来导出图像。目前我使用:

 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,但标签不清晰。在将其制作成图像之前,我是否需要以某种方式缩放照片和字体大小?谢谢!

4

1 回答 1

3

所以实际上是的,在捕获图像之前,我需要缩放整个视图和它的 subviews。这是我的发现(可能是显而易见的事情,但我花了一段时间才意识到——我会很高兴有任何改进)

渲染相同大小的图像

当您想将 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
}

将视图渲染到图像 - 相同大小

渲染不同尺寸的图像

但是,当您想要导出图像的特定尺寸时该怎么办?因此,从我的用例中,我想渲染最终尺寸(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
}

将视图渲染为图像 - 更大的尺寸

我的方法

但是因为我不想弄乱显示给用户的视图的大小,所以我采取了不同的方式并使用了第二个视图,它没有显示给用户。这意味着就在我想要捕获图像之前,我准备了具有相同内容但更大尺寸的“复制”视图。我没有将它添加到视图控制器的视图层次结构中,因此它是不可见的。

重要的提示!

你真的需要照顾子视图。这意味着,您必须增加字体大小、更新移动子视图的位置(例如它们的中心)等!这里只有几行来说明:

        // 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)

将视图渲染到图像 - 更大的尺寸与第二个视图 质量与实际使用的差异 - 放大到标签: 区别:之后/之前

于 2020-04-20T10:17:45.237 回答