Skip to content

Commit 765155c

Browse files
committed
♻️ Improve image manipulation code for better quality of generated images
1 parent aa55a63 commit 765155c

2 files changed

Lines changed: 76 additions & 26 deletions

File tree

Sources/ChangeMenuBarColor/Commands/Abstract/Command.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ class Command {
5252
return wallpaper
5353
}
5454

55+
// Use our new function to get the original wallpaper directly from the file
56+
if let originalWallpaper = getOriginalWallpaper(for: screen) {
57+
originalWallpaper.adjustSize()
58+
return originalWallpaper
59+
}
60+
61+
// Fallback to the old method if our new function fails
5562
guard let path = NSWorkspace.shared.desktopImageURL(for: screen), let wallpaper = NSImage(contentsOf: path) else {
5663
Log.error("Cannot read the currently set macOS wallpaper. Try providing a specific wallpaper as a parameter instead.")
5764
return nil

Sources/ChangeMenuBarColor/Extensions/ImageFunctions.swift

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,58 @@ func createSolidImage(color: NSColor, width: CGFloat, height: CGFloat) -> NSImag
4545
}
4646

4747
func combineImages(baseImage: NSImage, addedImage: NSImage) -> NSImage? {
48-
guard let context = createContext(width: baseImage.size.width, height: baseImage.size.height) else {
49-
Log.error("Could not create graphical context when merging images")
50-
return nil
51-
}
52-
53-
guard let baseImageCGImage = baseImage.cgImage, let addedImageCGImage = addedImage.cgImage else {
54-
Log.error("Could not create cgImage when merging images")
55-
return nil
56-
}
57-
58-
// Draw the base image (wallpaper)
59-
context.draw(baseImageCGImage, in: CGRect(x: 0, y: 0, width: baseImage.size.width, height: baseImage.size.height))
48+
// Create a high-quality representation context
49+
let width = baseImage.size.width
50+
let height = baseImage.size.height
6051

61-
// The original method calculated this rect incorrectly for some displays
62-
// So we'll ensure we're only drawing the menu bar portion
63-
let menuBarPortionRect = CGRect(
64-
x: 0,
65-
y: baseImage.size.height - addedImage.size.height,
66-
width: baseImage.size.width, // Ensure we cover the full width
67-
height: min(addedImage.size.height, 40 * NSScreen.main?.backingScaleFactor ?? 2) // Safety limit
52+
// Create bitmap representation with higher quality options
53+
let rep = NSBitmapImageRep(
54+
bitmapDataPlanes: nil,
55+
pixelsWide: Int(width),
56+
pixelsHigh: Int(height),
57+
bitsPerSample: 8,
58+
samplesPerPixel: 4,
59+
hasAlpha: true,
60+
isPlanar: false,
61+
colorSpaceName: .calibratedRGB,
62+
bytesPerRow: 0,
63+
bitsPerPixel: 0
6864
)
6965

70-
// Draw the menu bar portion
71-
context.draw(addedImageCGImage, in: menuBarPortionRect)
72-
73-
guard let composedImage = context.makeImage() else {
74-
Log.error("Could not create composed image when merging with the wallpaper")
66+
rep?.size = NSSize(width: width, height: height)
67+
68+
// Create drawing context
69+
NSGraphicsContext.saveGraphicsState()
70+
guard let rep = rep, let context = NSGraphicsContext(bitmapImageRep: rep) else {
71+
Log.error("Could not create graphics context when merging images")
72+
NSGraphicsContext.restoreGraphicsState()
7573
return nil
7674
}
77-
78-
return NSImage(cgImage: composedImage, size: baseImage.size)
75+
NSGraphicsContext.current = context
76+
77+
// Draw the base image (wallpaper) at full quality
78+
baseImage.draw(in: NSRect(x: 0, y: 0, width: width, height: height),
79+
from: NSRect(x: 0, y: 0, width: baseImage.size.width, height: baseImage.size.height),
80+
operation: .copy,
81+
fraction: 1.0)
82+
83+
// Determine proper menu bar height - use a reasonable default if needed
84+
let scaleFactor = NSScreen.main?.backingScaleFactor ?? 2.0
85+
let menuBarHeight = min(addedImage.size.height, 24 * scaleFactor)
86+
87+
// Draw the menu bar portion with high quality
88+
addedImage.draw(in: NSRect(x: 0, y: height - menuBarHeight, width: width, height: menuBarHeight),
89+
from: NSRect(x: 0, y: 0, width: addedImage.size.width, height: menuBarHeight),
90+
operation: .sourceOver,
91+
fraction: 1.0)
92+
93+
NSGraphicsContext.restoreGraphicsState()
94+
95+
// Create final image from the bitmap representation
96+
let finalImage = NSImage(size: NSSize(width: width, height: height))
97+
finalImage.addRepresentation(rep)
98+
99+
return finalImage
79100
}
80101

81102
func createContext(width: CGFloat, height: CGFloat) -> CGContext? {
@@ -89,3 +110,25 @@ func colorName(_ color: NSColor) -> String {
89110
return color.description
90111
}
91112
}
113+
114+
func getOriginalWallpaper(for screen: NSScreen) -> NSImage? {
115+
let workspace = NSWorkspace.shared
116+
if let url = workspace.desktopImageURL(for: screen) {
117+
do {
118+
let imageData = try Data(contentsOf: url)
119+
if let image = NSImage(data: imageData) {
120+
Log.debug("Successfully loaded original wallpaper from \(url.path)")
121+
return image
122+
} else {
123+
Log.error("Failed to convert data to NSImage")
124+
return nil
125+
}
126+
} catch {
127+
Log.error("Failed to load original wallpaper: \(error)")
128+
return nil
129+
}
130+
} else {
131+
Log.error("Could not get desktop image URL")
132+
return nil
133+
}
134+
}

0 commit comments

Comments
 (0)