26

我知道这是一个常见的问题,并且这个问题有很多答案。我已经使用了其中的一些。虽然很多都是一样的。但对我来说可悲的是,他们都没有为我工作。以下代码我一直使用到现在。

-(void)getRGBAsFromImage:(UIImage*)image atX:(int)xx andY:(int)yy
{
    // First get the image into your data buffer
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.
    int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;

    CGFloat red   = (rawData[byteIndex]     * 1.0) / 255.0;
    CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0;
    CGFloat blue  = (rawData[byteIndex + 2] * 1.0) / 255.0;
    CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
    byteIndex += 4;
    NSLog(@"the vale of the rbg of red is %f",red);

    demoColor.tintColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
    free(rawData);
}

这是我使用的另一种方法 -

- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef) inImage {

    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    // Get image width, height. We'll use the entire image.
    size_t pixelsWide = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);

    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.
    //colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    colorSpace = CGColorSpaceCreateDeviceRGB();
    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
    // per component. Regardless of what the source image format is
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning
    CGColorSpaceRelease( colorSpace );

    return context;
}


- (UIColor*) getPixelColorAtLocation:(CGPoint)point {
    UIColor* color = nil;
    //CGImageRef inImage = self.image.CGImage;
    CGImageRef inImage = [AppDelegate getInstance].capturedImage.CGImage;
    // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue
    CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage];
    if (cgctx == NULL) { return nil; /* error */ }

    size_t w = CGImageGetWidth(inImage);
    size_t h = CGImageGetHeight(inImage);
    CGRect rect = {{0,0},{w,h}}; 

    // Draw the image to the bitmap context. Once we draw, the memory
    // allocated for the context for rendering will then contain the
    // raw image data in the specified color space.
    CGContextDrawImage(cgctx, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap
    // context.
    unsigned char* data = CGBitmapContextGetData (cgctx);
    if (data != NULL) {
        //offset locates the pixel in the data from x,y.
        //4 for 4 bytes of data per pixel, w is width of one row of data.
        int offset = 4*((w*round(point.y))+round(point.x));
        int alpha =  data[offset];
        int red = data[offset+1];
        int green = data[offset+2];
        int blue = data[offset+3];
        NSLog(@"offset: %i colors: RGB A %i %i %i  %i",offset,red,green,blue,alpha);
        color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
    }

    // When finished, release the context
    CGContextRelease(cgctx);
    // Free image data memory for the context
    if (data) { free(data); }

    return color;
}

但这些都没有为我工作。请帮我解决这个问题。有什么我想念的吗?

我的 UI 中有 2 个 UIImageView。后面的那个包含我需要从中选择触摸像素颜色的图像。另一个 UIImageView 是用选择的颜色在背面图像上绘制。

请帮忙。任何帮助将不胜感激。

4

6 回答 6

52

这是我用过的,它看起来比你尝试过的方法更简单。

在我的自定义视图类中,我有这个:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint loc = [touch locationInView:self];
    self.pickedColor = [self colorOfPoint:loc];
}

colorOfPoint 是 UIView 上一个类别中的一个方法,代码如下:

#import "UIView+ColorOfPoint.h"
#import <QuartzCore/QuartzCore.h>

@implementation UIView (ColorOfPoint)

-(UIColor *) colorOfPoint:(CGPoint)point
    {
    unsigned char pixel[4] = {0};
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixel,
            1, 1, 8, 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(context, -point.x, -point.y);

    [self.layer renderInContext:context];

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    UIColor *color = [UIColor colorWithRed:pixel[0]/255.0
        green:pixel[1]/255.0 blue:pixel[2]/255.0
        alpha:pixel[3]/255.0];
    return color;
    }

不要忘记将类别导入自定义视图类并添加 QuartzCore 框架。


2013 年的琐碎说明:将最后一个参数转换为 (CGBitmapInfo) 以避免隐式转换警告:这里的示例。希望能帮助到你。

于 2012-10-07T16:36:43.480 回答
16

Swift 4、Xcode 9 - 带有 UIImageView 扩展

这是上述所有答案的组合,但在扩展中

extension UIImageView {
    func getPixelColorAt(point:CGPoint) -> UIColor{
        
        let pixel = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: 4)
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let context = CGContext(data: pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
        
        context!.translateBy(x: -point.x, y: -point.y)
        layer.render(in: context!)
        let color:UIColor = UIColor(red: CGFloat(pixel[0])/255.0,
                                    green: CGFloat(pixel[1])/255.0,
                                    blue: CGFloat(pixel[2])/255.0,
                                    alpha: CGFloat(pixel[3])/255.0)
        
        pixel.deallocate(capacity: 4)
        return color
    }
}

如何使用

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    if let point = touch?.location(in: view) {
        let color = myUIImageView.getPixelColorAt(point: point)
        print(color)
    }
}
于 2017-05-04T02:03:43.447 回答
13

感谢@Aggressor 发布上面的代码

斯威夫特 2.1

func getPixelColorAtPoint(point:CGPoint) -> UIColor{

   let pixel = UnsafeMutablePointer<CUnsignedChar>.alloc(4)
   let colorSpace = CGColorSpaceCreateDeviceRGB()
   let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
   let context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, bitmapInfo.rawValue)

   CGContextTranslateCTM(context, -point.x, -point.y)
   view.layer.renderInContext(context!)
   let color:UIColor = UIColor(red: CGFloat(pixel[0])/255.0, green: CGFloat(pixel[1])/255.0, blue: CGFloat(pixel[2])/255.0, alpha: CGFloat(pixel[3])/255.0)

   pixel.dealloc(4)
   return color
}

Swift 3,Xcode 版本 8.2 (8C38) 和 Swift 4,Xcode 版本 9.1 (9B55)

 func getPixelColorAtPoint(point:CGPoint, sourceView: UIView) -> UIColor{

    let pixel = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: 4)
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
    let context = CGContext(data: pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
    var color: UIColor? = nil

    if let context = context {
        context.translateBy(x: -point.x, y: -point.y)
        sourceView.layer.render(in: context)

        color = UIColor(red: CGFloat(pixel[0])/255.0,
                        green: CGFloat(pixel[1])/255.0,
                        blue: CGFloat(pixel[2])/255.0,
                        alpha: CGFloat(pixel[3])/255.0)

        pixel.deallocate(capacity: 4)
    }
    return color
}
于 2015-12-25T08:16:05.703 回答
9

很好的答案 rdelmar 这对我帮助很大!

以下是我在 Swift 中执行上述操作的方式:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
    {
        var touch:UITouch = event.allTouches()!.anyObject() as UITouch
        var loc = touch.locationInView(self)
        var color:UIColor = getPixelColorAtPoint(loc)
        println(color)
    }

    //returns the color data of the pixel at the currently selected point
    func getPixelColorAtPoint(point:CGPoint)->UIColor
    {
        let pixel = UnsafeMutablePointer<CUnsignedChar>.alloc(4)
        var colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
        let context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, bitmapInfo)

        CGContextTranslateCTM(context, -point.x, -point.y)
        layer.renderInContext(context)
        var color:UIColor = UIColor(red: CGFloat(pixel[0])/255.0, green: CGFloat(pixel[1])/255.0, blue: CGFloat(pixel[2])/255.0, alpha: CGFloat(pixel[3])/255.0)

        pixel.dealloc(4)
        return color
    }
于 2015-01-02T18:34:49.167 回答
2

首先,我要感谢这段代码的作者,它对我的​​游戏项目帮助很大,因为我一直在寻找这个函数来做一个像素完美的命中框(不包括 aplha 是 O 的地方)。这是 Swift 5 的一个小更新:

// Fonction permettant de retourner les valeurs RGBA d'un pixel d'une vue
func getPixelColor(atPosition:CGPoint) -> UIColor{

    var pixel:[CUnsignedChar] = [0, 0, 0, 0];
    let colorSpace = CGColorSpaceCreateDeviceRGB();
    let bitmapInfo = CGBitmapInfo(rawValue:    CGImageAlphaInfo.premultipliedLast.rawValue);
    let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue);

    context!.translateBy(x: -atPosition.x, y: -atPosition.y);
    layer.render(in: context!);
    let color:UIColor = UIColor(red: CGFloat(pixel[0])/255.0,
                                green: CGFloat(pixel[1])/255.0,
                                blue: CGFloat(pixel[2])/255.0,
                                alpha: CGFloat(pixel[3])/255.0);

    return color;

}

我对 pixel.dealloc(4) 有一些问题,就像在 Swift 5 中一样,您似乎不能再使用容量参数来解除分配。我删除了 (4),但它有一些奇怪的行为(因为 dealloc() 没有释放整个数组)。

我没有做 UIView 的扩展,因为在我的项目中我有自己的子类,但这很容易做到。

我实现代码的方式:

// Méthode déterminant si le "touch" est validé par l'objet (par défaut, exclut les zones transparentes et les objets invisibles). A surcharger si nécessaire.
func isHit(atPosition position:CGPoint) -> Bool
{

    // Si l'objet n'est pas caché (paramètre isHidden) et si la zone touchée correspond à une zone effectivement dessinée (non transparente), retourne true.
    if (!self.isHidden && self.getPixelColor(atPosition: position).cgColor.alpha != 0) {return true}
    else {return false}

}

我希望这会有所帮助。

于 2019-06-22T21:31:16.293 回答
1
import UIKit

class ViewController: UIViewController {
    
    let imageV = UIImageView(frame: CGRect(x: 0, y: 0, width: 223, height: 265))
    override func viewDidLoad() {
        super.viewDidLoad()
        imageV.center = view.center
        imageV.image = UIImage(named: "color_image")
        view.addSubview(imageV)
        // Do any additional setup after loading the view.
        
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
        imageV.isUserInteractionEnabled = true
        imageV.addGestureRecognizer(tapGestureRecognizer)
    }
    
    
    @objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
    {
        
        let cgpoint = tapGestureRecognizer.location(in: view)
        let color : UIColor = colorOfPoint(point: cgpoint)
        print("Picked Color is:",color)
        let new = UIView(frame: CGRect(x: 10, y: 10, width: 50, height: 50))
        new.backgroundColor = color
        view.addSubview(new)
    }
    
    func colorOfPoint(point:CGPoint) -> UIColor
    {
        let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        
        var pixelData:[UInt8] = [0, 0, 0, 0]
        
        let context = CGContext(data: &pixelData, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
        context!.translateBy(x: -point.x, y: -point.y);
        self.view.layer.render(in: context!)
        
        let red:CGFloat = CGFloat(pixelData[0])/CGFloat(255.0)
        let green:CGFloat = CGFloat(pixelData[1])/CGFloat(255.0)
        let blue:CGFloat = CGFloat(pixelData[2])/CGFloat(255.0)
        let alpha:CGFloat = CGFloat(pixelData[3])/CGFloat(255.0)
        
        let color:UIColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
        return color
    }
}
于 2021-10-21T06:44:01.547 回答