我试图通过抓取UIImage
,获取每个像素并从中减去CGImage
来使0xa
变暗,然后将每个像素保存到新缓冲区。但是当我尝试将该缓冲区作为图像加载时,函数[创建CGImage ]返回 nil 。这意味着我必须在我的代码中做错了(我不会感到惊讶)。我希望它与缓冲区格式不正确或其他东西有关。熟悉核心图形的人可以帮助我发现错误吗?
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
答案 0 :(得分:4)
有几点想法:
在编写自己的图像处理例程之前,您可以考虑应用Core Image filters之一。它可能会让您的生活更轻松,也可能为您带来更精致的结果。只需将每个通道减少一些固定数字就会引入您不期望的失真(例如色彩偏移,饱和度变化等)。
如果你打算这样做,我会对抓住数据提供者并按原样操作它保持警惕。您可能希望为图像提供者的性质(每通道位数,ARGB与RGBA等)引入各种条件逻辑。如果查看Apple's example in Q&A #1509,您可以检索预定格式的像素缓冲区(例如ARGB,每个组件8位,每像素4个字节。
此示例已过时,但它显示了如何创建预定格式的上下文,然后将图像绘制到该上下文中。然后,您可以使用您自己的提供程序而不是JPEG数据提供程序来操作该数据,并使用此预定格式创建新图像。
代码示例中最重要的问题是您正在尝试使用CGImageCreateWithJPEGDataProvider
,它需要“数据提供程序提供JPEG编码数据”。但是你的提供者可能不是JPEG编码的,所以它会失败。如果您要使用原始图像提供程序格式的数据,则必须使用CGImageCreate
创建新图像(手动提供width,height,bitsPerComponent,bitsPerPixel,bytesPerRow,colorSpace,bitmapInfo,等)。
您的日常工作存在一些不太严重的问题:
您注意到您看到每个第四个字节都是0xff
。在您的代码注释中回答您的问题时,这无疑是alpha通道。 (您可以通过检查原始CGBitmapInfo
的{{1}}来确认这一点。)您可能没有使用Alpha通道,但它显然在那里。
如果频道的值小于CGImageRef
,您的例程会将其设置为0x0a
。这显然不是你的意图(例如,如果像素是黑色的,你会把它变成白色!)。你应该检查一下这个逻辑。
在我的测试中,这种迭代/操作0xff
数组的方法非常慢。我不完全确定为什么会这样,但是如果直接操作字节缓冲区,它会快得多。
所以,下面,请找到创建预定格式(RGBA,每个组件8位等)的上下文的例程,操作它(我转换为B& W虽然你可以做你想做的任何事情),并创建新的那个图像。所以,在Swift 2中:
Byte
其中
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)
}
或者,在Swift 3中:
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
}