我试图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
一些想法:
在编写自己的图像处理例程之前,您可以考虑应用“核心图像”过滤器之一。它可以使您的生活更加轻松,并且可以为您提供更精致的结果。仅将每个通道减少一些固定数量就会引入您不希望的失真(例如,色彩偏移,饱和度变化等)。
如果您要执行此操作,那么我会担心仅获取数据提供者并按原样对其进行操作。您可能想针对图像提供者的性质引入各种条件逻辑(每通道位数,ARGB与RGBA等)。如果查看Q&A#1509中的Apple示例,则可以检索预定格式的像素缓冲区(在其示例ARGB中,每个分量8位,每个像素4个字节。
此示例已过时,但它显示了如何创建预定格式的上下文,然后在该上下文中绘制图像。然后,您可以处理该数据,并使用您自己的提供程序(而不是JPEG数据提供程序)使用此预定格式创建新图像。
代码示例中最重要的问题是您尝试使用CGImageCreateWithJPEGDataProvider
,它期望“提供JPEG编码数据的数据提供者”。但是您的提供程序可能未经过JPEG编码,因此将失败。如果要使用原始图像提供者格式的数据,则必须使用创建新图像CGImageCreate
(手动提供宽度,高度,bitsPerComponent,bitsPerPixel,bytesPerRow,colorSpace,bitmapInfo等)。
您的例程中有一些不太严重的问题:
您会注意到,您看到的每个第四个字节都是一个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] 删除。
我来说两句