Created
March 24, 2017 11:49
-
-
Save MaciejGad/11d8469b218817290ee77012edb46608 to your computer and use it in GitHub Desktop.
NSImage extensions for easy resizing, cropping and saving png images. Version updated for Swift 3. Originally by Raphael Hanneken https://gist.github.com/raphaelhanneken/cb924aa280f4b9dbb480
This file contains hidden or 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
extension NSImage { | |
/// Returns the height of the current image. | |
var height: CGFloat { | |
return self.size.height | |
} | |
/// Returns the width of the current image. | |
var width: CGFloat { | |
return self.size.width | |
} | |
/// Returns a png representation of the current image. | |
var PNGRepresentation: Data? { | |
if let tiff = self.tiffRepresentation, let tiffData = NSBitmapImageRep(data: tiff) { | |
return tiffData.representation(using: .PNG, properties: [:]) | |
} | |
return nil | |
} | |
/// Copies the current image and resizes it to the given size. | |
/// | |
/// - parameter size: The size of the new image. | |
/// | |
/// - returns: The resized copy of the given image. | |
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 | |
} | |
/// Copies the current image and resizes it to the size of the given NSSize, while | |
/// maintaining the aspect ratio of the original image. | |
/// | |
/// - parameter size: The size of the new image. | |
/// | |
/// - returns: The resized copy of the given image. | |
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) | |
} | |
/// Copies and crops an image to the supplied size. | |
/// | |
/// - parameter size: The size of the new image. | |
/// | |
/// - returns: The cropped copy of the given image. | |
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 | |
} | |
/// Saves the PNG representation of the current image to the HD. | |
/// | |
/// - parameter url: The location url to which to write the png file. | |
func savePNGRepresentationToURL(url: URL) throws { | |
if let png = self.PNGRepresentation { | |
try png.write(to: url, options: .atomicWrite) | |
} | |
} | |
} |
Using tiff for PNGRepresentation will result to a large Data object.
I'm using this :
var PNGRepresentation: Data? {
guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil)
else { return nil }
let imageRep = NSBitmapImageRep(cgImage: cgImage)
imageRep.size = self.size
return imageRep.representation(using: .jpeg, properties: [.compressionFactor : 0.8])
}
CompressionFactor can be an optional param.
Using tiff for PNGRepresentation will result to a large Data object.
I'm using this :
var PNGRepresentation: Data? { guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil } let imageRep = NSBitmapImageRep(cgImage: cgImage) imageRep.size = self.size return imageRep.representation(using: .jpeg, properties: [.compressionFactor : 0.8]) }CompressionFactor can be an optional param.
It doesn't make any difference, and you use a data that was originally JPG as PNG.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Awesome, thank you for updating and sharing this!