Add right-click Copy Image to diagrams

This commit is contained in:
Ian Gulliver
2026-10-23 09:08:21 -07:00
parent 41335867ef
commit fe86916ce6
3 changed files with 57 additions and 13 deletions
+14
View File
@@ -1103,6 +1103,7 @@ struct BoxDiagramView: View {
store.openSheet(.diagram(layout), fromTask: inTask) store.openSheet(.diagram(layout), fromTask: inTask)
} }
.help("Open full size") .help("Open full size")
.diagramMenu(layout)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
case .failure(let error): case .failure(let error):
DiagramFailure(source: source, reason: error.reason) DiagramFailure(source: source, reason: error.reason)
@@ -1166,6 +1167,19 @@ private struct TappableCanvas: View {
.onTapGesture(coordinateSpace: .local) { p in .onTapGesture(coordinateSpace: .local) { p in
tap(layout.hit(p)) tap(layout.hit(p))
} }
.diagramMenu(layout)
}
}
extension View {
func diagramMenu(_ layout: BoxLayout) -> some View {
contextMenu {
Button("Copy Image") {
if let image = diagramCGImage(layout) {
copyToClipboard(platformImage(image))
}
}
}
} }
} }
+19
View File
@@ -31,6 +31,16 @@ func copyToClipboard(_ text: String) {
NSPasteboard.general.setString(text, forType: .string) NSPasteboard.general.setString(text, forType: .string)
} }
@MainActor
func copyToClipboard(_ image: PlatformImage) {
NSPasteboard.general.clearContents()
NSPasteboard.general.writeObjects([image])
}
func platformImage(_ cg: CGImage) -> PlatformImage {
NSImage(cgImage: cg, size: NSSize(width: cg.width / 2, height: cg.height / 2))
}
@MainActor @MainActor
func openExternal(_ url: URL) { func openExternal(_ url: URL) {
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
@@ -96,6 +106,15 @@ func copyToClipboard(_ text: String) {
UIPasteboard.general.string = text UIPasteboard.general.string = text
} }
@MainActor
func copyToClipboard(_ image: PlatformImage) {
UIPasteboard.general.image = image
}
func platformImage(_ cg: CGImage) -> PlatformImage {
UIImage(cgImage: cg, scale: 2, orientation: .up)
}
@MainActor @MainActor
func openExternal(_ url: URL) { func openExternal(_ url: URL) {
UIApplication.shared.open(url) UIApplication.shared.open(url)
+24 -13
View File
@@ -1,6 +1,6 @@
#if os(macOS)
import SwiftUI import SwiftUI
#if os(macOS)
@MainActor @MainActor
func renderDiagram(html: Bool) -> Int32 { func renderDiagram(html: Bool) -> Int32 {
FontSize.stored = false FontSize.stored = false
@@ -17,18 +17,7 @@ func renderDiagram(html: Bool) -> Int32 {
FileHandle.standardOutput.write(Data(diagramHTML(layout).utf8)) FileHandle.standardOutput.write(Data(diagramHTML(layout).utf8))
return 0 return 0
} }
let content = BoxCanvas(layout: layout) guard let png = diagramCGImage(layout).flatMap({ NSBitmapImageRep(cgImage: $0).representation(using: .png, properties: [:]) }) else {
.frame(width: layout.size.width, height: layout.size.height)
.padding(16)
.background(Palette.bg)
.environment(\.colorScheme, .light)
let renderer = ImageRenderer(content: content)
renderer.scale = 2
var png: Data?
NSAppearance(named: .aqua)!.performAsCurrentDrawingAppearance {
png = renderer.cgImage.flatMap { NSBitmapImageRep(cgImage: $0).representation(using: .png, properties: [:]) }
}
guard let png else {
FileHandle.standardError.write(Data("diagram didn't render".utf8)) FileHandle.standardError.write(Data("diagram didn't render".utf8))
return 1 return 1
} }
@@ -36,3 +25,25 @@ func renderDiagram(html: Bool) -> Int32 {
return 0 return 0
} }
#endif #endif
@MainActor
func diagramCGImage(_ layout: BoxLayout) -> CGImage? {
let content = BoxCanvas(layout: layout)
.frame(width: layout.size.width, height: layout.size.height)
.padding(16)
.background(Palette.bg)
.environment(\.colorScheme, .light)
let renderer = ImageRenderer(content: content)
renderer.scale = 2
var image: CGImage?
#if os(macOS)
NSAppearance(named: .aqua)!.performAsCurrentDrawingAppearance {
image = renderer.cgImage
}
#else
UITraitCollection(userInterfaceStyle: .light).performAsCurrent {
image = renderer.cgImage
}
#endif
return image
}