PDA

View Full Version : RGBA Color Information of CGPoint




Darkroom
Nov 29, 2009, 09:02 AM
what frameworks or apple example code should i research in order to receive pixel color information (RGBA) of CGPoint?



Darkroom
Nov 30, 2009, 08:17 AM
seems like a much tricker execution that i had imagined it would be / should be. i found a solution here: What Color is My Pixel? Image based color picker on iPhone (http://www.markj.net/iphone-uiimage-pixel-color/)

PhoneyDeveloper
Nov 30, 2009, 05:51 PM
If you're only going to get one pixel one time then the code on that blog might be ok. But it does memory allocations and draws the entire image every time you try to get one pixel. That's kind of ridiculous.

You might look at these:

https://devforums.apple.com/message/22176#22176

https://devforums.apple.com/message/20732#20732

http://developer.apple.com/mac/library/qa/qa2007/qa1509.html

Darkroom
Nov 30, 2009, 06:09 PM
i've looked at so many. i'm new to core graphics so i really can't tell which one is best. for clarity, can you explain in point form what should be done in order to receive an NSLog output of the RGBA values from a UIImage?

PhoneyDeveloper
Nov 30, 2009, 07:10 PM
In all cases what you want to do is get a pointer to the bitmap data and then read your pixel out of the bitmap data. The only question is how to get the pointer to the bitmap data.

The CopyImagePixels function in the apple reference gets the pointer to the bitmap data. I don't think you need to draw the image into a bitmap context in most cases. Then you can use the code from that blog to read out the four pixels.

Alternatively you could use the code from that blog entry but I would restructure it so that it only creates the bitmap context one time and only draws into it one time and then you can read out the pixels as many times as you like.

lloyddean
Nov 30, 2009, 11:25 PM
Don't assume the image pixels are in CPU memory, because depending upon the Graphics system they could very well be in a GPU's VRAM.

Darkroom
Dec 1, 2009, 07:31 AM
i'm planning on converting the UIImage to a CGImage, cycling thru the pixels of the CGImage once and adding them to an array that i can select from based on touch coordinates. but is an array even necessary?

it sounds like you're saying it isn't necessary to produce an array, and that all that is required is CopyImagePixels, but i don't understand how CopyImagePixels should be employed.


CFDataRef CopyImagePixels(CGImageRef inImage)
{
return CGDataProviderCopyData(CGImageGetDataProvider(inImage));
}

PhoneyDeveloper
Dec 1, 2009, 12:17 PM
The image data are in a kind of array and I don't see any point in copying each pixel or each channel into a second array. The RGBA info for each pixel is stored in order in the image data. Each pixel is stored in a row. There are as many rows as the height of the image.

There is code in that blog entry for reading the individual channels of a specified pixel into local variables and that code is OK.

What I would do is to write a simple class that manages the NSData that contains the image data. This class would then have methods to read the individual channels (rgba) and/or all four channels, depending on what your needs are.

Darkroom
Dec 1, 2009, 04:27 PM
ok. so i reworked the code to make the context draw only once as well as to handle touchesMoved. the following works, miraculously, but do you have any other thoughts?


#import "ColorPickerViewController.h"
#import <CoreGraphics/CoreGraphics.h>

@implementation ColorPickerViewController
@synthesize outputLabel, pictureView;


#pragma mark -
#pragma mark Launch Methods

- (void)viewWillAppear:(BOOL)animated
{
UIImage *colorWheelImage = [UIImage imageNamed:@"colorWheel1.png"];
self.pictureView.image = colorWheelImage;
[self createCGContextWithImage:colorWheelImage];

[super viewWillAppear:animated];
}

- (void)dealloc
{
[outputLabel release];
[pictureView release];
free(pixelData);
[super dealloc];
}


#pragma mark -
#pragma mark Touch Methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.view.backgroundColor = [self pixelColorAtLocation:[[touches anyObject] locationInView:self.pictureView]];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
self.view.backgroundColor = [self pixelColorAtLocation:[[touches anyObject] locationInView:self.pictureView]];
}


#pragma mark -
#pragma mark Pixel Data Methods

- (void)createCGContextWithImage:(UIImage*)image
{
NSLog(@"CGContext Created Image");
CGImageRef imageRef = [image CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger imageRefHeight = CGImageGetHeight(imageRef);

imageRefWidth = CGImageGetWidth(imageRef);
pixelData = malloc(imageRefWidth * imageRefHeight * 4);

NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = (bytesPerPixel * imageRefWidth);
NSUInteger bitsPerComponent = 8;

CGContextRef context = CGBitmapContextCreate(pixelData, imageRefWidth, imageRefHeight, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
CGContextDrawImage(context, CGRectMake(0, 0, imageRefWidth, imageRefHeight), imageRef);
CGContextRelease(context);
}

- (UIColor*)pixelColorAtLocation:(CGPoint)point
{
int offset = 4 * ((imageRefWidth * round(point.y)) + round(point.x));

int red = pixelData[offset];
int green = pixelData[offset+1];
int blue = pixelData[offset+2];
int alpha = pixelData[offset+3];

self.outputLabel.text = [NSString stringWithFormat:@"Red:%i\nGreen:%i\nBlue:%i\nAlpha:%i", red, green, blue, alpha];
return [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
}


@end

PhoneyDeveloper
Dec 1, 2009, 04:56 PM
You're leaking the color space ref.

Make sure that createCGContextWithImage() can only be called once or if it's called more than once that it doesn't leak the image data. You might want to check for errors when creating the bitmap context (it will return nil under some circumstances).

Otherwise looks OK.

Darkroom
Dec 1, 2009, 05:23 PM
oh... humm, i'm not use to CG... should i also release the CGImage on the last line after releasing the context??


CGImageRelease(imageRef);


also, what circumstances might return nil when creating a CGContext?

kainjow
Dec 1, 2009, 05:47 PM
oh... humm, i'm not use to CG... should i also release the CGImage on the last line after releasing the context??

Since the method doesn't have alloc, init, copy, or retain in it, you shouldn't release it. Any CG/CF/etc object you create via a Create function you should release yourself. If the object doesn't have its own special release function (like CGImageRelease), use CFRelease.

also, what circumstances might return nil when creating a CGContext?

The docs don't say anything specifically, but you could have mismatching arguments, or an invalid color space, etc. If it's possible for an error to occur, you should always check for it and handle it properly.

Darkroom
Dec 1, 2009, 05:59 PM
Any CG/CF/etc object you create via a Create function you should release yourself. If the object doesn't have its own special release function (like CGImageRelease), use CFRelease.

that's seems easy enough to remember. big help you guys. thanks. :)

PhoneyDeveloper
Dec 1, 2009, 06:12 PM
what circumstances might return nil when creating a CGContext?

Only some combinations of bitspercomponent, colorspace, and CGBitmapInfo are supported. If you ask for an unsupported combination it returns nil. There is a table somewhere in the docs that describes the supported combinations. Obviously the code you have is working now but I ran into a case where code that worked for an early version of iPhoneOS stopped working in a later version so these things can change. You might want to have an assertion for a nil context so you'll notice it if something changes.

One other comment. If you pass nil for the first parameter to CGBitmapContextCreate() it will create and destroy the image data buffer for you. Usually I'm not interested in the contents of that buffer so I always pass nil. In your case you could pass nil and then get the data buffer with CGBitmapContextGetData(). The way you have it is OK though as is.

Darkroom
Dec 1, 2009, 07:09 PM
i've just noticed some strange behavior. it seems the drawn image context is tiling beyond the boundaries of the native image's view frame. i've attached the project. if you drag near the bottom of the screen the colors continue to change.

i hope i'm doing something stupid rather than this being a bug?

guruk
Feb 28, 2010, 03:31 PM
Hi DarkRoom did you fixed that?
Because I really would like to use your two functions :)
but till now i also did not found the fix...

Also it would be the fastest routine i also found.. and even me tried several

thx
chris



i've just noticed some strange behavior. it seems the drawn image context is tiling beyond the boundaries of the native image's view frame. i've attached the project. if you drag near the bottom of the screen the colors continue to change.

i hope i'm doing something stupid rather than this being a bug?