I used code from https://stackoverflow.com/a/59333377/2402338 to build an image sharing feature for my app. It works great except for a small problem I cannot seem to figure out. If I share the generated image via iMessage it looks normal on my phone - maybe a little pixelated / blurry, if I get close:
On the receivers end it shows up blurry / pixelated:
If the receiver taps the image to full screen it the image looks fine:
Now, to complicate things more, if the receiver copies the image and sends it back the sent image now shows up fine for them:
but blurry for the initial sender of the image:
I am not sure what to do here. I've tried several things with changing the scale of the UIGraphicsImageRenderer, but that doesn't seem ideal. Sharing the image to other apps via the share sheet does not result in the pixelation / blurriness. I have also tested between friends on different iPhone models so it doesn't seem to be related to differing models.
The code to replicate my example:
import SwiftUI
@main
struct image_sharingApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State private var shareableImage: UIImage? = nil
@State private var displayShareSheet: Bool = false
var body: some View {
Group {
if self.shareableImage == nil {
Text("LOADING")
} else {
Image(uiImage: self.shareableImage!)
.cornerRadius(10)
}
Button( action: {
self.displayShareSheet.toggle()
}, label: {
Text("Share")
.fontWeight(.medium)
.padding()
.frame(width: UIScreen.main.bounds.width-128)
.font(.system(.body, design: .rounded))
.background(Color.blue)
.cornerRadius(8)
.foregroundColor(Color.white)
})
}.onAppear(perform: {
self.renderShareableImage()
}).sheet(isPresented: self.$displayShareSheet, content: {
ShareSheet(
image: self.shareableImage!
)
})
}
func renderShareableImage() {
self.shareableImage = ShareableImage().asImage()
}
}
struct ShareableImage: View {
var body: some View {
VStack(alignment: .leading, spacing: 14) {
VStack(alignment: .leading) {
Text("Hello, world!")
.foregroundColor(Color(UIColor.white))
.bold()
.font(.system(.title))
}
}
.padding(EdgeInsets(top: 50, leading: 20, bottom: 50, trailing: 20))
.background(Color(UIColor.red))
}
}
extension View {
func asImage() -> UIImage {
let controller = UIHostingController(rootView: self)
controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)
let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
controller.view.bounds = CGRect(origin: .zero, size: size)
controller.view.sizeToFit()
let image = controller.view.asImage()
controller.view.removeFromSuperview()
return image
}
}
extension UIView {
func asImage() -> UIImage {
// this seems to provide the best non-blurry image
// let rendererFormat = UIGraphicsImageRendererFormat.default()
// rendererFormat.opaque = false
// rendererFormat.scale = UIScreen.main.scale * 3
//
// let renderer = UIGraphicsImageRenderer(size: self.bounds.size, format: rendererFormat)
let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
struct ShareSheet: UIViewControllerRepresentable {
let image: UIImage
func makeUIViewController(context: Context) -> UIActivityViewController {
let activityItems: [Any] = [image]
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: nil)
return controller
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}