【问题标题】:Scaling an image OSX Swift缩放图像 OSX Swift
【发布时间】:2017-04-13 04:05:15
【问题描述】:

我目前正在尝试使用 swift 缩放图像。这不应该是一项艰巨的任务,因为我已经在 30 分钟内用 C# 实现了缩放解决方案 - 但是,我已经被困了 2 天了。

我尝试过在堆栈帖子中进行谷歌搜索/爬网,但无济于事。我见过人们使用的两个主要解决方案是:

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 上正常缩放,但在视网膜 mac 上的缩放大小加倍。我知道这是由于 Retina mac 的像素密度,这是意料之中的,但我需要一个忽略 HiDPI 规范并只执行正常缩放操作的缩放解决方案。

这导致我对选项 1 进行了更多研究。这似乎是一个合理的功能,但它实际上不会缩放输入图像,然后在我保存返回的图像时将文件大小加倍(可能是由于像素密度)。我发现另一个堆栈帖子与其他人有完全相同的问题,使用完全相同的实现 (found here)。在两个建议的答案中,第一个不起作用,第二个是我一直在尝试使用的另一个实现。

如果人们可以发布 Swift 化的答案,而不是 Obj C,我将非常感激!

编辑: 这是我实现第一个解决方案的副本 - 我将其分为 2 个功能:

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)")
    }
}

【问题讨论】:

  • “应该”还是“不应该”?琐碎意味着容易。另外,您这样做是为了在屏幕上显示它还是将其写回磁盘或其他东西?缩放到更大或更小的尺寸?
  • 编辑了 OP :)
  • 并且我正在缩小以写回磁盘
  • CGFloat转成Float再转回CGFloat的目的是什么?在 Swift 中,if 表达式周围不需要括号。
  • 完全忘记为帖子更改它...最初它们都是浮动的,但我已经更改了很多不同的部分以使其正常工作

标签: swift image macos cocoa nsimage


【解决方案1】:

对于遇到此问题的其他人 - 我最终花费了无数小时试图找到解决此问题的方法,结果只是获得了屏幕的缩放因子(普通 mac 为 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))
}

【讨论】:

  • 您应该除以它,而不是检查特定的比例因子:CGFloat(oWidth*ratio)/scaleFactor。这样,如果 Apple 引入支持比例因子为其他值的设备/模式,您的代码将继续正常工作。但是首先检查0!
  • 这将是一个很好的方法 - 虽然我很高兴让它工作:P
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-01-04
  • 2018-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
相关资源
最近更新 更多