I'm using this Extension to take an image of a SwiftUI view (for sharing) but the only problem is my view has a cornerRadius
of 10.0 so round the corners, so this image ends up with black non rounded corners, how can I get rid of it?
extension View {
func takeScreenshot(origin: CGPoint, size: CGSize) -> UIImage? {
// Get the main window.
guard let window = UIApplication.shared.windows.first else {
print("View.takeScreenshot: No main window found")
return nil
}
// Create an image of the entire window. Note how we're using `window.bounds` for this
// to capture the entire window.
UIGraphicsBeginImageContextWithOptions(window.bounds.size, false, 0.0)
let renderer = UIGraphicsImageRenderer(bounds: window.bounds, format: UIGraphicsImageRendererFormat())
let image = renderer.image { (context) in
window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
}
UIGraphicsEndImageContext()
/*
At this point we have a screenshot of the entire window.
Now we're going to crop it to just include the part of the screen
we want.
*/
// Scale is the pixel density of the screen. E.g. 3.0 on iPhone 12 Pro which has a 3x display.
// This will be used in the UIImage extension below.
let scale = UIScreen.main.scale
let rect = CGRect(x: origin.x, y: origin.y, width: size.width, height: size.height)
let croppedImage = image.cropped(boundingBox: rect, scale: scale)
return croppedImage
}
}
extension UIImage {
func cropped(boundingBox: CGRect, scale: CGFloat) -> UIImage? {
/*
To crop UIImage we must first convert it to a CGImage.
UIImage uses points, which are independent of pixels.
Therefore, we need to take the scaling factor of the screen into account
when cropping.
For example, if we want to crop a 100x50pt square starting at (75, 90) from a UIImage
on a device with a 2x scaling factor, we would multiple everything by 2 and crop a
200x100px square starting at (150, 180).
*/
let x = boundingBox.origin.x * scale
let y = boundingBox.origin.y * scale
let width = boundingBox.width * scale
let height = boundingBox.height * scale
let adjustedBoundingBox = CGRect(x: x, y: y, width: width, height: height)
guard let cgImage = self.cgImage?.cropping(to: adjustedBoundingBox) else {
print("UIImage.cropped: Couldn't create cropped image")
return nil
}
return UIImage(cgImage: cgImage)
}
}
The View that I am taking a screenshot of:
var shareCard: some View {
VStack {
Spacer()
GeometryReader { geometry in
if backgroundImage != UIImage() {
Image(uiImage: backgroundImage)
.resizable()
.scaledToFill()
.frame(width: geometry.size.width, height: geometry.size.height)
.clipped() //needed to add clipped otherwise the picture would go outside of the frame. From https://sarunw.com/posts/how-to-resize-swiftui-image-and-keep-aspect-ratio/
.cornerRadius(10.0)
.overlay(
Color.black
.cornerRadius(10.0)
.opacity(0.45) //keep at 0.45?
)
} else {
Image("sampleBackground")
.resizable()
//.scaledToFill()
.frame(width: geometry.size.width, height: geometry.size.height)
.cornerRadius(10.0)
.onAppear {
proxy = geometry
}
}
}
Spacer()
}
.frame(height: 375)
.padding(.horizontal)
.overlay(
TabView(selection: $selectedTabIndex) {
//Omitted - these are views that are overlayed over the background or image and don't impact the size of the snapshot
}
.frame(height: 430)
.padding(.horizontal)
.tabViewStyle(.page(indexDisplayMode: isTakingSnapShot ? .never : .always))
.overlay(
VStack {
switch shareType {
case .TodaySummary:
VStack {
HStack {
HStack(alignment: .center) {
Image("logo")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 40)
.padding(.leading)
VStack(alignment: .leading, spacing: 3) {
Text("AppName")
.foregroundColor(.white)
.font(.headline)
.fontWeight(.bold)
Text(Date(), style: .date)
.foregroundColor(.white)
.font(.footnote)
}
}
Spacer()
}
.padding([.leading, .top])
Spacer()
}
.frame(height: 375)
case .Workout:
EmptyView() //Pass empty view here because we use a different header for workout share
}
}
)
)
}