How do I make UIImage conform to Transferable?

Hello!

I've been teaching myself Swift and wanted to challenge myself by creating a drawing app. I want to add a feature that allows the user to share the drawing on their canvas, but I'm having some difficulty. I tried using a ShareLink, but it's asking that I conform in to Transferable. How do I do that?

import SwiftUI
import PencilKit

struct ContentView: View {
    @State private var canvasView = PKCanvasView()

    var body: some View {
        Text("Let's draw!")
        
        GeometryReader { geometry in
            VStack {
                Spacer()
                HStack {
                    Spacer()
                    PencilKitView()
                        .frame(width: geometry.size.width * 1, height: geometry.size.height * 0.7)
                    Spacer()
                }
                Spacer()
            }
        }
        
        //share button
        Button("share with a friend") {
            let portionRect = CGRect(x: 0, y: 0, width: 100, height: 100) 
            let scale: CGFloat = 1.0
                    
            let image = canvasView.drawing.image(from: portionRect, scale: scale)
            
            ShareLink(
                item: image,
                preview: SharePreview(
                    "Share Preview",
                    image: image
                )
            )
        }
    }
}


struct PencilKitView: UIViewRepresentable {
    typealias UIViewType = PKCanvasView
    
    let toolPicker = PKToolPicker()
    
    func makeUIView(context: Context) -> PKCanvasView {
        let pencilKitCanvasView = PKCanvasView()
        
        pencilKitCanvasView.drawingPolicy = PKCanvasViewDrawingPolicy.anyInput
        
        toolPicker.addObserver(pencilKitCanvasView)
        toolPicker.setVisible(true, forFirstResponder: pencilKitCanvasView)
        
        pencilKitCanvasView.becomeFirstResponder()
        
        return pencilKitCanvasView
    }
    
    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        
    }
}

#Preview {
    ContentView()
}

Replies

Hello,

There is no "one correct way" to implement Transferable for your data model, I highly recommend that you read over Choosing a transfer representation for a model type.

Having said that, here is a way that you might conform UIImage to Transferable for exporting:

extension UIImage: Transferable {
    
    public static var transferRepresentation: some TransferRepresentation {
        
        DataRepresentation(exportedContentType: .png) { image in
            if let pngData = image.pngData() {
                return pngData
            } else {
                // Handle the case where UIImage could not be converted to png.
                throw ConversionError.failedToConvertToPNG
            }
        }
    }
    
    enum ConversionError: Error {
        case failedToConvertToPNG
    }
}