A Swift question. Not an Obj-C question. Please don't mark it as duplicate
I am trying to write a class that generates a JPEG thumbnail on OS X. I hope I have something sensible that forms the scaled down NSImage but I'm struggling to write a JPEG file to disk.
class ImageThumbnail {
let size = CGSize(width: 128, height: 128)
var originalPath = ""
init(originalPath: String){
self.originalPath = originalPath
}
func generateThumbnail() {
let url = NSURL(fileURLWithPath: originalPath)
if let imageSource = CGImageSourceCreateWithURL(url, nil) {
let options: [NSString: NSObject] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height) / 2.0,
kCGImageSourceCreateThumbnailFromImageAlways: true
]
let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options)
let scaledImage = cgImage.flatMap { NSImage(CGImage: $0, size: size) }
// How do I write scaledImage to a JPEG file?
}
}
}
Example usage: ImageThumbail(originalPath: "/path/to/original").generateThumbnail()
First you need to get a bitmap representation of the image, get a JPEG representation of that image (or whatever format you want), and then write the binary data to a file:
if let bits = scaledImage?.representations.first as? NSBitmapImageRep {
let data = bits.representationUsingType(.NSJPEGFileType, properties: [:])
data?.writeToFile("/path/myImage.jpg", atomically: false)
}
NSBitmapImageFileType
gives you a choice of representations:
public enum NSBitmapImageFileType : UInt {
case NSTIFFFileType
case NSBMPFileType
case NSGIFFileType
case NSJPEGFileType
case NSPNGFileType
case NSJPEG2000FileType
}
It appears that either in Swift 3 NSCGImageSnapshotRep
no longer casts as NSBitmapImageRep
, or this works for only some images (I can't tell which is true as I only encountered images that do not cast to NSBitmapImageRep in my case when loading some JPEG data into an NSImage, then trying to encode a JPEG representation again).
This slight alteration to another answer works for me in Swift 3 + macOS Sierra SDK in Xcode 8:
let cgImage = img.cgImage(forProposedRect: nil, context: nil, hints: nil)!
let bitmapRep = NSBitmapImageRep(cgImage: cgImage)
let jpegData = bitmapRep.representation(using: NSBitmapImageFileType.JPEG, properties: [:])!
(Please excuse the forced unwraps, just there for brevity – definitely optionals to check in production code given current SDK has introduced optionality here.)
extension NSImage {
func imagePNGRepresentation() -> NSData? {
if let imageTiffData = self.tiffRepresentation, let imageRep = NSBitmapImageRep(data: imageTiffData) {
// let imageProps = [NSImageCompressionFactor: 0.9] // Tiff/Jpeg
// let imageProps = [NSImageInterlaced: NSNumber(value: true)] // PNG
let imageProps: [String: Any] = [:]
let imageData = imageRep.representation(using: NSBitmapImageFileType.PNG, properties: imageProps) as NSData?
return imageData
}
return nil
}
}
if let thumbImageData = thumbimage.imagePNGRepresentation() {
thumbImageData.write(toFile: "/path/to/thumb.png", atomically: false)
}
This extension:
public extension NSImage {
func write(to url: URL, format: NSBitmapImageRep.FileType, props: [NSBitmapImageRep.PropertyKey : Any] ) -> Result<URL, Error> {
return self.representations.first
.asNonOptional
.map { $0 as? NSBitmapImageRep }
.flatMap { data -> R<NSBitmapImageRep> in data.asNonOptional }
.map { $0.representation(using: .jpeg, properties: props) }
.flatMap{ $0.asNonOptional }
.map { try? $0.write(to: url) }
.map { $0.asNonOptional }
.map { _ in url}
}
}
works with most needed file formats and supports of any needed properties.
usage:
_ = someImage.write(to: url, format: .png, props: [.compressionFactor : NSNumber(floatLiteral: 1.0)])
_ = someImage.write(to: url, format: .jpeg, props: [.compressionFactor : NSNumber(floatLiteral: 1.0)])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.