Ond*_*rol 3 uiview uiimage ios swift uigraphicsimagerenderer
我正在开发 iOS 应用程序,该应用程序应该使用户能够创建 Instagram 故事照片并将其导出到 Instagram。基本上像 Unfold、Stellar、Chroma Stories 这样的应用程序...我已经准备好了 UI,用户可以从准备好的模板中进行选择,并向其中添加带有滤镜、标签等的自己的照片。
我的问题是 -将创建的 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
}
Run Code Online (Sandbox Code Playgroud)
生成的图像尺寸为 1080 x 1920,但标签不清晰。在将其制作为图像之前,我是否需要以某种方式缩放照片和字体大小?谢谢!
所以实际上是的,在捕获图像之前我需要缩放整个视图及其子视图。这是我的发现(也许是显而易见的事情,但我花了一段时间才意识到 \xe2\x80\x93\xc2\xa0I\ 会对任何改进感到高兴)
\n\n当你想将UIView捕获为图像时,你可以简单地使用这个函数。生成的图像将具有与视图相同的尺寸(根据实际设备缩放 2 倍/3 倍)
\n\n func makeImageFrom(_ desiredView: MyView) -> UIImage {\n let size = CGSize(width: desiredView.bounds.width, height: desiredView.bounds.height)\n let renderer = UIGraphicsImageRenderer(size: size)\n let image = renderer.image { (ctx) in\n desiredView.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)\n }\n return image\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n但是,当您想要导出的图像具有特定尺寸时该怎么办?\n因此,从我的用例来看,我想渲染最终尺寸(1080 x 1920)的图像,但我想要捕获的视图具有较小的尺寸(在我的情况是 275 x 487)。如果你在没有任何东西的情况下进行这样的渲染,那么质量肯定会有所损失。
\n\n如果您想避免这种情况并保留清晰的标签和其他子视图,则需要尝试将视图理想地缩放到所需的大小。就我而言,将其从 275 x 487 调整为 1080 x 1920。
\n\nfunc makeImageFrom(_ desiredView: MyView) -> UIImage {\n let format = UIGraphicsImageRendererFormat()\n // We need to divide desired size with renderer scale, otherwise you get output size larger @2x or @3x\n let size = CGSize(width: 1080 / format.scale, height: 1920 / format.scale)\n\n let renderer = UIGraphicsImageRenderer(size: size, format: format)\n let image = renderer.image { (ctx) in\n // remake constraints or change size of desiredView to 1080 x 1920\n // handle it\'s subviews (update font size etc.)\n // ...\n desiredView.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)\n // undo the size changes\n // ...\n }\n return image\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n但是因为我不想弄乱向用户显示的视图的大小,所以我采取了不同的方式并使用了不向用户显示的第二个视图。这意味着在我想要捕获图像之前,我准备了内容相同但尺寸更大的“重复”视图。我没有将其添加到视图控制器的视图层次结构中,因此它不可见。
\n\n重要的提示!
\n\n您确实需要照顾子视图。这意味着,您必须增加字体大小,更新移动子视图的位置(例如它们的中心)等!\n这里只有几行来说明这一点:
\n\n // 1. Create bigger view\n let hdView = MyView()\n hdView.frame = CGRect(x: 0, y: 0, width: 1080, height: 1920)\n\n // 2. Load content according to the original view (desiredView)\n // set text, images...\n\n // 3. Scale subviews\n // Find out what scale we need\n let scaleMultiplier: CGFloat = 1080 / desiredView.bounds.width // 1080 / 275 = 3.927 ...\n\n // Scale everything, for examples label\'s font size\n [label1, label2].forEach { $0.font = UIFont.systemFont(ofSize: $0.font.pointSize *\xc2\xa0scaleMultiplier, weight: .bold) }\n // or subview\'s center\n subview.center = subview.center.applying(.init(scaleX: scaleMultiplier, y: scaleMultiplier))\n\n // 4. Render image from hdView\n let hdImage = makeImageFrom(hdView)\nRun Code Online (Sandbox Code Playgroud)\n\n
\n与实际使用的质量差异 \xe2\x80\x93 放大到标签:\n
| 归档时间: |
|
| 查看次数: |
1723 次 |
| 最近记录: |