Swift设置图片尺寸
Swift设置图片尺寸

Swift设置图片尺寸

在 macOS / iOS 中,设置图片尺寸本质上是对 NSImage 或 CGImage 做缩放/重绘。不能直接修改原始 NSImage 的像素数据大小,而是需要生成一个新的图像。

1、使用 NSImage 重绘

import AppKit

func resizeImage(_ image: NSImage, to newSize: CGSize) -> NSImage? {
    let newImage = NSImage(size: newSize)
    
    newImage.lockFocus()
    defer { newImage.unlockFocus() }
    
    // 拉伸或压缩绘制原图
    image.draw(
        in: NSRect(origin: .zero, size: newSize),
        from: NSRect(origin: .zero, size: image.size),
        operation: .copy,
        fraction: 1.0
    )
    
    return newImage
}

newSize 是目标尺寸(像素单位取决于图像分辨率)。

.lockFocus() / .unlockFocus() 用于在内存中绘制新的图像。

fraction: 1.0 表示完全不透明绘制。

这种方法适用于macOS中的NSImage复制一个新的NSImage,可以用于后续压缩或保存。

2、使用 CGImage / Core Graphics 缩放

import CoreGraphics

func resizeCGImage(_ cgImage: CGImage, to newSize: CGSize) -> CGImage? {
    let colorSpace = cgImage.colorSpace ?? CGColorSpaceCreateDeviceRGB()
    guard let context = CGContext(
        data: nil,
        width: Int(newSize.width),
        height: Int(newSize.height),
        bitsPerComponent: cgImage.bitsPerComponent,
        bytesPerRow: 0,
        space: colorSpace,
        bitmapInfo: cgImage.bitmapInfo.rawValue
    ) else { return nil }

    // 绘制缩放
    context.interpolationQuality = .high
    context.draw(cgImage, in: CGRect(origin: .zero, size: newSize))
    
    return context.makeImage()
}

这种方法适用于macOS中的CGImage复制一个新的CGImage。

可以设置 interpolationQuality 来控制缩放质量(.low / .medium / .high / .none)。

3、NSBitmapImageRep 缩放(适合保存位图)

func resizeWithBitmap(_ image: NSImage, newSize: CGSize) -> Data? {
    guard let tiffData = image.tiffRepresentation,
          let bitmap = NSBitmapImageRep(data: tiffData) else { return nil }
    
    let resizedBitmap = NSBitmapImageRep(
        bitmapDataPlanes: nil,
        pixelsWide: Int(newSize.width),
        pixelsHigh: Int(newSize.height),
        bitsPerSample: bitmap.bitsPerSample,
        samplesPerPixel: bitmap.samplesPerPixel,
        hasAlpha: bitmap.hasAlpha,
        isPlanar: bitmap.isPlanar,
        colorSpaceName: bitmap.colorSpaceName,
        bytesPerRow: 0,
        bitsPerPixel: 0
    )
    
    resizedBitmap?.size = newSize
    // 重新绘制
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: resizedBitmap!)
    image.draw(in: NSRect(origin: .zero, size: newSize))
    NSGraphicsContext.restoreGraphicsState()
    
    return resizedBitmap?.representation(using: .jpeg, properties: [.compressionFactor: 1.0])
}

可以直接生成 JPEG / PNG Data。

适合直接压缩+输出。

注意事项

1、比例缩放 vs 指定大小

如果只指定 newSize,图片可能会被拉伸/压缩失真。

如果想保持比例,可以先计算缩放比例:

let aspectRatio = image.size.width / image.size.height
let targetWidth: CGFloat = 800
let targetHeight = targetWidth / aspectRatio

2、高分屏/Retina

NSImage 有 size 属性和像素分辨率两套数据,缩放时要注意 pixelsWide / pixelsHigh。

3、缩放后压缩

缩放后的图片再走 CGImageDestination 压缩,可以更好控制文件大小。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注