为什么从 CGImage 中采样的颜色会根据它是否是缩略图而有所不同?

问题描述 投票:0回答:1

我有一些对 CGImage 中的像素进行采样的代码。我正在采样的图像完全是红色的。当我对全尺寸图像进行采样时,生成的颜色都是红色阴影,但如果我对从同一 URL 创建的缩略图进行采样,则生成的颜色都是黄色阴影。我从图像本身中提取了所有常量,所以这里真的很茫然。

 func analayze(imageAtURL url: URL) async throws -> [Color: Int] {
        guard let imgSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
            throw Error.cantLoadImage(url)
        }
        
        let cgImage: CGImage
        switch optimization {
        case .fullSize:
            guard let img = CGImageSourceCreateImageAtIndex(imgSource, 0, nil) else {
                throw Error.cantInstantiateImage(url)
            }
            cgImage = img
        case let .scale(maxSide):
            let options: [CFString: Any] = [
                kCGImageSourceCreateThumbnailFromImageAlways: true as CFBoolean,
                kCGImageSourceThumbnailMaxPixelSize: maxSide as CFNumber
            ]
            guard let img = CGImageSourceCreateThumbnailAtIndex(imgSource, 0, options as CFDictionary) else {
                throw Error.cantInstantiateImage(url)
            }
            cgImage = img
        default:
            throw Error.unsupportedOptimization(optimization)
        }


        let width = cgImage.width
        let height = cgImage.height

        let bytesPerRow = cgImage.bytesPerRow
        let bytesPerPixel = bytesPerRow / width
        let bitsPerComponent = cgImage.bitsPerComponent
        assert(bitsPerComponent == 8, "Expected 8 bits per component, got \(bitsPerComponent)")

        guard let pixelData = cgImage.dataProvider?.data else {
            throw Error.contextHasNoData
        }

        guard let unsafePointer = CFDataGetBytePtr(pixelData) else {
            throw Error.cantCreatePointer
        }

        let unsafeRawPointer = UnsafeRawPointer(unsafePointer)

        let points = pointsInRect(width: width, height: height)

        @Sendable
        func findClosestColorInTable(for point: DiscretePoint) -> Color? {
            let offset = (point.y * bytesPerRow) + (point.x * bytesPerPixel)
            let red = CGFloat(unsafeRawPointer.load(fromByteOffset: offset, as: UInt8.self)) / 255
            let green = CGFloat(unsafeRawPointer.load(fromByteOffset: offset + 1, as: UInt8.self)) / 255
            let blue = CGFloat(unsafeRawPointer.load(fromByteOffset: offset + 2, as: UInt8.self)) / 255
            let imgColor = Color(r: red, g: green, b: blue)
//            let nearestNeighbor = self.colorTree.nearest(to: imgColor)
//            return nearestNeighbor
            return imgColor
        }

这是全尺寸方法的图像和结果:

对于缩放方法:

swift image-processing core-graphics
1个回答
0
投票

正如 @HangarRash 所指出的, CGImageSourceCreateThumbnailAtIndex 不承诺它将返回具有线性 RGB 色彩空间的 RGB(A) 数据,这似乎是您在这里假设的。虽然您可以深入研究数据格式的所有细节,但如果性能不是绝对关键,我建议您将缩略图重新绘制到具有您想要的像素布局和色彩空间的 CGContext 中。这会简单得多,让 CoreGraphics 为您完成工作。

如果您需要避免额外的往返,请参阅 HangarRash 关于在哪里查找信息的评论,尽管您可能还需要检查色彩空间以确保您使用的是正确的转换。这变得很复杂,所以我只在您绝对需要时才推荐它。融入上下文将更容易保持一致。

© www.soinside.com 2019 - 2024. All rights reserved.