[英]Why do I get the wrong color of a pixel with following code?
我用backgroundcolor RED創建一個UIImage:
let theimage:UIImage=imageWithColor(UIColor(red: 1, green: 0, blue: 0, alpha: 1) );
func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRectMake(0.0, 0.0, 200.0, 200.0)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
我正在檢索圖像中間的顏色,如下所示:
let h:CGFloat=theimage.size.height;
let w:CGFloat=theimage.size.width;
let test:UIColor=theimage.getPixelColor(CGPoint(x: 100, y: 100))
var rvalue:CGFloat = 0;
var gvalue:CGFloat = 0;
var bvalue:CGFloat = 0;
var alfaval:CGFloat = 0;
test.getRed(&rvalue, green: &gvalue, blue: &bvalue, alpha: &alfaval);
print("Blue Value : " + String(bvalue));
print("Red Value : " + String(rvalue));
extension UIImage {
func getPixelColor(pos: CGPoint) -> UIColor {
let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage))
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
let pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4
let r = CGFloat(data[pixelInfo]) / CGFloat(255.0)
let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
let b = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)
return UIColor(red: r, green: g, blue: b, alpha: a)
}
}
結果我得到:
藍色值:1.0紅色值:0.0
為什么這個 ? 我找不到錯誤。
問題不是內置的getRed
函數,而是從提供者數據中的各個顏色組件構建UIColor
對象的函數。 您的代碼假設提供者數據以RGBA格式存儲,但顯然不是。 它似乎是ARGB格式。 另外,我也不確定你的字節順序是否合適。
擁有圖像時,可以通過多種方式將這些圖像打包到提供者數據中。 Quartz 2D Programming Guide中顯示了一些示例:
如果您要使用針對特定格式硬編碼的getPixelColor
例程,我可能會檢查alphaInfo
和bitmapInfo
(在Swift 4.2中):
extension UIImage {
func getPixelColor(point: CGPoint) -> UIColor? {
guard let cgImage = cgImage,
let pixelData = cgImage.dataProvider?.data
else { return nil }
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
let alphaInfo = cgImage.alphaInfo
assert(alphaInfo == .premultipliedFirst || alphaInfo == .first || alphaInfo == .noneSkipFirst, "This routine expects alpha to be first component")
let byteOrderInfo = cgImage.byteOrderInfo
assert(byteOrderInfo == .order32Little || byteOrderInfo == .orderDefault, "This routine expects little-endian 32bit format")
let bytesPerRow = cgImage.bytesPerRow
let pixelInfo = Int(point.y) * bytesPerRow + Int(point.x) * 4;
let a: CGFloat = CGFloat(data[pixelInfo+3]) / 255
let r: CGFloat = CGFloat(data[pixelInfo+2]) / 255
let g: CGFloat = CGFloat(data[pixelInfo+1]) / 255
let b: CGFloat = CGFloat(data[pixelInfo ]) / 255
return UIColor(red: r, green: g, blue: b, alpha: a)
}
}
如果你總是以編程方式為依賴於位圖信息的代碼構建這個圖像,我在創建圖像時明確指定了這些細節:
func image(with color: UIColor, size: CGSize) -> UIImage? {
let rect = CGRect(origin: .zero, size: size)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil,
width: Int(rect.width),
height: Int(rect.height),
bitsPerComponent: 8,
bytesPerRow: Int(rect.width) * 4,
space: colorSpace,
bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) else {
return nil
}
context.setFillColor(color.cgColor)
context.fill(rect)
return context.makeImage().flatMap { UIImage(cgImage: $0) }
}
也許更好,如技術問答1509所示 ,您可能希望讓getPixelData
顯式創建自己的預定格式的上下文,將圖像繪制到該上下文,現在代碼不依賴於原始圖像的格式你正在申請這個。
extension UIImage {
func getPixelColor(point: CGPoint) -> UIColor? {
guard let cgImage = cgImage else { return nil }
let width = Int(size.width)
let height = Int(size.height)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: colorSpace,
bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
else {
return nil
}
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
guard let pixelBuffer = context.data else { return nil }
let pointer = pixelBuffer.bindMemory(to: UInt32.self, capacity: width * height)
let pixel = pointer[Int(point.y) * width + Int(point.x)]
let r: CGFloat = CGFloat(red(for: pixel)) / 255
let g: CGFloat = CGFloat(green(for: pixel)) / 255
let b: CGFloat = CGFloat(blue(for: pixel)) / 255
let a: CGFloat = CGFloat(alpha(for: pixel)) / 255
return UIColor(red: r, green: g, blue: b, alpha: a)
}
private func alpha(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 24) & 255)
}
private func red(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 16) & 255)
}
private func green(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 8) & 255)
}
private func blue(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 0) & 255)
}
private func rgba(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 {
return (UInt32(alpha) << 24) | (UInt32(red) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0)
}
}
顯然,如果你要檢查一堆像素,你會想要重構這一點(將標准像素緩沖區的創建與檢查顏色的代碼分離),但希望這說明了這個想法。
對於早期版本的Swift,請參閱此答案的先前版本 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.