I want to add a white border to the photo, while preserving the quality of the photo, so I use UIGraphicsImageRenderer to draw a white background, and then draw the photo up, the result is a dramatic increase in memory usage, is there any better way?
The resolution of the original picture is 4032 * 3024.
let renderer = UIGraphicsImageRenderer(size: CGSize(width: canvasSideLength, height: canvasSideLength))
let newImage = renderer.image { context in
UIColor.white.setFill()
context.fill(CGRect(x: 0, y: 0, width: canvasSideLength, height: canvasSideLength))
image.draw(in: CGRect(x: photoCanvasX, y: photoCanvasY, width: photoCanvasWidth, height: photoCanvasHeight))
}
When considering the memory used, don’t be misled by the size of the JPG or PNG file, because that is generally compressed. You will require four bytes per pixel when performing image operations in memory (e.g. width × height × 4, in pixels).
Worse, by default, UIGraphicsImageRenderer
will generate images at screen resolution (e.g. potentially 2× or 3× depending upon your device). E.g. on a 3× device, consider:
let rect = CGRect(origin: .zero, size: CGSize(width: 8_519, height: 8_519))
let image = UIGraphicsImageRenderer(bounds: rect).image { _ in
UIColor.white.setFill()
UIBezierPath(rect: rect).fill()
}
print(image.cgImage!.width, "×", image.cgImage!.height)
That will print:
25557 × 25557
When you consider that it then takes 4 bytes per pixel, that adds up to 2.6gb. Even if the image is only 4,032 × 3,024, as suggested by your revised question, that’s still 439mb per image.
You may want to make sure to specify an explicit scale of 1:
let rect = CGRect(origin: .zero, size: CGSize(width: 8_519, height: 8_519))
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let image = UIGraphicsImageRenderer(bounds: rect, format: format).image { _ in
UIColor.white.setFill()
UIBezierPath(rect: rect).fill()
}
print(image.cgImage!.width, "×", image.cgImage!.height)
That will print, as you expected:
8519 × 8519
Then you are only going to require 290mb for the image. That’s still a lot of memory, but a lot less than if you use the default scale (on retina devices). Or, considering your revised 4,032 × 3,024 image, this 1× image could take only 49mb, 1/9th the size of the corresponding 3× image where you didn’t set the scale.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With