How to resize - resample - change file size - NSImage

泪湿孤枕 提交于 2019-12-12 03:47:18

问题


I have made a lot of search on google, followed a lot of GitHub code, without success.

I need to read a jpeg file, which have a DPI = 72, and size = 16000x1096 for example I need, then, to resize it, in order to save a jpeg file, with 72 DPI, 800x548 pixels this, under OSX, so I can use NSIMAGE, not UIImage !

I don't care if I lose some quality !

finally, after making som ma-ny tries, I put here my latest code, and require some help please :

    // get source image, jpeg, 1600x1196, 72 dpi
    let sourceImage = NSImage(contentsOfFile: source)

    // compute the scale, to have the longest size = 800 pixels. 72 DPI
    let width = CGFloat(sourceImage!.size.width)
    let height = CGFloat(sourceImage!.size.height)
    var scale = CGFloat( 800.0 / width)
    if width < height {
        scale = 800.0 / height
    }
    let newSize:NSSize = NSSize(width: Int(width * scale), height: Int(height * scale))
    print ("new size : " + String(describing: newSize) )

    // create a new image, with the "small" size
    let newImage = NSImage(size: NSSize(width: newSize.width, height: newSize.height))
    // lockfocus : draw will be done in this image
    newImage.lockFocus()
    // interpolation = low, because I don't care of quality
    NSGraphicsContext.current()?.imageInterpolation = NSImageInterpolation.low
    // draw the big image, into the small one
    sourceImage!.draw(in: NSMakeRect(0, 0, newSize.width, newSize.height), from: NSMakeRect(0, 0, width, height), operation: NSCompositingOperation.copy, fraction: CGFloat(1.0))
    newImage.unlockFocus()

    print("newImage size: " + String(describing: newImage.size))
    // display : newImage size: 800 x 598

    let cgRef = newImage.cgImage(forProposedRect: nil, context: nil, hints: nil)
    let newRep = NSBitmapImageRep(cgImage: cgRef!)
    newRep.size = newSize

    let jfifProperties = NSDictionary(dictionary: [kCGImagePropertyJFIFIsProgressive:kCFBooleanTrue])
    let properties = NSDictionary(dictionary: [kCGImageDestinationLossyCompressionQuality:1.0,
                                               kCGImagePropertyJFIFDictionary:jfifProperties,
                                               kCGImagePropertyDPIHeight: 72.0,
                                               kCGImagePropertyDPIWidth:72.0,
                                               kCGImagePropertyPixelHeight: 1.0,
                                               kCGImagePropertyPixelWidth: 1.0
                                               ])

    let data = newRep.representation(using: .JPEG, properties: properties as! [String : Any]) //[:])
    do {
        let url = URL(string: "file://" + destination)
        try data?.write(to: url!) //, options: false)
    }
    catch let error as NSError {
        resizeError = error.localizedDescription
        return false
    }

This code does not work properly. I obtain a file, which is 144 DPI, and 1600 x 1096 !

if I print, under debugger, the variable newImage, It display this :

Printing description of newImage: \n\t< (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Color LCD)>\n\t\twidth = 1600, height = 1196, bpc = 8, bpp = 32, row bytes = 6400 \n\t\tkCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Little \n\t\tis mask? No, has mask? No, has matte? No, should interpolate? Yes>"

as we can see, the content seem to have the same size than the original, isn't it ?

I really need some help, please, I am blocked, and don't find any solution.

thanks for any answer, who could help me.

Best regards Olivier


回答1:


I found the solution myself, but I appreciate that people tried to help me. thank you to you.

here is how I fixed it :

    // get source image, jpeg, 1600x1196, 72 dpi
    let sourceImage = NSImage(contentsOfFile: source)

    // compute the scale, to have the longest size = 800 pixels. 72 DPI
    let width = CGFloat(sourceImage!.size.width)
    let height = CGFloat(sourceImage!.size.height)
    var scale = CGFloat( resizedLongestSize / width)
    if width < height {
        scale = resizedLongestSize / height
    }
    let newSize:NSSize = NSSize(width: Int(width * scale), height: Int(height * scale))

    // create NSBitmapRep manually, if using cgImage, the resulting size is wrong
    let rep = NSBitmapImageRep(bitmapDataPlanes: nil,
                               pixelsWide: Int(newSize.width),
                               pixelsHigh: Int(newSize.height),
                               bitsPerSample: 8,
                               samplesPerPixel: 4,
                               hasAlpha: true,
                               isPlanar: false,
                               colorSpaceName: NSDeviceRGBColorSpace,
                               bytesPerRow: Int(newSize.width * 4),
                               bitsPerPixel: 32)

    let ctx = NSGraphicsContext(bitmapImageRep: rep!)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrent( ctx )
    sourceImage!.draw(in: NSMakeRect(0, 0, newSize.width, newSize.height))
    ctx?.flushGraphics()
    NSGraphicsContext.restoreGraphicsState()

    // Get NSData, and save it
    let data = rep?.representation(using: .JPEG, properties: [:]) // properties as! [String : Any]) //
    do {
        let url = URL(string: "file://" + destination)
        try data?.write(to: url!) //, options: false)
    }
    catch let error as NSError {
        resizeError = error.localizedDescription
        return false
    }

this code works well, and provide a picture, in a file, resized, with a limited set of EXIF data, which would be easy to fill if needed.

thanks Olivier



来源:https://stackoverflow.com/questions/41677780/how-to-resize-resample-change-file-size-nsimage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!