RGBA Color Information of CGPoint

Discussion in 'iPhone/iPad Programming' started by Darkroom, Nov 29, 2009.

  1. Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #1
    what frameworks or apple example code should i research in order to receive pixel color information (RGBA) of CGPoint?
     
  2. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #2
  3. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #3
  4. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #4
    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?
     
  5. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    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.
     
  6. macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #6
    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.
     
  7. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #7
    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));
    }
    
     
  8. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #8
    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.
     
  9. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #9
    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
    
     
  10. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #10
    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.
     
  11. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #11
    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?
     
  12. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #12
    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.

    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.
     
  13. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #13
    that's seems easy enough to remember. big help you guys. thanks. :)
     
  14. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #14
    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.
     
  15. thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #15
    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?
     

    Attached Files:

  16. macrumors newbie

    Joined:
    Feb 28, 2010
    #16
    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



     

Share This Page