我有一些对 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
}
这是全尺寸方法的图像和结果:
对于缩放方法:
正如 @HangarRash 所指出的, CGImageSourceCreateThumbnailAtIndex 不承诺它将返回具有线性 RGB 色彩空间的 RGB(A) 数据,这似乎是您在这里假设的。虽然您可以深入研究数据格式的所有细节,但如果性能不是绝对关键,我建议您将缩略图重新绘制到具有您想要的像素布局和色彩空间的 CGContext 中。这会简单得多,让 CoreGraphics 为您完成工作。
如果您需要避免额外的往返,请参阅 HangarRash 关于在哪里查找信息的评论,尽管您可能还需要检查色彩空间以确保您使用的是正确的转换。这变得很复杂,所以我只在您绝对需要时才推荐它。融入上下文将更容易保持一致。