I am using ScreenCaptureKit to create a screenshot software,
but I found that the screenshot captured by the new API, SCScreenshotManager.captureImage, is very blurry.
This is my screenshot. It is so blurry.
But I hope it's like this.
My code is as follows.
func captureScreen(windows: [SCWindow], display: SCDisplay) async throws -> CGImage? {
let availableWindows = windows.filter { window in
Bundle.main.bundleIdentifier != window.owningApplication?.bundleIdentifier
}
let filter = SCContentFilter(display: display, including: availableWindows)
if #available(macOS 14.0, *) {
let image = try? await SCScreenshotManager.captureImage(
contentFilter: filter,
configuration: SCStreamConfiguration.defaultConfig(
width: display.width,
height: display.height
)
)
return image
} else {
return nil
}
}
extension SCStreamConfiguration {
static func defaultConfig(width: Int, height: Int) -> SCStreamConfiguration {
let config = SCStreamConfiguration()
config.width = width
config.height = height
config.showsCursor = false
if #available(macOS 14.0, *) {
config.captureResolution = .best
}
return config
}
}
Post
Replies
Boosts
Views
Activity
I'm displaying file structure using DisclosureGroup.
And I encountered a memory leak problem.
Code
Node
Node represents a file or a folder.
isExpanded is used to indicate if the child nodes are visible.
If true, it will find its child nodes, which are set into children.
If false, it will clear children for releasing references.
class Node: ObservableObject, Identifiable, Hashable, CustomStringConvertible {
// ...
@Published var name: String
@Published var children: [Node]?
@Published var isExpanded = false {
willSet {
if self.isFile {
// This node represents a file.
// It does not have any children.
return
}
if newValue {
if children?.count == 0 {
DispatchQueue.main.async {
// get child nodes
self.children = childrenOf(self.url)
}
}
} else {
if children?.count != 0 {
DispatchQueue.main.async {
// collapse child nodes
self.children?.forEach { child in
child.isExpanded = false
}
// clear children when this node is collapsed
self.children = []
}
}
}
}
}
init(/*...*/) {
// ...
print("init \(name)")
}
deinit {
// ...
print("deinit \(name)")
}
// ...
}
For convenience, I print some messages when initializing Node and deinitializing Node.
TreeNode
TreeNode displays Node using DisclosureGroup.
struct TreeNode: View {
@ObservedObject var parent: Node
@ObservedObject var node: Node
var body: some View {
if node.isFile {
Text(node.name)
} else {
DisclosureGroup(
isExpanded: $node.isExpanded,
content: {
if node.isExpanded {
ForEach(node.children ?? []) { child in
TreeNode(parent: node, node: child)
}
}
},
label: {
FolderNodeView(node: node)
}
)
}
}
}
struct FolderNodeView: View {
@ObservedObject var node: Node
var body: some View {
Label(
title: { Text(node.name) },
icon: { Image(systemName: "folder.fill") }
)
}
}
I use if node.isExpanded for lazy loading.
When node.isExpanded is true, it will show node's children and print initialization messages. Otherwise, it will hide child nodes and print deinitialization messages.
But unexpectedly it does not print any deinitialization messages when the node is collapsed. This indicates that it retains references and therefore these Node objects still exists in memory causing memory leak.
Demo
When the node is expanded, its child nodes will be displayed after loading is completed. The code works correctly.
Then I collapsed the node, it didn't print any deinitialization messages. And when I expanded it again, it initialized new nodes and deinitialized the old nodes at this time. Deinitialization seems to be delayed.
So I guess TreeNode retains references when content is hidden.
Then I deleted TreeNode in ForEach.
DisclosureGroup(
isExpanded: $node.isExpanded,
content: {
if node.isExpanded {
ForEach(node.children ?? []) { child in
// TreeNode(parent: node, node: child)
}
}
},
label: {
FolderNodeView(node: node)
}
)
It cannot display the child nodes. But it released reference correctly.
So the code works expectedly.
After that, I tried to replace TreeNode with Text or Label.
I found that none of them released references immediately when I collapsed the node.
Why did this happen?
Any idea how to fix it?
Is there any way to get dock size?
I got Dock Window using CGWindowListCopyWindowInfo.
But I found its frame covers my entire screen.
Same promble as Notification Center.
Any way to get their size?