位图(Bitmap),又称栅格图(英语:Raster graphics)或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。
根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。例如,位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图。位深度为 8 的图像有 2^8(即 256)个可能的值。位深度为 8 的灰度模式图像有 256 个可能的灰色值。
RGB图像由三个颜色通道组成。8 位/通道的 RGB 图像中的每个通道有 256 个可能的值,这意味着该图像有 1600 万个以上可能的颜色值。有时将带有 8 位/通道 (bpc) 的 RGB 图像称作 24 位图像(8 位 x 3 通道 = 24 位数据/像素)。通常将使用24位RGB组合数据位表示的的位图称为真彩色位图。
在iOS中,Bitmap的数据由CGContext封装,看下CGContext的初始化方法如下:
init?(data: UnsafeMutableRawPointer?, width: Int, height: Int, bitsPerComponent:Int, bytesPerRow: Int, space: CGColorSpace, bitmapInfo: UInt32)
data: UnsafeMutableRawPointer,用于存放位图的点阵数据
width: Int 位图的宽
height: Int 位图的高
如width=10,height=10,则代表每一行有10个像素,每一列有20个像素
bitsPerComponent:Int 颜色组件或者alpha组件占的bite数,以32位图为列:bitsPerComponent = 8
bytesPerRow: Int 位图每行占的字节数(byte)以32位图为例:一个像素有4byte(rgba)
那么一行字节数: bytesPerRow = 4*width
space: CGColorSpac 颜色空间 CGColorSpaceCreateDeviceRGB
bitmapInfo: UInt32 一个常量,描述这个位图上下文所对应的位图的基本信息,例如:CGImageAlphaInfo.premultipliedLast
接下来我们以两种方式把图片从rgb888转成rgb56
第一种以UInt32来接收位图信息,即一个数据包含了RGBA所有数据
func rbg565Data() -> Data? {
guard let cgImage = self.cgImage
else { return Data() }
let width = Int(size.width)
let height = Int(size.height)
// bytes array
let srcRowBytes = 4 * width
var bytes = Array<UInt32>.init(repeating: 0, count: srcRowBytes * height)
// create context for image
guard let context = CGContext(data: &bytes, width: width, height: height, bitsPerComponent: 8, bytesPerRow: srcRowBytes, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue )
else { return nil }
// fill buffer
context.interpolationQuality = .high
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
var newBytes = [UInt8]()
for col in 0..<height {
for row in 0..<width {
// let pixeIndex = (col*width+row)*4
let color = bytes[(col*width+row)]
let r = UInt8(( color >> 0 ) & 0xff )
let g = UInt8(( color >> 8 ) & 0xff )
let b = UInt8(( color >> 16) & 0xff )
let data = (r & 0xf8) | ((g >> 5) & 0x7)
newBytes.append(data)
let data2 = ((g<<3) & 0xE0) | ((b >> 3) & 0x1F)
newBytes.append(data2)
}
}
return Data(bytes: newBytes, count: newBytes.count)
}
第二种已UInt8来存储位图信息,即一个数据只包含RGBA中一个通道信息,比如R
func rbg565Data() -> Data? {
guard let cgImage = self.cgImage
else { return Data() }
let width = Int(size.width)
let height = Int(size.height)
// bytes array
let srcRowBytes = 4 * width
var bytes = Array<UInt8>.init(repeating: 0, count: srcRowBytes * height)
// create context for image
guard let context = CGContext(data: &bytes, width: width, height: height, bitsPerComponent: 8, bytesPerRow: srcRowBytes, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue )
else { return nil }
// fill buffer
context.interpolationQuality = .high
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
var newBytes = [UInt8]()
for i in 0..<(bytes.count/4) {
let pixeIndex = i*4
let r = UInt8(bytes[pixeIndex])
let g = UInt8(bytes[pixeIndex+1])
let b = UInt8(bytes[pixeIndex+2])
let data:UInt8 = (r & 0xf8) | ((g >> 5) & 0x7)
newBytes.append(data)
let data2:UInt8 = ((g<<3) & 0xE0) | ((b >> 3) & 0x1F)
newBytes.append(data2)
// logD("---r=\(r),g=\(g),b=\(b),data=\(data),data1=\(data2)")
}
return Data(bytes: newBytes, count: newBytes.count)
}