当前位置: 首页 > 面试题库 >

在Swift中将像素数组转换为UIImage

越星晖
2023-03-14
问题内容

我一直在尝试找出如何在Swift中将rgb像素数据数组转换为UIImage。

我将每个像素的rgb数据保持在一个简单的结构中:

public struct PixelData {
   var a: Int
   var r: Int
   var g: Int
   var b: Int
}

我已经实现了以下功能,但是生成的图像不正确:

func imageFromARGB32Bitmap(pixels:[PixelData], width: Int, height: Int)-> UIImage {
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo:CGBitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.rawValue)
    let bitsPerComponent:Int = 8
    let bitsPerPixel:Int = 32

    assert(pixels.count == Int(width * height))

    var data = pixels // Copy to mutable []
    let providerRef = CGDataProviderCreateWithCFData(
        NSData(bytes: &data, length: data.count * sizeof(PixelData))
    )

    let cgim = CGImageCreate(
        width,
        height,
        bitsPerComponent,
        bitsPerPixel,
        width * Int(sizeof(PixelData)),
        rgbColorSpace,
        bitmapInfo,
        providerRef,
        nil,
        true,
        kCGRenderingIntentDefault
    )
    return UIImage(CGImage: cgim)!
}

关于如何正确地将rgb数组转换为UIImage的任何提示或指针?


问题答案:

注意:
这是iOS创建的解决方案UIImage。有关macOS和的解决方案NSImage,请参见此答案。

唯一的问题是结构中的数据类型PixelData需要为UInt8。我在Playground中使用以下内容创建了测试图像:

public struct PixelData {
    var a: UInt8
    var r: UInt8
    var g: UInt8
    var b: UInt8
}

var pixels = [PixelData]()

let red = PixelData(a: 255, r: 255, g: 0, b: 0)
let green = PixelData(a: 255, r: 0, g: 255, b: 0)
let blue = PixelData(a: 255, r: 0, g: 0, b: 255)

for _ in 1...300 {
    pixels.append(red)
}
for _ in 1...300 {
    pixels.append(green)
}
for _ in 1...300 {
    pixels.append(blue)
}

let image = imageFromARGB32Bitmap(pixels: pixels, width: 30, height: 30)

Swift 4更新:

我更新imageFromARGB32Bitmap为使用Swift4。该函数现在返回a,UIImage?并在出现任何问题时guard用于返回nil

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)
}

使它成为UIImage的便捷初始化器:

此函数可以用作的convenience初始化程序UIImage。这是实现:

extension UIImage {
    convenience init?(pixels: [PixelData], width: Int, height: Int) {
        guard width > 0 && height > 0, pixels.count == width * height else { return nil }
        var data = pixels
        guard let providerRef = CGDataProvider(data: Data(bytes: &data, count: data.count * MemoryLayout<PixelData>.size) as CFData)
            else { return nil }
        guard let cgim = CGImage(
            width: width,
            height: height,
            bitsPerComponent: 8,
            bitsPerPixel: 32,
            bytesPerRow: width * MemoryLayout<PixelData>.size,
            space: CGColorSpaceCreateDeviceRGB(),
            bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue),
            provider: providerRef,
            decode: nil,
            shouldInterpolate: true,
            intent: .defaultIntent)
        else { return nil }
        self.init(cgImage: cgim)
    }
}

这是一个用法示例:

// Generate a 500x500 image of randomly colored pixels

let height = 500
let width = 500

var pixels: [PixelData] = .init(repeating: .init(a: 0, r: 0, g: 0, b: 0), count: width * height)
for index in pixels.indices {
    pixels[index].a = 255
    pixels[index].r = .random(in: 0...255)
    pixels[index].g = .random(in: 0...255)
    pixels[index].b = .random(in: 0...255)
}
let image = UIImage(pixels: pixels, width: width, height: height)


 类似资料:
  • 问题内容: 这不再适用于Xcode 8 beta 6: 要么 错误是:上下文类型’CFArray’不能与数组文字一起使用 从数组转换为CFArray的最新方法是什么? 问题答案: 如果添加演员表,它将起作用: 或者您可以在通话中添加演员表: 在Swift 3(Xcode 8 beta 6)中,已删除对桥接类型的隐式转换。 在某些情况下,例如这种情况,您将需要添加显式强制转换以使其起作用。

  • 问题内容: 如何将一个4字节的数组转换为相应的Int? 例: 输入: 输出: 我在互联网上发现的某些代码不起作用: 问题答案: 有两个问题: 在64位平台上是64位整数,您的输入数据只有32位。 在所有当前的Swift平台上使用小尾数表示法,您输入的是大尾数。 话虽如此,以下方法会起作用: 或在Swift 3中使用: 使用一些缓冲区指针魔术,您可以避免中间复制到对象(Swift 2): 有关此方法

  • 问题内容: 我要实现的是: 我怎样才能返回对象,而是如果? 问题答案: 我找到了解决方案。在结果上创建了扩展名。 并使用像

  • 我想要实现的是: 如果,我如何将对象返回为?

  • 问题内容: 我正在尝试找出如何在Swift中将转换为。 我想出一种解决方法,但是我很想弄清楚如何在Swift中做到这一点。 问题答案: 转换为: 而另一种方式-转换为: 或者,如果您使用的是Swift 2或3:

  • 问题内容: 我正在尝试转换从UITextField中获取的数字(我认为这些数字实际上是字符串),并将其转换为Float,因此我可以将它们相乘。 我有两个声明如下: 当用户按下UIButton时,我想计算用户赚取的工资,但是我不能,因为我需要先将其转换为浮动工资,然后才能使用它们。 我知道如何通过执行以下操作将它们转换为整数: 但是,我不知道如何将它们转换为浮点数。 问题答案: 迅捷2.0+ 现在,