为什么我会得到一个像素的错误颜色与下面的代码? [英] Why do I get the wrong color of a pixel with following code?

查看:244
本文介绍了为什么我会得到一个像素的错误颜色与下面的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用backgroundcolor RED 创建一个UIImage:

  let theimage:UIImage = imageWithColor (红色:1,绿色:0,蓝色:0,α:1)); 

func imageWithColor(color:UIColor) - > UIImage {
let rect = CGRectMake(0.0,0.0,200.0,200.0)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()

CGContextSetFillColorWithColor ,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:&al; alfaval);


print(Blue Value:+ String(bvalue));
print(Red Value:+ String(rvalue));


扩展UIImage {
func getPixelColor(pos:CGPoint) - > UIColor {

let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage))
let data:UnsafePointer< UInt8> = CFDataGetBytePtr(pixelData)

让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 [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格式。此外,我不确定你是否有字节顺序。



当你有一个图像,有多种方式将这些包装到提供程序数据。以下示例显示在



如果你要有一个 getPixelColor 例程,这是一个硬编码的特定格式,我可以检查 CGImageGetAlphaInfo CGImageGetBitmapInfo 如此:

 code> extension UIImage {
func getPixelColor(point:CGPoint) - > UIColor {
let cgImage = self.CGImage

let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage))
let data:UnsafePointer< UInt8> = CFDataGetBytePtr(pixelData)

让alphaInfo = CGImageGetAlphaInfo(cgImage)
assert(alphaInfo == .PremultipliedFirst || alphaInfo == .First || alphaInfo == .NoneSkipFirst, alpha是第一个组件)

let byteOrder = CGImageGetBitmapInfo(cgImage).rawValue& CbitmapInfo.ByteOrderMask.rawValue
assert(byteOrder == CGBitmapInfo.ByteOrder32Little.rawValue,此例程需要小端字节32位格式)

让bytesPerRow = CGImageGetBytesPerRow(cgImage)
let pixelInfo = Int(point.y)* bytesPerRow + Int(point.x)* 4;

let a = CGFloat(data [pixelInfo + 3])/ CGFloat(255.0)
let r = CGFloat(data [pixelInfo + 2])/ CGFloat(255.0)
let g = CGFloat(data [pixelInfo + 1])/ CGFloat(255.0)
let b = CGFloat(data [pixelInfo])/ CGFloat(255.0)

return UIColor ,green:g,blue:b,alpha:a)
}
}

如果你始终以编程方式为依赖于位图信息的代码构建此图像,我将在创建图像时明确指定这些详细信息:

  func imageWithColor(color:UIColor) - > UIImage {
let rect = CGRectMake(0.0,0.0,200.0,200.0)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGBitmapContextCreate(nil, .height),8,Int(rect.width)* 4,colorSpace,CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)

CGContextSetFillColorWithColor(context,color.CGColor)
CGContextFillRect (context,rect)

let cgImage = CGBitmapContextCreateImage(context)!
let image = UIImage(CGImage:cgImage)

return image
}

也许更好,如技术问答; A 1509 ,您可能希望 getPixelData 显式创建其自己的预定格式的上下文,将图像绘制到该上下文中,现在代码不是取决于您应用此图片的原始图片的格式。

 扩展UIImage {

func getPixelColor(point:CGPoint) - > UIColor {
let cgImage = self.CGImage
let width = Int(size.width)
let height = Int(size.height)
let colorSpace = CGColorSpaceCreateDeviceRGB
$ b let context = CGBitmapContextCreate(nil,width,height,8,width * 4,colorSpace,CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)!
CGContextDrawImage(context,CGRectMake(0,0,size.width,size.height),cgImage)

let pixelBuffer = UnsafeMutablePointer< UInt32>(CGBitmapContextGetData(context))

let pixel = pixelBuffer + Int(point.y)* width + Int(point.x)

let r = CGFloat(red(pixel.memory))/ CGFloat(255.0)
let g = CGFloat(green(pixel.memory))/ CGFloat(255.0)
let b = CGFloat(blue(pixel.memory))/ CGFloat(255.0)
let a = CGFloat alpha(pixel.memory))/ CGFloat(255.0)

return UIColor(red:r,green:g,blue:b,alpha:a)
}

private func alpha(color:UInt32) - > UInt8 {
return UInt8((color>> 24)& 255)
}

私有函数红色(颜色:UInt32) UInt8 {
return UInt8((color>> 16)& 255)
}

private func green(color:UInt32) UInt8 {
return UInt8((color>> 8)& 255)
}

private func blue(color:UInt32) UInt8 {
return UInt8((color>> 0)& 255)
}

private func rgba(red red:UInt8,green:UInt8,blue:UInt8 ,alpha:UInt8) - > UInt32 {
return(UInt32(alpha)<< 24)| (UInt32(红色)<< 16)| (UInt32(绿色)<< 8)| (UInt32(blue)<<<< 0)
}

}


$ b b

显然,如果你要检查一堆像素,你会想重构这个(解耦标准化的像素缓冲区从检查颜色的代码的创建),但希望这说明了这个想法。


I create an UIImage with backgroundcolor RED:

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
}

I am retrieving the color in the middle of the image as follow:

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)
    }
}

As result I get :

Blue Value : 1.0 Red Value : 0.0

Why this ? I couldn't find the mistake.

解决方案

The problem is not the built-in getRed function, but rather the function that builds the UIColor object from the individual color components in the provider data. Your code is assuming that the provider data is stored in RGBA format, but it apparently is not. It would appear to be in ARGB format. Also, I'm not sure you have the byte order right, either.

When you have an image, there are a variety of ways of packing those into the provider data. A few examples are shown in the Quartz 2D Programming Guide:

If you're going to have a getPixelColor routine that is hard-coded for a particular format, I might check the CGImageGetAlphaInfo and CGImageGetBitmapInfo like so:

extension UIImage {
    func getPixelColor(point: CGPoint) -> UIColor {
        let cgImage = self.CGImage

        let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage))
        let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)

        let alphaInfo = CGImageGetAlphaInfo(cgImage)
        assert(alphaInfo == .PremultipliedFirst || alphaInfo == .First || alphaInfo == .NoneSkipFirst, "This routine expects alpha to be first component")

        let byteOrder = CGImageGetBitmapInfo(cgImage).rawValue & CGBitmapInfo.ByteOrderMask.rawValue
        assert(byteOrder == CGBitmapInfo.ByteOrder32Little.rawValue, "This routine expects little-endian 32bit format")

        let bytesPerRow = CGImageGetBytesPerRow(cgImage)
        let pixelInfo = Int(point.y) * bytesPerRow + Int(point.x) * 4;

        let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)
        let r = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
        let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
        let b = CGFloat(data[pixelInfo  ]) / CGFloat(255.0)

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}

And if you were to always build this image programmatically for code that is dependent upon the bit map info, I'd explicitly specify these details when I created the image:

func imageWithColor(color: UIColor) -> UIImage {
    let rect = CGRectMake(0.0, 0.0, 200.0, 200.0)
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let context = CGBitmapContextCreate(nil, Int(rect.width), Int(rect.height), 8, Int(rect.width) * 4, colorSpace, CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)

    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextFillRect(context, rect)

    let cgImage = CGBitmapContextCreateImage(context)!
    let image = UIImage(CGImage: cgImage)

    return image
}

Perhaps even better, as shown in Technical Q&A 1509, you might want to have getPixelData explicitly create its own context of a predetermined format, draw the image to that context, and now the code is not contingent upon the format of the original image to which you are applying this.

extension UIImage {

    func getPixelColor(point: CGPoint) -> UIColor {
        let cgImage = self.CGImage
        let width = Int(size.width)
        let height = Int(size.height)
        let colorSpace = CGColorSpaceCreateDeviceRGB()

        let context = CGBitmapContextCreate(nil, width, height, 8, width * 4, colorSpace, CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)!
        CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), cgImage)

        let pixelBuffer = UnsafeMutablePointer<UInt32>(CGBitmapContextGetData(context))

        let pixel = pixelBuffer + Int(point.y) * width + Int(point.x)

        let r = CGFloat(red(pixel.memory))   / CGFloat(255.0)
        let g = CGFloat(green(pixel.memory)) / CGFloat(255.0)
        let b = CGFloat(blue(pixel.memory))  / CGFloat(255.0)
        let a = CGFloat(alpha(pixel.memory)) / CGFloat(255.0)

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }

    private func alpha(color: UInt32) -> UInt8 {
        return UInt8((color >> 24) & 255)
    }

    private func red(color: UInt32) -> UInt8 {
        return UInt8((color >> 16) & 255)
    }

    private func green(color: UInt32) -> UInt8 {
        return UInt8((color >> 8) & 255)
    }

    private func blue(color: UInt32) -> UInt8 {
        return UInt8((color >> 0) & 255)
    }

    private func rgba(red red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 {
        return (UInt32(alpha) << 24) | (UInt32(red) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0)
    }

}

Clearly, if you're going to check a bunch of pixels, you'll want to refactor this (decouple the creation of the standardized pixel buffer from the code that checks the color), but hopefully this illustrates the idea.

这篇关于为什么我会得到一个像素的错误颜色与下面的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆