swiftuisavephotopencilkit

PencilKit: Saving drawing to Photos


I am attempting to save a PencilKit drawing to Photos. But all I get is a yellow background.

Code explanation:

I added a blue square with a pencil to show that this view exports correctly. This does not affect the issue I have with the pencil drawing not showing. I separated my PencilKitView in a separate view in order to be able to export it in saveToPhotos() I can draw on the phone, but when I export to photos, the blue square with the pencil shows but the pencil drawing does not:

Saved image in Photos shows blue square with pencil, but the pencil image only shows as a yellow background with a "parking forbidden" icon

import PencilKit
import SwiftUI

struct PencilContentView: View {
    let pkv = PencilKitView()

    var body: some View {
        VStack(alignment: .center) {
            pkv

            Button("Save to photos") {
                saveToPhotos()
            }
            .buttonStyle(.borderedProminent)
        }
    }

    func saveToPhotos() {
        let renderer = ImageRenderer(content: pkv.frame(width: 400, height: 600))
        renderer.scale = 1.0

        if let uiImage = renderer.uiImage {
            UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
        }
    }
}

struct PencilKitView: View {
    var body: some View {
        ZStack {
            CanvasView()

            Rectangle()
                .fill(Color.blue)
                .frame(width: 100, height: 100)

            Image(systemName: "pencil")
                .resizable()
                .frame(width: 50, height: 50)
        }
    }
}

struct CanvasView: UIViewRepresentable {
    func makeUIView(context: Context) -> PKCanvasView {
        let canvasView = PKCanvasView()

        canvasView.drawingPolicy = .anyInput

        return canvasView
    }

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

I also receive an error message:

ERROR: ... is trying to save an opaque image (400x600) with 'AlphaPremulLast'. This would unnecessarily increase the file size and will double (!!!) the required memory when decoding the image --> ignoring alpha.

How can I save my pencil drawing as a photo?


Solution

  • You can't tell ImageRenderer to render to “flatten” a UIViewRepresentable (here, PKCanvasView) into an image, which is why you see:

    Unable to render flattened version of PlatformViewRepresentableAdaptor.
    

    So, please use PencilKit's built-in snapshot of the current drawing instead.

    NOTE: you should add NSPhotoLibraryAddUsageDescription to the Info.plist first.

    
    //
    //  ContentView.swift
    //  PencilKitExport
    //
    //  Created by 0x67 on 2025-09-01.
    //
    
    import SwiftUI
    import PencilKit
    
    final class CanvasController: ObservableObject {
        let view = PKCanvasView()
    }
    
    struct PencilContentView: View {
        @StateObject private var canvas = CanvasController()
    
        var body: some View {
            VStack(alignment: .center) {
                CanvasView(canvas: canvas)
                    .frame(minWidth: 300, minHeight: 400)
                    .background(Color(UIColor.secondarySystemBackground))
    
                Button("Save to photos") {
                    saveToPhotos()
                }
                .buttonStyle(.borderedProminent)
            }
            .padding()
        }
    
        private func saveToPhotos() {
            // ImageRenderer cannot flatten UIViewRepresentable (PKCanvasView).
            // Use PencilKit's built-in snapshot of the current drawing instead.
            let pk = canvas.view
            let bounds = pk.bounds.isEmpty ? CGRect(x: 0, y: 0, width: 400, height: 600) : pk.bounds
            let scale = UIScreen.main.scale
            let uiImage = pk.drawing.image(from: bounds, scale: scale)
            UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
        }
    }
    
    struct CanvasView: UIViewRepresentable {
        let canvas: CanvasController
    
        func makeUIView(context: Context) -> PKCanvasView {
            let v = canvas.view
            v.drawingPolicy = .anyInput
            return v
        }
    
        func updateUIView(_ uiView: PKCanvasView, context: Context) { }
    }
    
    #Preview {
        PencilContentView()
    }