Skip to content

Commit

Permalink
Merge pull request #16 from igorkulman/ratio-fix
Browse files Browse the repository at this point in the history
Correctly resizing wallpapers
  • Loading branch information
igorkulman authored Dec 3, 2020
2 parents c8c01a7 + 8afa863 commit 21f15b0
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Sources/ChangeMenuBarColor/Commands/Gradient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class Gradient: Command, ParsableCommand {
return nil
}

guard let resizedWallpaper = wallpaper.resized(to: screen.size) else {
guard let resizedWallpaper = wallpaper.crop(size: screen.size) else {
print("Cannot not resize provided wallpaper to screen size".red)
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ChangeMenuBarColor/Commands/SolidColor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final class SolidColor: Command, ParsableCommand {
return nil
}

guard let resizedWallpaper = wallpaper.resized(to: screen.size) else {
guard let resizedWallpaper = wallpaper.crop(size: screen.size) else {
print("Cannot not resize provided wallpaper to screen size".red)
return nil
}
Expand Down
104 changes: 86 additions & 18 deletions Sources/ChangeMenuBarColor/Extensions/NSImage+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,97 @@ extension NSImage {
return self.cgImage(forProposedRect: &rect, context: nil, hints: nil)
}

func resized(to newSize: NSSize) -> NSImage? {
guard let bitmapRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(newSize.width), pixelsHigh: Int(newSize.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0) else {
print("Cannot create bitmap image for resizing".red)
return nil
}

bitmapRep.size = newSize
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bitmapRep)
draw(in: NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height), from: .zero, operation: .copy, fraction: 1.0)
NSGraphicsContext.restoreGraphicsState()

let resizedImage = NSImage(size: newSize)
resizedImage.addRepresentation(bitmapRep)
return resizedImage
}

var jpgData: Data? {
guard let tiffRepresentation = tiffRepresentation, let bitmapImage = NSBitmapImageRep(data: tiffRepresentation) else {
print("Cannot create data from bitmap image".red)
return nil
}

return bitmapImage.representation(using: .jpeg, properties: [:])
}
}

var height: CGFloat {
return self.size.height
}

var width: CGFloat {
return self.size.width
}

func copy(size: NSSize) -> NSImage? {
// Create a new rect with given width and height
let frame = NSMakeRect(0, 0, size.width, size.height)

// Get the best representation for the given size.
guard let rep = self.bestRepresentation(for: frame, context: nil, hints: nil) else {
return nil
}

// Create an empty image with the given size.
let img = NSImage(size: size)

// Set the drawing context and make sure to remove the focus before returning.
img.lockFocus()
defer { img.unlockFocus() }

// Draw the new image
if rep.draw(in: frame) {
return img
}

// Return nil in case something went wrong.
return nil
}

func resizeWhileMaintainingAspectRatioToSize(size: NSSize) -> NSImage? {
let newSize: NSSize

let widthRatio = size.width / self.width
let heightRatio = size.height / self.height

if widthRatio > heightRatio {
newSize = NSSize(width: floor(self.width * widthRatio), height: floor(self.height * widthRatio))
} else {
newSize = NSSize(width: floor(self.width * heightRatio), height: floor(self.height * heightRatio))
}

return self.copy(size: newSize)
}

func crop(size: NSSize) -> NSImage? {
// Resize the current image, while preserving the aspect ratio.
guard let resized = self.resizeWhileMaintainingAspectRatioToSize(size: size) else {
return nil
}
// Get some points to center the cropping area.
let x = floor((resized.width - size.width) / 2)
let y = floor((resized.height - size.height) / 2)

// Create the cropping frame.
let frame = NSMakeRect(x, y, size.width, size.height)

// Get the best representation of the image for the given cropping frame.
guard let rep = resized.bestRepresentation(for: frame, context: nil, hints: nil) else {
return nil
}

// Create a new image with the new size
let img = NSImage(size: size)

img.lockFocus()
defer { img.unlockFocus() }

if rep.draw(in: NSMakeRect(0, 0, size.width, size.height),
from: frame,
operation: NSCompositingOperation.copy,
fraction: 1.0,
respectFlipped: false,
hints: [:]) {
// Return the cropped image.
return img
}

// Return nil in case anything fails.
return nil
}
}

0 comments on commit 21f15b0

Please sign in to comment.