diff --git a/Sources/SwiftUIBackports/Internal/Platforms.swift b/Sources/SwiftUIBackports/Internal/Platforms.swift index 12dfe7d..fcd1759 100644 --- a/Sources/SwiftUIBackports/Internal/Platforms.swift +++ b/Sources/SwiftUIBackports/Internal/Platforms.swift @@ -3,17 +3,68 @@ import UIKit public typealias PlatformImage = UIImage +public typealias PlatformScreen = UIScreen internal typealias PlatformView = UIView internal typealias PlatformViewController = UIViewController +extension UIScreen { + @nonobjc + public static var mainScreen: UIScreen { + return .main + } +} + +extension UIImage { + public var png: Data? { + return self.pngData() + } + + public func jpg(quality: CGFloat) -> Data? { + return self.jpegData(compressionQuality: quality) + } +} + #elseif os(macOS) import AppKit public typealias PlatformImage = NSImage +public typealias PlatformScreen = NSScreen internal typealias PlatformView = NSView internal typealias PlatformViewController = NSViewController +extension NSScreen { + public static var mainScreen: NSScreen { + return NSScreen.main! + } + + public var scale: CGFloat { + return backingScaleFactor + } +} + +extension NSImage { + public var png: Data? { + return NSBitmapImageRep(data: tiffRepresentation!)?.representation(using: .png, properties: [:]) + } + + public func jpg(quality: CGFloat) -> Data? { + return NSBitmapImageRep(data: tiffRepresentation!)?.representation(using: .jpeg, properties: [.compressionFactor: quality]) + } +} + #endif + +extension CGContext { + + internal static var current: CGContext? { +#if os(OSX) + return NSGraphicsContext.current?.cgContext +#else + return UIGraphicsGetCurrentContext() +#endif + } + +} diff --git a/Sources/SwiftUIBackports/Shared/ImageRenderer/Renderer.swift b/Sources/SwiftUIBackports/Shared/ImageRenderer/Renderer.swift index 6efc44c..256aa51 100644 --- a/Sources/SwiftUIBackports/Shared/ImageRenderer/Renderer.swift +++ b/Sources/SwiftUIBackports/Shared/ImageRenderer/Renderer.swift @@ -4,7 +4,7 @@ public final class ImageRenderer: ObservableObject where Content: View public var content: Content public var label: String? public var proposedSize: ProposedViewSize = .unspecified - public var scale: CGFloat = UIScreen.main.scale + public var scale: CGFloat = PlatformScreen.mainScreen.scale public var isOpaque: Bool = false public var colorMode: ColorRenderingMode = .nonLinear @@ -22,7 +22,7 @@ public final class ImageRenderer: ObservableObject where Content: View public extension ImageRenderer { var cgImage: CGImage? { #if os(macOS) - nsImage?.cgImage + nsImage?.cgImage(forProposedRect: nil, context: .current, hints: nil) #else uiImage?.cgImage #endif @@ -31,7 +31,7 @@ public extension ImageRenderer { #if os(macOS) var nsImage: NSImage? { - nil + NSHostingController(rootView: content).view.snapshot } #else @@ -44,7 +44,6 @@ public extension ImageRenderer { let format = UIGraphicsImageRendererFormat(for: controller.traitCollection) format.opaque = isOpaque - format.preferredRange = colorMode.range format.scale = scale let renderer = UIGraphicsImageRenderer(size: size, format: format) @@ -62,8 +61,7 @@ public extension ImageRenderer { #endif } -#if os(macOS) -#else +#if os(iOS) extension ColorRenderingMode { var range: UIGraphicsImageRendererFormat.Range { switch self { @@ -74,3 +72,11 @@ extension ColorRenderingMode { } } #endif + +#if os(macOS) +private extension NSView { + var snapshot: NSImage? { + return NSImage(data: dataWithPDF(inside: bounds)) + } +} +#endif diff --git a/Sources/SwiftUIBackports/Shared/ShareLink/ShareSheet.swift b/Sources/SwiftUIBackports/Shared/ShareLink/ShareSheet.swift index 4642922..2b195b7 100644 --- a/Sources/SwiftUIBackports/Shared/ShareLink/ShareSheet.swift +++ b/Sources/SwiftUIBackports/Shared/ShareLink/ShareSheet.swift @@ -13,7 +13,7 @@ extension View { #if os(macOS) -private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollection, Data.Element: Shareable { +private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollection, Data.Element: Shareable { @Binding var item: ActivityItem? public func makeNSView(context: Context) -> SourceView { @@ -27,7 +27,7 @@ private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollectio final class SourceView: NSView, NSSharingServicePickerDelegate, NSSharingServiceDelegate { var picker: NSSharingServicePicker? - var item: Binding { + var item: Binding?> { didSet { updateControllerLifecycle( from: oldValue.wrappedValue, @@ -36,7 +36,7 @@ private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollectio } } - init(item: Binding) { + init(item: Binding?>) { self.item = item super.init(frame: .zero) } @@ -45,7 +45,7 @@ private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollectio fatalError("init(coder:) has not been implemented") } - private func updateControllerLifecycle(from oldValue: ActivityItem?, to newValue: ActivityItem?) { + private func updateControllerLifecycle(from oldValue: ActivityItem?, to newValue: ActivityItem?) { switch (oldValue, newValue) { case (.none, .some): presentController() @@ -57,7 +57,7 @@ private struct ShareSheet: NSViewRepresentable where Data: RandomAccessCollectio } func presentController() { - picker = NSSharingServicePicker(items: item.wrappedValue?.items ?? []) + picker = NSSharingServicePicker(items: item.wrappedValue?.data.map { $0 } ?? []) picker?.delegate = self DispatchQueue.main.async { guard self.window != nil else { return } @@ -139,6 +139,7 @@ private extension ShareSheet { let controller = UIActivityViewController(activityItems: item.wrappedValue?.data.map { $0 } ?? [], applicationActivities: nil) controller.presentationController?.delegate = self controller.popoverPresentationController?.permittedArrowDirections = .any + controller.popoverPresentationController?.sourceRect = view.bounds controller.popoverPresentationController?.sourceView = view controller.completionWithItemsHandler = { [weak self] _, _, _, _ in self?.item.wrappedValue = nil diff --git a/Sources/SwiftUIBackports/Shared/ShareLink/Transferable.swift b/Sources/SwiftUIBackports/Shared/ShareLink/Transferable.swift index 4db7522..aa41e48 100644 --- a/Sources/SwiftUIBackports/Shared/ShareLink/Transferable.swift +++ b/Sources/SwiftUIBackports/Shared/ShareLink/Transferable.swift @@ -45,7 +45,13 @@ extension Image: Shareable { .appendingPathComponent("\(UUID().uuidString)") .appendingPathExtension(pathExtension) let renderer = ImageRenderer(content: self) + + #if os(iOS) let data = renderer.uiImage?.jpegData(compressionQuality: 0.8) + #else + let data = renderer.nsImage?.jpg(quality: 0.8) + #endif + try data?.write(to: url, options: .atomic) return .init(contentsOf: url) } catch { @@ -61,7 +67,7 @@ extension PlatformImage: Shareable { let url = URL(fileURLWithPath: NSTemporaryDirectory()) .appendingPathComponent("\(UUID().uuidString)") .appendingPathExtension(pathExtension) - let data = jpegData(compressionQuality: 0.8) + let data = jpg(quality: 0.8) try data?.write(to: url, options: .atomic) return .init(contentsOf: url) } catch {