I'm trying to setup a widget to pull an image down from a webserver and I'm running into an error of Widget archival failed due to image being too large [9] - (1024, 1024), totalArea: 1048576 > max[718080.000000].
I've tried two different approaches to resolve this error and both have failed to resolve the image.
I've also confirmed that I'm getting the image in the AppIntentTimelineProvider
.
private func getImageUI(urlString: String) -> UIImage? {
guard let url = URL(string: urlString) else { return nil }
guard let imageData = try? Data(contentsOf: url) else { return nil }
return UIImage(data: imageData)?.resizedForWidget()
}
Is there another approach I could take on addressing this issue so the image appears on the widget?
Simple approach
extension UIImage {
func resized(toWidth width: CGFloat, isOpaque: Bool = true) -> UIImage? {
let canvas = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: canvas, format: format).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
}
extension UIImage {
/// Resize the image to strictly fit within WidgetKit’s max allowed pixel area (718,080 pixels)
func resizedForWidget(maxArea: CGFloat = 718_080.0, isOpaque: Bool = true) -> UIImage? {
let originalWidth = size.width
let originalHeight = size.height
let originalArea = originalWidth * originalHeight
print("🔍 Original Image Size: \(originalWidth)x\(originalHeight) → Total Pixels: \(originalArea)")
// ✅ If the image is already within the limit, return as is
if originalArea <= maxArea {
print("✅ Image is already within the allowed area.")
return self
}
// 🔄 Calculate the exact scale factor to fit within maxArea
let scaleFactor = sqrt(maxArea / originalArea)
let newWidth = floor(originalWidth * scaleFactor) // Use `floor` to ensure area is always within limits
let newHeight = floor(originalHeight * scaleFactor)
let newSize = CGSize(width: newWidth, height: newHeight)
print("🛠 Resizing Image: \(originalWidth)x\(originalHeight) → \(newWidth)x\(newHeight)")
// ✅ Force bitmap rendering to ensure the resized image is properly stored
let format = UIGraphicsImageRendererFormat()
format.opaque = isOpaque
format.scale = 1 // Ensures we are not letting UIKit auto-scale it back up
let renderer = UIGraphicsImageRenderer(size: newSize, format: format)
let resizedImage = renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: newSize))
}
print("✅ Final Resized Image Size: \(resizedImage.size), Total Pixels: \(resizedImage.size.width * resizedImage.size.height)")
return resizedImage
}
}
These are logs from a failed image render if that helps
- 🔍 Original Image Size: 720.0x1280.0 → Total Pixels: 921600.0
- 🛠 Resizing Image: 720.0x1280.0 → 635.0x1129.0
- ✅ Final Resized Image Size: (635.0, 1129.0), Total Pixels: 716915.0