【问题标题】:Cocoa: Capture Screen and scale image on saving in SwiftCocoa:在 Swift 中保存时捕获屏幕并缩放图像
【发布时间】:2021-12-09 20:25:36
【问题描述】:

下面的代码我用来在 macOS 应用程序中捕获屏幕,

let img = CGDisplayCreateImage(CGMainDisplayID())

guard let destination = FileManager.default.urls(for: .downloadsDirectory,
    in: .userDomainMask).first?.appendingPathComponent("shot.jpg", isDirectory: false)
else {
    print("Unable to save captured image!")
    return
}
            
let properties: CFDictionary = [
    kCGImagePropertyPixelWidth: "900",
    kCGImagePropertyPixelHeight: "380"
] as CFDictionary
            
if let dest = CGImageDestinationCreateWithURL(destination as CFURL, kUTTypeJPEG, 1, properties) {
    CGImageDestinationAddImage(dest, img!, properties)
    CGImageDestinationFinalize(dest)
}
else {
    print("Unable to create captured image to the destination!")
}

我必须在保存时将图像缩放到特定大小。所以,我使用了CFDictionary 和图像的width, heigh 属性。但似乎我做错了。请帮我找出正确的解决方案。谢谢!

【问题讨论】:

  • 提示:NSImgedraw(in:from:operation:fraction:)
  • @ElTomato 如果我将 CGImage 转换为 NSImage ,则 NSImage 容量的 JPEG 表示将高于存储中原始未缩放的图像容量。这就是问题所在。
  • “看来我做错了”并不能真正描述您面临的问题。如果您不想调整图像大小,那么您要解决的问题是什么?
  • @ElTomato,我正在寻找解决方案来调整图像大小,同时通过设置properties 或任何其他方式将其从 CGImage 中保存。 developer.apple.com/documentation/imageio/cgimageproperties/…
  • 再一次,“看来我做错了”并不能真正描述您面临的问题。

标签: swift cocoa swift5


【解决方案1】:

首先,您不能使用CGImageDestinationCreateWithURLCGImageDestinationAddImage 调整大小。如果您查看文档herehere,您会注意到kCGImagePropertyPixelWidthkCGImagePropertyPixelHeight 均不受支持。

您需要手动调整大小。如果您觉得它有帮助,您可以使用此工具或对其进行修改。它支持填充(拉伸)和适合(在保持原始纵横比的同时缩放)内容模式。如果您指定.fit,它将使绘图在结果图像中居中。如果您指定.fill,它将填充整个空间并拉伸它需要的任何维度。

enum ImageResizer {

    enum ContentMode {
        case fill
        case fit
    }

    enum Error: Swift.Error {
        case badOriginal
        case resizeFailed
    }

    static func resize(_ source: CGImage, to targetSize: CGSize, mode: ContentMode) throws -> CGImage {

        let context = CGContext(
            data: nil,
            width: Int(targetSize.width),
            height: Int(targetSize.height),
            bitsPerComponent: source.bitsPerComponent,
            bytesPerRow: 0,
            space: source.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!,
            bitmapInfo: source.bitmapInfo.rawValue
        )

        guard let context = context else {
            throw Error.badOriginal
        }

        let drawingSize: CGSize
        switch mode {
        case .fill:
            drawingSize = targetSize
        case .fit:
            drawingSize = CGSize(width: source.width, height: source.height)
                .scaledToFit(target: targetSize)
        }

        let drawRect = CGRect(origin: .zero, size: targetSize)
            .makeCenteredRect(withSize: drawingSize)

        context.interpolationQuality = .high
        context.draw(source, in: drawRect)

        guard let result = context.makeImage() else {
            throw Error.resizeFailed
        }

        return result
    }
}

ImageResizer 依赖于这些 CG 扩展来缩放源图像和居中缩放图像:

extension CGSize {

    var maxDimension: CGFloat {
        Swift.max(width, height)
    }

    var minDimension: CGFloat {
        Swift.min(width, height)
    }

    func scaled(by scalar: CGFloat) -> CGSize {
        CGSize(width: width * scalar, height: height * scalar)
    }

    func scaleFactors(to target: CGSize) -> CGSize {
        CGSize(
            width: target.width / width,
            height: target.height / height
        )
    }

    func scaledToFit(target: CGSize) -> CGSize {
        return scaled(by: scaleFactors(to: target).minDimension)
    }
}

extension CGRect {
    func makeCenteredRect(withSize size: CGSize) -> CGRect {
        let origin = CGPoint(
            x: midX - size.width / 2.0,
            y: midY - size.height / 2.0
        )
        return CGRect(origin: origin, size: size)
    }
}

另外,如果您要保存到 .downloadsDirectory,请确保设置了 permissions

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 2021-02-01
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多