从缓冲区创建的NSData创建UIImage返回nil?

流行内核

我试图UIImage通过抓住CGImage,获取每个像素并0xa从中减去,然后将每个像素保存到新的缓冲区中来变暗但是,当我尝试将该缓冲区作为图像加载回去时,[创建CGImage ]函数将返回nil这意味着我在代码中一定做错了(我不会感到惊讶)。我希望它与缓冲区格式不正确有关。熟悉Core Graphics的人可以帮助我发现错误吗?

var provider = CGImageGetDataProvider(imageArray[imageNumber]?.CGImage) //Get data provider for image in an array at index No. imageNumber
    let data = CGDataProviderCopyData(provider)
    var buffer = [Byte](count: CFDataGetLength(data), repeatedValue: 0) //create buffer for image data
    CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), &buffer) //load the image's bytes into buffer
    var newBuffer = [Byte](count:buffer.count, repeatedValue: 0) //Going to make some changes, need a place to save new image
    var index = 0
    for aByte in buffer {
        if aByte > 0xa && aByte != 0xff {
       newBuffer[index] = (aByte - 0xa) //subtract 0xa from buffer, where possible
        }
        else{
            newBuffer[index] = (0xff) //I *think* there is no alpha channel, but every fourth byte in buffer is 0xff
        }
        index += 1
    }
    var coreGraphicsImage = CGImageCreateWithJPEGDataProvider(CGDataProviderCreateWithCFData( CFDataCreate(kCFAllocatorDefault, newBuffer, newBuffer.count)), nil, true, kCGRenderingIntentDefault) //create CGimage from newBuffer.RETURNS NIL!
    let myImage = UIImage(CGImage: coreGraphicsImage) //also nil
    imageView.image = myImage

一些想法:

  1. 在编写自己的图像处理例程之前,您可以考虑应用“核心图像”过滤器之一它可以使您的生活更加轻松,并且可以为您提供更精致的结果。仅将每个通道减少一些固定数量就会引入您不希望的失真(例如,色彩偏移,饱和度变化等)。

  2. 如果您要执行此操作,那么我会担心仅获取数据提供者并按原样对其进行操作。您可能想针对图像提供者的性质引入各种条件逻辑(每通道位数,ARGB与RGBA等)。如果查看Q&A#1509中的Apple示例,则可以检索预定格式的像素缓冲区(在其示例ARGB中,每个分量8位,每个像素4个字节。

    此示例已过时,但它显示了如何创建预定格式的上下文,然后在该上下文中绘制图像。然后,您可以处理该数据,并使用您自己的提供程序(而不是JPEG数据提供程序)使用此预定格式创建新图像。

  3. 代码示例中最重要的问题是您尝试使用CGImageCreateWithJPEGDataProvider,它期望“提供JPEG编码数据的数据提供者”。但是您的提供程序可能未经过JPEG编码,因此将失败。如果要使用原始图像提供者格式的数据,则必须使用创建新图像CGImageCreate(手动提供宽度,高度,bitsPerComponent,bitsPerPixel,bytesPerRow,colorSpace,bitmapInfo等)。

  4. 您的例程中有一些不太严重的问题:

    • 您会注意到,您看到的每个第四个字节都是一个0xff在您的代码注释中回答您的问题时,无疑是alpha通道。(您可以通过检查CGBitmapInfo原始图像的来确认CGImageRef。)您可能没有使用Alpha通道,但是它很明显在那儿。

    • 您的例程(如果通道的值小于0x0a)将其设置为0xff这显然不是您的意图(例如,如果像素为黑色,则将其设为白色!)。您应该检查该逻辑。

    • 在我的测试中,这种迭代/操作Byte数组的方法非常慢。我不确定为什么会这样,但是如果您直接操作字节缓冲区,则速度会更快。

因此,在下面,请找到创建预定格式的上下文(RGBA,每个组件8位等),对其进行操作(尽管您可以做任何想做的事,我正在转换为B&W)并从中创建新图像的例程。因此,在Swift 2中:

func blackAndWhiteImage(image: UIImage) -> UIImage? {
    // get information about image

    let imageref = image.CGImage
    let width = CGImageGetWidth(imageref)
    let height = CGImageGetHeight(imageref)

    // create new bitmap context

    let bitsPerComponent = 8
    let bytesPerPixel = 4
    let bytesPerRow = width * bytesPerPixel
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = Pixel.bitmapInfo
    let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)

    // draw image to context

    let rect = CGRectMake(0, 0, CGFloat(width), CGFloat(height))
    CGContextDrawImage(context, rect, imageref)

    // manipulate binary data

    let pixels = UnsafeMutablePointer<Pixel>(CGBitmapContextGetData(context))

    for row in 0 ..< height {
        for col in 0 ..< width {
            let offset = Int(row * width + col)

            let red = Float(pixels[offset].red)
            let green = Float(pixels[offset].green)
            let blue = Float(pixels[offset].blue)
            let alpha = pixels[offset].alpha
            let luminance = UInt8(0.2126 * red + 0.7152 * green + 0.0722 * blue)
            pixels[offset] = Pixel(red: luminance, green: luminance, blue: luminance, alpha: alpha)
        }
    }

    // return the image

    let outputImage = CGBitmapContextCreateImage(context)!
    return UIImage(CGImage: outputImage, scale: image.scale, orientation: image.imageOrientation)
}

在哪里

struct Pixel: Equatable {
    private var rgba: UInt32

    var red: UInt8 {
        return UInt8((rgba >> 24) & 255)
    }

    var green: UInt8 {
        return UInt8((rgba >> 16) & 255)
    }

    var blue: UInt8 {
        return UInt8((rgba >> 8) & 255)
    }

    var alpha: UInt8 {
        return UInt8((rgba >> 0) & 255)
    }

    init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
        rgba = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
    }

    static let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
}

func ==(lhs: Pixel, rhs: Pixel) -> Bool {
    return lhs.rgba == rhs.rgba
}

或者,在Swift 3中:

func blackAndWhite(image: UIImage) -> UIImage? {
    // get information about image

    let imageref = image.cgImage!
    let width = imageref.width
    let height = imageref.height

    // create new bitmap context

    let bitsPerComponent = 8
    let bytesPerPixel = 4
    let bytesPerRow = width * bytesPerPixel
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = Pixel.bitmapInfo
    let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)!

    // draw image to context

    let rect = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))
    context.draw(imageref, in: rect)

    // manipulate binary data

    guard let buffer = context.data else {
        print("unable to get context data")
        return nil
    }

    let pixels = buffer.bindMemory(to: Pixel.self, capacity: width * height)

    for row in 0 ..< height {
        for col in 0 ..< width {
            let offset = Int(row * width + col)

            let red = Float(pixels[offset].red)
            let green = Float(pixels[offset].green)
            let blue = Float(pixels[offset].blue)
            let alpha = pixels[offset].alpha
            let luminance = UInt8(0.2126 * red + 0.7152 * green + 0.0722 * blue)
            pixels[offset] = Pixel(red: luminance, green: luminance, blue: luminance, alpha: alpha)
        }
    }

    // return the image

    let outputImage = context.makeImage()!
    return UIImage(cgImage: outputImage, scale: image.scale, orientation: image.imageOrientation)
}

struct Pixel: Equatable {
    private var rgba: UInt32

    var red: UInt8 {
        return UInt8((rgba >> 24) & 255)
    }

    var green: UInt8 {
        return UInt8((rgba >> 16) & 255)
    }

    var blue: UInt8 {
        return UInt8((rgba >> 8) & 255)
    }

    var alpha: UInt8 {
        return UInt8((rgba >> 0) & 255)
    }

    init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
        rgba = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
    }

    static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue

    static func ==(lhs: Pixel, rhs: Pixel) -> Bool {
        return lhs.rgba == rhs.rgba
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

从缓冲区创建QImage,没有深层副本?

来自分类Dev

是否可以从缓冲区(pByte)和大小创建VarArray OleVariant,而不进行复制?

来自分类Dev

从HTML创建PDF并将其从缓冲区发送给用户

来自分类Dev

如何从缓冲区返回文件流?

来自分类Dev

字节缓冲区NSData

来自分类Dev

在Numpy数组中创建缓冲区

来自分类Dev

动态顶点缓冲区创建失败

来自分类Dev

在openCL中创建子缓冲区

来自分类Dev

如何释放libjpeg创建的缓冲区?

来自分类Dev

在openCL中创建子缓冲区

来自分类Dev

ReadAsync从缓冲区获取数据

来自分类Dev

Python从缓冲区读取数据

来自分类Dev

从缓冲区读取Python 2.6

来自分类Dev

返回从缓冲区和函数读取的字符串而没有动态分配?

来自分类Dev

在Emacs 24.3下使用缓冲区名称中的空格创建新缓冲区

来自分类Dev

从Swift中的缓冲区获取NSData

来自分类Dev

如何创建缓冲区溢出以测试Address Sanitizer?

来自分类Dev

如何从音频标签创建音频缓冲区?

来自分类Dev

如何创建线程安全缓冲区/ POD?

来自分类Dev

使用缓冲区创建实例后需要MemoryStream吗?

来自分类Dev

用熊猫创建缓冲区时发生内存泄漏?

来自分类Dev

在OpenGL中创建不可变缓冲区

来自分类Dev

如何从char []创建指向缓冲区的指针

来自分类Dev

查找缓冲区地址以创建外壳代码

来自分类Dev

使用CFFI在Python中创建CData类型的缓冲区

来自分类Dev

ArcGIS使用Android中的GeometryServer创建缓冲区

来自分类Dev

WebGL。是否在GPU中创建缓冲区?

来自分类Dev

在Swift中从vDSP DSPSplitComplex创建Metal缓冲区

来自分类Dev

zeromq在节点之间创建消息缓冲区