0

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:

enter image description here

On the receivers end it shows up blurry / pixelated:

enter image description here

If the receiver taps the image to full screen it the image looks fine:

enter image description here

Now, to complicate things more, if the receiver copies the image and sends it back the sent image now shows up fine for them:

enter image description here

but blurry for the initial sender of the image:

enter image description here

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()
    }
}
joncarl
  • 642
  • 1
  • 6
  • 18
  • because you are using ***uiImage*** and it reads data, your data has low resolution! make it higher for sharper Image. – ios coder Nov 30 '20 at 01:41
  • @Omid I don't follow. UIGraphicsImageRenderer is generating the UIImage and I don't see a way to increase the resolution. – joncarl Dec 01 '20 at 02:26

0 Answers0