@@ -72,8 +72,9 @@ public extension Snapshotting where Format == PlatformImage, Value == (AVAudioPC
7272 /// - height: The height of the resulting image.
7373 /// - strategy: The strategy to use when generating the waveform. Defaults to `.joinedLines`.
7474 /// - mono: A boolean indicating whether to mix down to a mono signal before generating the waveform. Defaults to `true`.
75+ @available ( macOS 13 . 0 , iOS 16 . 0 , * )
7576 static func waveform( width: Int , height: Int , strategy: WaveformStrategy = . joinedLines, mono: Bool = true ) -> Snapshotting {
76- Snapshotting < PlatformView , PlatformImage > . image ( size : . init ( width : width , height : height ) )
77+ SimplySnapshotting < PlatformImage > . image ( )
7778 . pullback { buffer1, buffer2 in
7879 let verticalPadding : CGFloat = 4
7980 let waveformHeight = CGFloat ( height) - ( verticalPadding * 2 )
@@ -95,7 +96,8 @@ public extension Snapshotting where Format == PlatformImage, Value == (AVAudioPC
9596 }
9697 . padding ( . vertical, verticalPadding)
9798 . background ( Color . black)
98- return PlatformHostingView ( rootView: waveform. environment ( \. colorScheme, . light) )
99+
100+ return renderViewToImage ( waveform, width: width, height: height)
99101 }
100102 }
101103}
@@ -108,8 +110,14 @@ public extension Snapshotting where Format == PlatformImage, Value == AVAudioPCM
108110 /// - height: The height of the resulting image.
109111 /// - strategy: The strategy to use when generating the waveform. Defaults to `.joinedLines`.
110112 /// - mono: A boolean indicating whether to mix down to a mono signal before generating the waveform. Defaults to `true`.
111- static func waveform( width: Int , height: Int , strategy: WaveformStrategy = . joinedLines, mono: Bool = true ) -> Snapshotting {
112- Snapshotting < PlatformView , PlatformImage > . image ( size: . init( width: width, height: height) )
113+ @available ( macOS 13 . 0 , iOS 16 . 0 , * )
114+ static func waveform(
115+ width: Int ,
116+ height: Int ,
117+ strategy: WaveformStrategy = . joinedLines,
118+ mono: Bool = true
119+ ) -> Snapshotting {
120+ SimplySnapshotting < PlatformImage > . image ( )
113121 . pullback { buffer in
114122 let verticalPadding : CGFloat = 4
115123 let waveformHeight = CGFloat ( height) - ( verticalPadding * 2 )
@@ -121,7 +129,8 @@ public extension Snapshotting where Format == PlatformImage, Value == AVAudioPCM
121129 )
122130 . padding ( . vertical, verticalPadding)
123131 . background ( Color . black)
124- return PlatformHostingView ( rootView: waveform. environment ( \. colorScheme, . light) )
132+
133+ return renderViewToImage ( waveform, width: width, height: height)
125134 }
126135 }
127136
@@ -138,14 +147,14 @@ public extension Snapshotting where Format == PlatformImage, Value == AVAudioPCM
138147 window: [ Float ] ? = nil ,
139148 threshold: Float = 0.005
140149 ) -> Snapshotting {
141- Snapshotting < PlatformView , PlatformImage > . image ( size : . init ( width : width , height : height ) )
150+ SimplySnapshotting < PlatformImage > . image ( )
142151 . pullback { buffer in
143152 let effectiveWindow = window ?? createHannWindow ( size: Int ( buffer. frameLength) )
144153 let data = buffer
145154 . spectrum ( window: effectiveWindow)
146155 . filter { $0. amplitude > threshold }
147156 let spectrum = SpectrumView ( data: data, height: CGFloat ( height) )
148- return PlatformHostingView ( rootView : spectrum . environment ( \ . colorScheme , . light ) )
157+ return renderViewToImage ( spectrum , width : width , height : height )
149158 }
150159 }
151160
@@ -165,7 +174,7 @@ public extension Snapshotting where Format == PlatformImage, Value == AVAudioPCM
165174 imageWidth: Int = 1000
166175 ) -> Snapshotting {
167176 let height = frequencyCount
168- return Snapshotting < PlatformView , PlatformImage > . image ( size : . init ( width : imageWidth , height : height ) )
177+ return SimplySnapshotting < PlatformImage > . image ( )
169178 . pullback { buffer in
170179 let fftSize = frequencyCount * 2
171180 let lastBucketStart = Int ( buffer. frameLength) - fftSize
@@ -187,11 +196,32 @@ public extension Snapshotting where Format == PlatformImage, Value == AVAudioPCM
187196 let duration = Double ( buffer. frameLength) / buffer. format. sampleRate
188197
189198 let spectrogram = SpectrogramView ( data: data, width: width, height: height, maxFrequency: maxFrequency, duration: duration)
190- return PlatformHostingView ( rootView : spectrogram . environment ( \ . colorScheme , . light ) )
199+ return renderViewToImage ( spectrogram , width : imageWidth , height : height )
191200 }
192201 }
193202}
194203
204+ /// Renders a SwiftUI view to a platform image using ImageRenderer
205+ /// - Parameters:
206+ /// - view: The SwiftUI view to render
207+ /// - width: The width of the resulting image
208+ /// - height: The height of the resulting image
209+ /// - Returns: A platform-specific image (NSImage on macOS, UIImage on iOS)
210+ @available ( iOS 16 . 0 , macOS 13 . 0 , * )
211+ @MainActor
212+ private func renderViewToImage< Content: View > ( _ view: Content , width: Int , height: Int ) -> PlatformImage {
213+ let renderer = ImageRenderer (
214+ content: view. environment ( \. colorScheme, . light)
215+ )
216+ renderer. proposedSize = . init( width: CGFloat ( width) , height: CGFloat ( height) )
217+ renderer. scale = 2
218+ #if os(iOS)
219+ return renderer. uiImage!
220+ #else
221+ return renderer. nsImage!
222+ #endif
223+ }
224+
195225/// Creates a normalized Hann window of the specified size
196226/// - Parameter size: The number of samples in the window
197227/// - Returns: An array of Float values representing the Hann window function
0 commit comments