Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
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

macrumors 68040
Sep 2, 2008
3,114
93
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.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
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.

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

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
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

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
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?

Code:
#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

macrumors 68040
Sep 2, 2008
3,114
93
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

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
oh... humm, i'm not use to CG... should i also release the CGImage on the last line after releasing the context??

Code:
CGImageRelease(imageRef);

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

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
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.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
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

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
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?
 

Attachments

  • ColorPicker.zip
    105.3 KB · Views: 127

guruk

macrumors newbie
Feb 28, 2010
1
0
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?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.