Last active
August 24, 2023 01:04
-
-
Save raphaelhanneken/cb924aa280f4b9dbb480 to your computer and use it in GitHub Desktop.
NSImage extensions for easy resizing, cropping and saving png images.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSImageExtensions.swift | |
// | |
import Cocoa | |
extension NSImage { | |
/// The height of the image. | |
var height: CGFloat { | |
return size.height | |
} | |
/// The width of the image. | |
var width: CGFloat { | |
return size.width | |
} | |
/// A PNG representation of the image. | |
var PNGRepresentation: Data? { | |
if let tiff = self.tiffRepresentation, let tiffData = NSBitmapImageRep(data: tiff) { | |
return tiffData.representation(using: .png, properties: [:]) | |
} | |
return nil | |
} | |
// MARK: Resizing | |
/// Resize the image to the given size. | |
/// | |
/// - Parameter size: The size to resize the image to. | |
/// - Returns: The resized image. | |
func resize(withSize targetSize: NSSize) -> NSImage? { | |
let frame = NSRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height) | |
guard let representation = self.bestRepresentation(for: frame, context: nil, hints: nil) else { | |
return nil | |
} | |
let image = NSImage(size: targetSize, flipped: false, drawingHandler: { (_) -> Bool in | |
return representation.draw(in: frame) | |
}) | |
return image | |
} | |
/// Copy the image and resize it to the supplied size, while maintaining it's | |
/// original aspect ratio. | |
/// | |
/// - Parameter size: The target size of the image. | |
/// - Returns: The resized image. | |
func resizeMaintainingAspectRatio(withSize targetSize: NSSize) -> NSImage? { | |
let newSize: NSSize | |
let widthRatio = targetSize.width / self.width | |
let heightRatio = targetSize.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.resize(withSize: newSize) | |
} | |
// MARK: Cropping | |
/// Resize the image, to nearly fit the supplied cropping size | |
/// and return a cropped copy the image. | |
/// | |
/// - Parameter size: The size of the new image. | |
/// - Returns: The cropped image. | |
func crop(toSize targetSize: NSSize) -> NSImage? { | |
guard let resizedImage = self.resizeMaintainingAspectRatio(withSize: targetSize) else { | |
return nil | |
} | |
let x = floor((resizedImage.width - targetSize.width) / 2) | |
let y = floor((resizedImage.height - targetSize.height) / 2) | |
let frame = NSRect(x: x, y: y, width: targetSize.width, height: targetSize.height) | |
guard let representation = resizedImage.bestRepresentation(for: frame, context: nil, hints: nil) else { | |
return nil | |
} | |
let image = NSImage(size: targetSize, | |
flipped: false, | |
drawingHandler: { (destinationRect: NSRect) -> Bool in | |
return representation.draw(in: destinationRect) | |
}) | |
return image | |
} | |
// MARK: Saving | |
/// Save the images PNG representation the the supplied file URL: | |
/// | |
/// - Parameter url: The file URL to save the png file to. | |
/// - Throws: An unwrappingPNGRepresentationFailed when the image has no png representation. | |
func savePngTo(url: URL) throws { | |
if let png = self.PNGRepresentation { | |
try png.write(to: url, options: .atomicWrite) | |
} else { | |
throw NSImageExtensionError.unwrappingPNGRepresentationFailed | |
} | |
} | |
} | |
/// Exceptions for the image extension class. | |
/// | |
/// - creatingPngRepresentationFailed: Is thrown when the creation of the png representation failed. | |
enum NSImageExtensionError: Error { | |
case unwrappingPNGRepresentationFailed | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just saying above, it did not crop the image, only resize it !