缩放图像 OSX Swift
Scaling an image OSX Swift
我目前正在尝试使用 swift 缩放图像。这 应该 是一项艰巨的任务,因为我已经在 30 分钟内用 C# 实现了一个缩放解决方案 - 然而,我已经被困了 2几天了。
我已经通过堆栈 post 尝试 googling/crawling 但无济于事。我见过人们使用的两个主要解决方案是:
A function written in Swift to resize an NSImage proportionately
和
An Obj C Implementation of the above link
所以我更愿意使用最 efficient/least cpu 密集的解决方案,根据我的研究,这是选项 2。由于选项 2 使用 NSImage.lockfocus()
和 NSImage.unlockFocus
,该图像在非 Retina Mac 上可以很好地缩放,但在 Retina Mac 上缩放尺寸加倍。我知道这是由于 Retina mac 的像素密度造成的,这是可以预料的,但我需要一个忽略 HiDPI 规范并只执行正常缩放操作的缩放解决方案。
这让我对选项 1 进行了更多研究。它看起来像是一个合理的函数,但它实际上并没有缩放输入图像,然后在我保存返回的图像时将文件大小加倍(可能是由于像素密度) .我发现另一个堆栈 post 与其他人有与我完全相同的问题,使用完全相同的实现 (found here)。在两个建议的答案中,第一个不起作用,第二个是我一直尝试使用的另一个实现。
如果人们能够 post 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)")
}
}
对于遇到此问题的任何其他人 - 我最终花了无数小时试图找到一种方法来做到这一点,并最终得到屏幕的缩放因子(普通 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))
}
我目前正在尝试使用 swift 缩放图像。这 应该 是一项艰巨的任务,因为我已经在 30 分钟内用 C# 实现了一个缩放解决方案 - 然而,我已经被困了 2几天了。
我已经通过堆栈 post 尝试 googling/crawling 但无济于事。我见过人们使用的两个主要解决方案是:
A function written in Swift to resize an NSImage proportionately
和
An Obj C Implementation of the above link
所以我更愿意使用最 efficient/least cpu 密集的解决方案,根据我的研究,这是选项 2。由于选项 2 使用 NSImage.lockfocus()
和 NSImage.unlockFocus
,该图像在非 Retina Mac 上可以很好地缩放,但在 Retina Mac 上缩放尺寸加倍。我知道这是由于 Retina mac 的像素密度造成的,这是可以预料的,但我需要一个忽略 HiDPI 规范并只执行正常缩放操作的缩放解决方案。
这让我对选项 1 进行了更多研究。它看起来像是一个合理的函数,但它实际上并没有缩放输入图像,然后在我保存返回的图像时将文件大小加倍(可能是由于像素密度) .我发现另一个堆栈 post 与其他人有与我完全相同的问题,使用完全相同的实现 (found here)。在两个建议的答案中,第一个不起作用,第二个是我一直尝试使用的另一个实现。
如果人们能够 post 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)")
}
}
对于遇到此问题的任何其他人 - 我最终花了无数小时试图找到一种方法来做到这一点,并最终得到屏幕的缩放因子(普通 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))
}