检索无法与UIGraphicsImageRenderer图像一起正常工作的像素数据

时间:2019-03-03 15:06:11

标签: swift uigraphicsrenderer

我有以下代码从UIImage获取像素数据,该代码适用于大多数图像,但是当我使用UIGraphicsImageRenderer创建图像时不起作用。我希望有人知道解决方案。

我当前的代码生成一个简单的图像,但是访问数据会产生意外的结果。

func myDraw() {

    let renderer = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 200))
    let image = renderer.image { context in

        context.cgContext.setFillColor(UIColor.black.cgColor)
        context.cgContext.addRect(CGRect(x: 0, y: 0, width: 100, height: 100))
        context.cgContext.fillPath()

        context.cgContext.setFillColor(UIColor.red.cgColor)
        context.cgContext.addRect(CGRect(x: 100, y: 100, width: 100, height: 100))
        context.cgContext.fillPath()

    }

    let providerData = image.cgImage!.dataProvider!.data
    let data = CFDataGetBytePtr(providerData)!
    var pixels = [PixelData]()
    for i in stride(from: 0, to: 160000-1, by: 4) {
        pixels.append(PixelData(a:data[i+3], r:data[i+0], g:data[i+1], b:data[i+2]))
    }
    self.canvas.image = self.imageFromARGB32Bitmap(pixels: pixels, width: 200, height: 200)

}

我已使用以下代码生成图像以查看其是否正常工作。

func imageFromARGB32Bitmap(pixels: [PixelData], width: Int, height: Int) -> UIImage? {
    guard width > 0 && height > 0 else { return nil }
    guard pixels.count == width * height else { return nil }

    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
    let bitsPerComponent = 8
    let bitsPerPixel = 32

    var data = pixels // Copy to mutable []
    guard let providerRef = CGDataProvider(data: NSData(bytes: &data,
                                                        length: data.count * MemoryLayout<PixelData>.size)
        )
        else { return nil }

    guard let cgim = CGImage(
        width: width,
        height: height,
        bitsPerComponent: bitsPerComponent,
        bitsPerPixel: bitsPerPixel,
        bytesPerRow: width * MemoryLayout<PixelData>.size,
        space: rgbColorSpace,
        bitmapInfo: bitmapInfo,
        provider: providerRef,
        decode: nil,
        shouldInterpolate: true,
        intent: .defaultIntent
        )
        else { return nil }

    return UIImage(cgImage: cgim)
}

2 个答案:

答案 0 :(得分:2)

一些观察结果:

  1. 您的代码假定negative_zero生成缩放比例为1的图像,而默认值为0(即设备使用的缩放比例)。

    相反,将比例尺强制为1:

    UIGraphicsImageRenderer
  2. 这不是这里的问题,但我们必须注意,您的代码仅假设let format = UIGraphicsImageRendererFormat() format.scale = 1 let renderer = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 200), format: format) 的格式将是特定的字节顺序和格式,就像您的UIGraphicsImageRendererFormat一样。如果您查看Apple Technical Note 1509(无疑是从其原始代码改编而成的苹果),他们不只是假定缓冲区将采用特定格式。当我们要操作/检查缓冲区时,我们应该(a)创建所需格式的上下文,(b)在该上下文上绘制图像(或其他内容),然后我们才能可靠地查看提供者数据。 / p>

  3. imageFromARGB32Bitmap可以工作,但是这让我有点紧张。

    • 使用imageFromARGB32BitmapApple advises

        

      使用不安全的指针为T的多个实例分配内存时,请使用类型为MemoryLayout<PixelData>.size而不是其stride的倍数。

      因此,我将使用size

    • 如果stride不是您所期望的4,该怎么办?我无法想象它永远不会是4,但是根据数据提供者的假设,它们将被打包。这只是次要的观察,但是我可能会明确地假设这一点。

    • 我们是否100%保证取消引用stride会为我们提供连续的缓冲区?为了安全起见,我倾向于withContiguousStorageIfAvailable

    例如:

    &data

答案 1 :(得分:0)

使用render.pngData代替render.image,然后从UIImage.init(data: pngData)获取图像

当我想从UIGraphicsImageRenderer生成的图像中获取像素颜色时,遇到了相同的问题。

代码:

  let render = UIGraphicsImageRenderer(size: .init(width: 414, height: 100))
  // iPhone Xs, so scale is 3, the img actual size is 1242x300
  let img = render.image { ctx in
      ctx.cgContext.setFillColor(UIColor.red.cgColor)
      ctx.cgContext.addRect(.init(x: 0, y: 0, width: 10, height: 10))
      ctx.cgContext.drawPath(using: .fill)
  }

打印img像素颜色信息:

 let pixelData = img.cgImage!.dataProvider!.data
 let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
 let width = img.cgImage!.width
 let height = img.cgImage!.height

 for y in 0..<height {
     for x in 0..<width {
         let pixelInfo = (width * y + x) * 4

         print("xy: \(x) \(y) rgba: \(data[pixelInfo]) \(data[pixelInfo + 1]) \(data[pixelInfo + 2]) \(data[pixelInfo + 3])")
     }
 }

打印结果:

 xy: 0 0 rgba: 255 0 0 255
 xy: 1 0 rgba: 255 0 0 255
 xy: 2 0 rgba: 255 0 0 255
 xy: 3 0 rgba: 255 0 0 255
 xy: 4 0 rgba: 255 0 0 255
 ...
 xy: 1240 0 rgba: 0 0 0 0
 xy: 1241 0 rgba: 0 0 0 0
 xy: 0 1 rgba: 0 0 0 0
 ...
 xy: 5 1 rgba: 0 0 0 0
 xy: 6 1 rgba: 255 0 0 255
 xy: 7 1 rgba: 255 0 0 255
 xy: 8 1 rgba: 255 0 0 255
 ...
 xy: 1240 1 rgba: 0 0 0 0
 xy: 1241 1 rgba: 0 0 0 0
 xy: 0 2 rgba: 0 0 0 0
 xy: 1 2 rgba: 0 0 0 0
 ...     
 xy: 11 2 rgba: 0 0 0 0
 xy: 12 2 rgba: 255 0 0 255
 ...

我发现第二行有一些偏移,当我将img宽度414更改为400时,偏移消失了。

我不知道原因,如果有人知道,请在我的答案下方添加评论。

相关问题