Generating a png-File on the desktop from a screenshot made to the pasteboard on macOS

Hi stackoverflow forum,

I've written a macOS swiftUI app, which checks the availability to a website, i.e. to my cloud. In the case, the access is lost, I'm creating a screenshot to the pasteboard and I'm generating a POST request to a PHP script on my webserver, to send an information email to my email address.

I'm using the following 2 functions, to generate the screenshot and save it to the pasteboard. All based on the tutorial (very good!) from Grace Huang (https://www.youtube.com/watch?v=7nnYsRrtweA)

//MARK: - Ein Screenshot wird erstellt und im Pasteboard abgespeichert

func erfolgreichEinScreenshotErstellt() -> Bool{
    let task = Process()
    task.launchPath = "/usr/sbin/screencapture"
    task.arguments = ["-c"]
    task.launch()
    task.waitUntilExit()
    let status = task.terminationStatus
    return status == 0
}

//MARK: - Das gecaptured Bild wird aus dem Pastboard geholt und in das image geladen

func dasBildAbholenUndZeigen() -> NSImage {
    let pasteboard = NSPasteboard.general
    guard pasteboard.canReadItem(withDataConformingToTypes:
        NSImage.imageTypes) else{
        return NSImage()
    }
    guard let image = NSImage(pasteboard: pasteboard) else {
        return NSImage()
    }
    let tiffData = image.tiffRepresentation!
    let pngData = NSBitmapImageRep(data: tiffData)?.representation(using: .png, properties: [:])

    return image
}

Everything works fine till here!

The last step I like to do, I need a little help for: how can I save the "image" as a .png-file with a given name to my desktop for further use, i.e. generating a pdf file or so from the png file.

As you can see, I've tried the following code but than I've got stuck:

.........

    let tiffData = image.tiffRepresentation!
    let pngData = NSBitmapImageRep(data: tiffData)?.representation(using: .png, properties: [:])

Thanks in advance, if someone likes to help me with some code or a hint to a solution idea.

Best

Thomas

Upvotes: 0

Views: 112

Answers (2)

vadian
vadian

Reputation: 285072

As already mentioned the line to write the code to disk is missing.

However your approach is cumbersome. screencapture can save the image directly to disk just be replacing -c with the file path. The pasteboard detour is not needed.

But there is a general issue: Most likely your app is sandboxed. If so using Process() is not allowed. Fortunately you can take a screenshot with the Core Graphics API.

This function captures the contents of the main screen and saves the image in the Downloads folder (you have to enable it in the sandbox settings) with an iso8601 timestamp and returns the URL

enum ScreenshotError: Error {
    case cannotCreateImage
}

func takeScreenshot()  throws -> URL {
    let mainDisplayID = CGMainDisplayID()
    
    let timeStamp = Date().formatted(.iso8601.dateSeparator(.omitted).timeSeparator(.omitted))
    let fileUrl = URL.downloadsDirectory.appending(path: "screenshot_" + timeStamp + ".png")
    let screenshot = CGDisplayCreateImage(mainDisplayID)!
    let bitmapRep = NSBitmapImageRep(cgImage: screenshot)
    guard let jpegData = bitmapRep.representation(using: .png, properties: [:]) else {
        throw ScreenshotError.cannotCreateImage
    }
    try jpegData.write(to: fileUrl)
    return fileUrl
}

And call it

do {
    let fileURL = try takeScreenshot()
} catch {
    print(error)
}

Upvotes: 1

soundflix
soundflix

Reputation: 2763

Your method is missing the actual saving to disk call:

let tiffData = image.tiffRepresentation!
let pngData = NSBitmapImageRep(data: tiffData)?.representation(using: .png, properties: [:])
let path = URL(fileURLWithPath: "/Users/*YourUsername*/Desktop/testImage.png")
try? pngData?.write(to: path) // << save to disk

Upvotes: 0

Related Questions