In my case, I need to output a relatively large floor plan, and I simplified the code as follows. In the case of a relatively large size, the correct image cannot be output
Sample Code
let image1Size = CGSize(width: 400, height: 3000)
let size1 = CGSize(width: 430, height: 682)
let testView = UIView(frame: CGRect(origin: .zero, size: image1Size))
testView.backgroundColor = .red
let testImage = UIGraphicsImageRenderer(size: image1Size).image { context in
testView.drawHierarchy(in: CGRect(origin: .zero, size: image1Size), afterScreenUpdates: true)
}
let test2View = UIView(frame: CGRect(origin: .zero, size: size1))
test2View.backgroundColor = .red
let test2Image = UIGraphicsImageRenderer(size: size1).image { context in
test2View.drawHierarchy(in: CGRect(origin: .zero, size: size1), afterScreenUpdates: true)
}
result: error image expect image
I expect to be able to output the correct image at a relatively large size, or any other large image output possible
The size of the rect in:
func drawHierarchy(in rect: CGRect, afterScreenUpdates afterUpdates: Bool) -> Bool
is limited to 8192 x 8192
pixels.
That means on a 3x device, the max rect size is 2730, 2730
(2730 * 3 == 8190)
On a 2x device, the max rect size is 4096, 4096
(4096 * 2 == 8192)
You can create a UIImage
that is larger than that, and render several views into it... but each view's size is limited.
You can, however, render a view's layer at a larger size:
let viewSize: CGSize = .init(width: 400.0, height: 3000.0)
var testView = UIView(frame: CGRect(origin: .zero, size: viewSize))
testView.backgroundColor = .red
let v1 = UILabel()
v1.text = "Top-Left"
v1.backgroundColor = .yellow
let v2 = UILabel()
v2.text = "Bottom-Right"
v2.backgroundColor = .yellow
v1.sizeToFit()
v2.sizeToFit()
v1.frame.origin = .init(x: 20.0, y: 20.0)
v2.frame.origin = .init(x: viewSize.width - (v2.frame.width + 20.0), y: viewSize.height - (v2.frame.height + 20.0))
testView.addSubview(v1)
testView.addSubview(v2)
let image = UIGraphicsImageRenderer(bounds: testView.bounds).image { context in
testView.layer.render(in: context.cgContext)
}
I don't know why you can do that, but it (appears) to work.
Note: UIGraphicsImageRenderer
generates the image at point size. If your goal is to take a 400 x 3000
point UIView
and generate a 400 x 3000
pixel image, use UIGraphicsImageRendererFormat
and set .scale = 1
:
let fmt = UIGraphicsImageRendererFormat()
fmt.scale = 1
let image = UIGraphicsImageRenderer(bounds: testView.bounds, format: fmt).image { context in
testView.layer.render(in: context.cgContext)
}