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

lxkprmvk  于 2024-01-05  发布在  Swift
关注(0)|答案(1)|浏览(141)

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

  1. func analayze(imageAtURL url: URL) async throws -> [Color: Int] {
  2. guard let imgSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
  3. throw Error.cantLoadImage(url)
  4. }
  5. let cgImage: CGImage
  6. switch optimization {
  7. case .fullSize:
  8. guard let img = CGImageSourceCreateImageAtIndex(imgSource, 0, nil) else {
  9. throw Error.cantInstantiateImage(url)
  10. }
  11. cgImage = img
  12. case let .scale(maxSide):
  13. let options: [CFString: Any] = [
  14. kCGImageSourceCreateThumbnailFromImageAlways: true as CFBoolean,
  15. kCGImageSourceThumbnailMaxPixelSize: maxSide as CFNumber
  16. ]
  17. guard let img = CGImageSourceCreateThumbnailAtIndex(imgSource, 0, options as CFDictionary) else {
  18. throw Error.cantInstantiateImage(url)
  19. }
  20. cgImage = img
  21. default:
  22. throw Error.unsupportedOptimization(optimization)
  23. }
  24. let width = cgImage.width
  25. let height = cgImage.height
  26. let bytesPerRow = cgImage.bytesPerRow
  27. let bytesPerPixel = bytesPerRow / width
  28. let bitsPerComponent = cgImage.bitsPerComponent
  29. assert(bitsPerComponent == 8, "Expected 8 bits per component, got \(bitsPerComponent)")
  30. guard let pixelData = cgImage.dataProvider?.data else {
  31. throw Error.contextHasNoData
  32. }
  33. guard let unsafePointer = CFDataGetBytePtr(pixelData) else {
  34. throw Error.cantCreatePointer
  35. }
  36. let unsafeRawPointer = UnsafeRawPointer(unsafePointer)
  37. let points = pointsInRect(width: width, height: height)
  38. @Sendable
  39. func findClosestColorInTable(for point: DiscretePoint) -> Color? {
  40. let offset = (point.y * bytesPerRow) + (point.x * bytesPerPixel)
  41. let red = CGFloat(unsafeRawPointer.load(fromByteOffset: offset, as: UInt8.self)) / 255
  42. let green = CGFloat(unsafeRawPointer.load(fromByteOffset: offset + 1, as: UInt8.self)) / 255
  43. let blue = CGFloat(unsafeRawPointer.load(fromByteOffset: offset + 2, as: UInt8.self)) / 255
  44. let imgColor = Color(r: red, g: green, b: blue)
  45. // let nearestNeighbor = self.colorTree.nearest(to: imgColor)
  46. // return nearestNeighbor
  47. return imgColor
  48. }

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


的数据
对于缩放方法:


bvk5enib

bvk5enib1#

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

相关问题