swift 为什么CGImage的采样颜色会因是否是缩略图而异?

lxkprmvk  于 5个月前  发布在  Swift
关注(0)|答案(1)|浏览(44)

我有一些在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
        }

字符串
以下是全尺寸方法的图像和结果:


的数据
对于缩放方法:


bvk5enib

bvk5enib1#

正如@HangarRash所指出的,CGImageSourceData ThumbnailAtIndex并不保证它会返回具有线性RGB颜色空间的RGB(A)数据,这似乎是你在这里假设的。虽然你可以深入研究数据格式的所有细节,但如果性能不是绝对重要的,我建议你重新-将缩略图绘制到一个CGContext中,它具有你想要的像素布局和颜色空间。这将简单得多,让CoreGraphics为你做这项工作。
如果你需要避免额外的往返,请参阅HangarRash关于在哪里查找信息的评论,尽管你可能还需要检查颜色空间以确保你使用了正确的转换。这很复杂,所以我只在你绝对需要的时候推荐它。在上下文中绘制会更容易保持一致。

相关问题