裁剪NSImage(macOS)正方形没有扭曲

问题描述:

我正在使用下面的代码来在macOS上Swift中调整图像的大小。这是行得通的,但如果图像不是以方形开始的,则调整大小会压缩图像。裁剪NSImage(macOS)正方形没有扭曲

如何调整图像大小,然后将其绘制在中心位置并保持比例,如果图像不是正方形,则可以防止压扁?

func resize(image: NSImage, w: CGFloat, h: CGFloat) -> NSImage { 
    var destSize = NSMakeSize(CGFloat(w), CGFloat(h)) 
    var newImage = NSImage(size: destSize) 
    newImage.lockFocus() 
    image.draw(in: NSMakeRect(0, 0, destSize.width, destSize.height), from: NSMakeRect(0, 0, image.size.width, image.size.height), operation: NSCompositingOperation.sourceOver, fraction: CGFloat(1)) 
    newImage.unlockFocus() 
    newImage.size = destSize 
    return NSImage(data: newImage.tiffRepresentation!)! 
} 

谢谢

+0

从代码,它似乎不像你裁剪图像。看起来你正在尝试调整大小。请确认这是你想要的。 – ryantxr

下面的代码行的问题是:

image.draw(in: NSMakeRect(0, 0, destSize.width, destSize.height), from: NSMakeRect(0, 0, image.size.width, image.size.height), operation: NSCompositingOperation.sourceOver, fraction: CGFloat(1)) 

您是来自来源的整个矩形绘制到目的地的整个矩形。这将因此缩放图像以适应目的地,而您想保持宽高比。您需要决定如何显示最终图像并相应地调整源矩形或目标矩形。

例如,如果要缩放结果以显示整个图像,则需要调整目标矩形的宽度或高度,使其与源宽高比相同。

或者,如果您想裁剪结果,则需要调整源矩形的宽度或高度,并再次保持相同的宽高比。如果您想裁剪(例如)顶部和底部,则还必须调整源矩形的原点。

其他一些功能如draw(in:from:operation:fraction:)可以为您处理缩放,因此根据您的需要,它们可能会更好。

假设您想要将整个源图像放入目标图像空间(或大小),保持原始图像的高宽比并在图像不适合目标时添加一些空白区域。

有三种情况需要考虑。

  1. 源和目标的高宽比是相同的。

    • 没问题,只是调整大小。
  2. 长宽比目的地比源

    • 高度更宽是驱动值(因为它是更小)。
    • 找出从源到目标的高度比例。
    • 使用该比率从源宽度计算目标宽度。
  3. 长宽比目的地比源

    • 宽度更高是驱动值。
    • 找出从源到目标的宽度比例。
    • 使用该比率来计算源高度的目标高度。

我创造了这个功能来计算你需要的大小。

func calcNewSize(source: NSSize, destination: NSSize) -> NSSize { 
    let widthRatio: Float = Float(destination.width)/Float(source.width) 
    let heightRatio: Float = Float(destination.height)/Float(source.height) 
    var newSize = NSSize() 

    print("widthRatio \(widthRatio) heightRatio \(heightRatio)") 

    if widthRatio == heightRatio { 
     print("use same ratio") 
     newSize = destination 
    } 
    else if widthRatio > heightRatio { 
     print("use height ratio") 
     newSize.height = source.height * CGFloat(heightRatio) 
     newSize.width = source.width * CGFloat(heightRatio) 
    } 
    else { 
     print("use width ratio") 
     newSize.height = source.height * CGFloat(widthRatio) 
     newSize.width = source.width * CGFloat(widthRatio) 
    } 
    return newSize 
} 
+0

这听起来像是正确的事情。我希望它能够绘制图像,以便剪切图像的多余部分而不是空白区域。这是否意味着基于更短的死亡而不是更长的时间来调整大小?谢谢。 –

+0

如果你要裁剪,那么你不希望整个源图像,只有它的一部分。根据较小的比例调整大小。弄清楚如何通过从目的地向后计算来裁剪源,以便选择所需源的一部分。 – ryantxr

+0

还有一个假设,即源始终大于目的地。如果不是,你必须决定你想要做什么。缩放图像失去质量。 – ryantxr