2017-04-13 126 views
0

我正在尝试使用swift缩放图像。这个不应该是一个困难的任务,因为我在30分钟内在C#中实现了一个缩放解决方案 - 但是,现在我已经停留了2天。缩放图像OSX Swift

我试过谷歌搜索/爬过栈帖但无济于事。我看到了两个主要的解决方案的人使用的都是:

A function written in Swift to resize an NSImage proportionately

resizeNSImage.swift

An Obj C Implementation of the above link

所以,我宁愿使用最有效的/最少的CPU密集型解决方案,根据我的研究是选项2.由于选项2使用NSImage.lockfocus()NSImage.unlockFocus,图像在非视网膜Mac上可以很好地缩放s,但在视网膜苹果机上的缩放倍数加倍。我知道这是由于Retina mac的像素密度造成的,并且是可以预期的,但我需要一种无视HiDPI规格并且只执行正常缩放操作的缩放解决方案。

这让我对选项1做了更多的研究。它看起来像一个声音函数,但它实际上不会缩放输入图像,然后将文件大小加倍,因为我保存返回的图像(大概是由于像素密度)。我发现另一个堆栈帖子与其他人有完全相同的问题,使用完全相同的实现(found here)。在两个建议的答案中,第一个不起作用,第二个是我一直试图使用的其他实现。

如果有人可以发布Swift已解决的答案,与Obj C相反,我非常感谢!

编辑: 这里是我的实现第一方案的副本 - 我把它分成两个功能:

func getSizeProportions(oWidth: CGFloat, oHeight: CGFloat) -> NSSize { 

    var ratio:Float = 0.0 
    let imageWidth = Float(oWidth) 
    let imageHeight = Float(oHeight) 

    var maxWidth = Float(0) 
    var maxHeight = Float(600) 

    if (maxWidth == 0) { 
     maxWidth = imageWidth 
    } 

    if(maxHeight == 0) { 
     maxHeight = imageHeight 
    } 

    // Get ratio (landscape or portrait) 
    if (imageWidth > imageHeight) { 
     // Landscape 
     ratio = maxWidth/imageWidth; 
    } 
    else { 
     // Portrait 
     ratio = maxHeight/imageHeight; 
    } 

    // Calculate new size based on the ratio 
    let newWidth = imageWidth * ratio 
    let newHeight = imageHeight * ratio 

    return NSMakeSize(CGFloat(newWidth), CGFloat(newHeight)) 
} 


func resizeImage(image:NSImage) -> NSImage { 
    print("original: ", image.size.width, image.size.height) 

    // Cast the NSImage to a CGImage 
    var imageRect:CGRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height) 
    let imageRef = image.cgImage(forProposedRect: &imageRect, context: nil, hints: nil) 

    // Create a new NSSize object with the newly calculated size 
    let newSize = NSSize(width: CGFloat(450), height: CGFloat(600)) 
    //let newSize = getSizeProportions(oWidth: CGFloat(image.size.width), oHeight: CGFloat(image.size.height)) 

    // Create NSImage from the CGImage using the new size 
    let imageWithNewSize = NSImage(cgImage: imageRef!, size: newSize) 

    print("scaled: ", imageWithNewSize.size.width, imageWithNewSize.size.height) 

    return NSImage(data: imageWithNewSize.tiffRepresentation!)! 
} 

编辑2:

正如Zneak指出:我需要将返回的图像保存到磁盘 - 使用这两种实现,我的保存功能将文件成功写入磁盘。虽然我不认为我的保存功能,可以与我目前的大小调整的实现搞砸,我只是在情况下附反正它:

func saveAction(image: NSImage, url: URL) { 

    if let tiffdata = image.tiffRepresentation, 
    let bitmaprep = NSBitmapImageRep(data: tiffdata) { 

    let props = [NSImageCompressionFactor: Appearance.imageCompressionFactor] 
    if let bitmapData = NSBitmapImageRep.representationOfImageReps(in: [bitmaprep], using: .JPEG, properties: props) { 

     let path: NSString = "~/Desktop/out.jpg" 
     let resolvedPath = path.expandingTildeInPath 

     try! bitmapData.write(to: URL(fileURLWithPath: resolvedPath), options: []) 

     print("Your image has been saved to \(resolvedPath)") 
    } 
} 
+0

“应该”还是“不应该”?平凡意味着容易。另外,你是在做这个,是为了在屏幕上显示它还是把它写回到磁盘或其他东西?缩放到更大或更小的尺寸? – zneak

+0

编辑的操作系统:) – amartin94

+0

和im缩小写回磁盘 – amartin94

回答

0

为了其他任何人遇到这样的问题 - 我最终花无数个小时试图找到一个办法做到这一点,并结束了刚刚起步的屏幕比例因子(1正常淅淅沥沥,2视网膜)...该代码看起来是这样的:

func getScaleFactor() -> CGFloat { 
    return NSScreen.main()!.backingScaleFactor 
} 

然后,一旦你有你的比例因子或者正常缩放或者是视网膜尺寸的一半:

if (scaleFactor == 2) { 
    //halve size proportions for saving on Retina Macs 
    return NSMakeSize(CGFloat(oWidth*ratio)/2, CGFloat(oHeight*ratio)/2) 
} else { 
    return NSMakeSize(CGFloat(oWidth*ratio), CGFloat(oHeight*ratio)) 
} 
+0

而不是检查具体的比例因子,你应该除以它: CGFloat的(oWidth *比)/ scaleFactor'。这样,如果苹果公司引入了支持比例因子是其他值的设备/模式,您的代码将继续正常工作。但*做*先检查0! – DarkDust