背景图片和 canvas with pencilKit Swiftui

Background Image and canvas with pencilKit Swiftui

我正在学习 PencilKit。

我有一个canvas,我想设置一个我们可以在上面绘制的背景图片。

当我保存 canvas 时,我希望我的背景图片可见

但是我有一个错误: 无法将类型 'Image' 的值转换为预期的参数类型 'UIImage?'

Image("badmintoncourt") 是我资产中的图像 我找不到解决方法,但我可能没有以正确的方式将背景图片添加到 canvas

    struct Home : View {
    @State var canvas = PKCanvasView()
    @Environment(\.undoManager) private var undoManager
    @State var showingAlert = false
    var body: some View{
        
        NavigationView{
            MyCanvas(canvasView: canvas)
                .navigationTitle("Drawing")
                .navigationBarTitleDisplayMode(.inline)
        }
    }
  
}


struct MyCanvas: UIViewRepresentable {
    var canvasView: PKCanvasView
    let picker = PKToolPicker.init()
    
    func makeUIView(context: Context) -> PKCanvasView {
        self.canvasView.tool = PKInkingTool(.pen, color: .black, width: 15)
        self.canvasView.isOpaque = false
        self.canvasView.backgroundColor = UIColor.clear
        self.canvasView.becomeFirstResponder()

        let imageView = Image("badmintoncourt")

        let subView = self.canvasView.subviews[0]
            subView.addSubview(imageView)
            subView.sendSubviewToBack(imageView)
        return canvasView
    }
    
    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        picker.addObserver(canvasView)
        picker.setVisible(true, forFirstResponder: uiView)
        DispatchQueue.main.async {
            uiView.becomeFirstResponder()
        }
    }
}

编辑: 这是我保存图像的代码:

func SaveImage(){
    let image = canvas.drawing.image(from: canvas.drawing.bounds, scale: 1)
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}

Image 不是 UIView,在这种情况下您必须使用 UIImageView

    let imageView = UIImageView(image: UIImage(named: "badmintoncourt"))

    let subView = self.canvasView.subviews[0]
        subView.addSubview(imageView)
        subView.sendSubviewToBack(imageView)

这就是我解决这个问题的方法,允许在图像上绘制并将两者保存在一个最终图像中。此解决方案使 canvas 用于绘制图像的大小。

我将 canvas 添加为图像的叠加层,并将绘图存储在单独的图像中。完成绘图后,我将两张图片合二为一。

struct DrawOnImageView: View {

    @Binding var image: UIImage

    let onSave: (UIImage) -> Void

    @State private var drawingOnImage: UIImage = UIImage()
    @State private var canvasView: PKCanvasView = PKCanvasView()

    init(image: Binding<UIImage>, onSave: @escaping (UIImage) -> Void) {
        self.image = image
        self.onSave = onSave
    }

    var body: some View {
        VStack {
            Button(action: { save() }, label: Text("Save"))

            Image(uiImage: self.image)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .edgesIgnoringSafeArea(.all)
                .overlay(CanvasView(canvasView: $canvasView, onSaved: onChanged), alignment: .bottomLeading)
        }
    }

    private func onChanged() -> Void {
        self.drawingOnImage = canvasView.drawing.image(
            from: canvasView.bounds, scale: UIScreen.main.scale)
    }

    private func initCanvas() -> Void {
        self.canvasView = PKCanvasView();
        self.canvasView.isOpaque = false
        self.canvasView.backgroundColor = UIColor.clear
        self.canvasView.becomeFirstResponder()
    }

    private func save() -> Void {
        onSave(self.image.mergeWith(topImage: drawingOnImage))
    }
}

UIImage 的这个扩展将允许您合并图像。我使用了这个答案中的代码

public extension UIImage {
    func mergeWith(topImage: UIImage) -> UIImage {
        let bottomImage = self

        UIGraphicsBeginImageContext(size)


        let areaSize = CGRect(x: 0, y: 0, width: bottomImage.size.width, height: bottomImage.size.height)
        bottomImage.draw(in: areaSize)

        topImage.draw(in: areaSize, blendMode: .normal, alpha: 1.0)

        let mergedImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return mergedImage
    }
}

最后,这是我的 canvas 观点,尽管我认为您的代码中的 MyCanvas 应该可以正常工作。我的观点基于 this PencilKit tutorial.

struct CanvasView {
    @Binding var canvasView: PKCanvasView
    let onSaved: () -> Void

    @State var toolPicker = PKToolPicker()
}

extension CanvasView: UIViewRepresentable {
    func makeUIView(context: Context) -> PKCanvasView {
        canvasView.tool = PKInkingTool(.pen, color: .gray, width: 10)
        #if targetEnvironment(simulator)
        canvasView.drawingPolicy = .anyInput
        #endif
        canvasView.delegate = context.coordinator
        showToolPicker()
        return canvasView
    }

    func updateUIView(_ uiView: PKCanvasView, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(canvasView: $canvasView, onSaved: onSaved)
    }
}

private extension CanvasView {
    func showToolPicker() {
        toolPicker.setVisible(true, forFirstResponder: canvasView)
        toolPicker.addObserver(canvasView)
        canvasView.becomeFirstResponder()
    }
}

class Coordinator: NSObject {
    var canvasView: Binding<PKCanvasView>
    let onSaved: () -> Void

    init(canvasView: Binding<PKCanvasView>, onSaved: @escaping () -> Void) {
        self.canvasView = canvasView
        self.onSaved = onSaved
    }
}

extension Coordinator: PKCanvasViewDelegate {
    func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
        if !canvasView.drawing.bounds.isEmpty {
            onSaved()
        }
    }
}