如何从UIView创建特定大小的图像 [英] How to create an image of specific size from UIView

查看:156
本文介绍了如何从UIView创建特定大小的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用iOS应用,该应用应该使用户能够创建Instagram故事照片并将其导出到Instagram.基本上是像Unfold,Stellar,Chroma Stories这样的应用程序...我已经准备了UI,用户可以从准备好的模板中进行选择,并使用滤镜,标签等将自己的照片添加到其中.

I'm working on iOS app which should enable users to create Instagram stories photos and export them to Instagram. Basically app like Unfold, Stellar, Chroma Stories... I've prepared UI where user can select from prepared templates and add to them own photos with filters, labels etc.

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

My question is - what is the best way to export created UIView to bigger Image? I mean how to get the best quality, sharp pixels of labels etc? Because the template view with subviews (added photos, labels...) is taking +- half of device's screen. But I need bigger size for exported image. Currently I use:

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

The resulted image has size of 1080 x 1920, but labels aren't sharp. Do I need to scale somehow the photo and font size before making it to an image? Thanks!

推荐答案

实际上是的,在捕获图像之前,我需要缩放整个视图及其子视图.这是我的发现(也许很明显,但是花了一段时间我才意识到–任何改进我都会很高兴)

So actually yes, before capturing image I need to scale whole view and it's subviews. Here are my findings (maybe obvious things but it took me a while to realize that – I'll be glad for any improvements)

当您要将UIView捕获为图像时,只需使用此功能即可.生成的图像将具有与视图相同的大小(根据实际设备缩放2倍/3倍)

When you want to capture UIView as an image, you can simply use this function. Resulted image will have a same size as a view (scaled 2x / 3x depending on actual device)

 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).如果您不做任何这样的渲染,那么质量肯定会损失.

But what to do, when you want a specific size for your exported image? So from my use-case I wanted to render image of final size (1080 x 1920), but a view I wanted to capture had a smaller size (in my case 275 x 487). If you do such a rendering without anything, there must be a loss in quality.

如果要避免这种情况并保留清晰的标签和其他子视图,则需要尝试将视图理想地缩放到所需的大小.就我而言,将其从275 x 487设置为1080 x 1920.

If you want to avoid that and preserve sharp labels and other subviews, you need to try to scale the view ideally to the desired size. In my case, make it from 275 x 487 to 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
}

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

But because I didn't want to mess with a size of a view displayed to the user, I took a different way and used second view which isn't shown to the user. That means that just before I want to capture image, I prepare "duplicated" view with the same content but bigger size. I don't add it to the view controller's view hierarchy, so it's not visible.

重要提示!

您确实需要照顾子视图.这意味着,您必须增加字体大小,更新已移动子视图的位置(例如其中心)等! 这里只是几行来说明这一点:

You really need to take care of subviews. That means, that you have to increase the font size, update position of moved subviews (for example their center) etc.! Here is just a few lines to illustrate that:

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

质量与实际用法之间的差异–放大至标签:

Difference in quality from real usage – zoomed to the label:

这篇关于如何从UIView创建特定大小的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆