RGB Values retrieved from Pixels incorrect - ios

I've rendered a circular gradient and created a method that lets me sweep over it with my finger, using a Pan gesture recognizer.
I am retrieving the pixel at my current touch position and want to retrieve it's color.
This means, the color value should constantly update while moving over the gradient.
i'm using the following code :
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender {
CGPoint translation = [sender translationInView:iv];
[sender setTranslation:CGPointZero inView:self.view];
CGPoint center = sender.view.center;
center.x += translation.x;
center.y += translation.y;
sender.view.center = center;
CGPoint colorPoint = [sender.view.superview convertPoint:center toView:iv];
[sender setTranslation:CGPointMake(0, 0) inView:self.view];
CGImageRef image = img.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
char *rawData = malloc(height * width * 4);
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(
rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);
int byteIndex = (bytesPerRow * colorPoint.y) + colorPoint.x * bytesPerPixel;
unsigned char red = rawData[byteIndex];
unsigned char green = rawData[byteIndex+1];
unsigned char blue = rawData[byteIndex+2];
UIColor *hauptfarbe = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
ch.backgroundColor = hauptfarbe;
NSLog(#"Color value - R : %i G : %i : B %i",red, green, blue);
}
this doesn't work as intended, giving me wrong colors and not showing some colors (like red) at all
EDIT : I cannot add a picture yet due to low rep. i will now add the code for rendering the gradient
Code :
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
int sectors = 180;
float radius = MIN(size.width, size.height)/2;
float angle = 2 * M_PI/sectors;
UIBezierPath *bezierPath;
for ( int i = 0; i < sectors; i++)
{
CGPoint center = CGPointMake((size.width/2), (size.height/2));
bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:i * angle endAngle:(i + 1) * angle clockwise:YES];
[bezierPath addLineToPoint:center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:((float)i)/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
img = UIGraphicsGetImageFromCurrentImageContext();
iv = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:iv];
[self.view addSubview:ch];
}

The first problem here is the way you're calculating colorPoint. They way it is now, colorPoint will always be the center point of the view. This handlePan: method should get you the point of the last touch in the view:
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender
{
if (sender.numberOfTouches)
{
CGPoint lastPoint = [sender locationOfTouch: sender.numberOfTouches - 1 inView: sender.view];
NSLog(#"lastPoint: %#", NSStringFromCGPoint(lastPoint));
}
}
From there, I would probably recommend that instead of blitting the image into a bitmap context and then attempting to read back from it at that point, that you just calculate the color for the point using the same mathematical process you used to create the image in the first place. The way you're doing it now is going to be much more CPU + memory intensive.
EDIT: Here's what I came up with. It works for me. Starting from the Single View Application template in Xcode, and using the code you posted, I have the following code in ViewController.m:
#implementation ViewController
{
UIImage* img;
UIImageView* iv;
}
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
int sectors = 180;
float radius = MIN(size.width, size.height)/2;
float angle = 2 * M_PI/sectors;
UIBezierPath *bezierPath;
for ( int i = 0; i < sectors; i++)
{
CGPoint center = CGPointMake((size.width/2), (size.height/2));
bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:i * angle endAngle:(i + 1) * angle clockwise:YES];
[bezierPath addLineToPoint:center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:((float)i)/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
img = UIGraphicsGetImageFromCurrentImageContext();
iv = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:iv];
colorView = [[UIView alloc] init];
colorView.frame = CGRectMake(CGRectGetMaxX(bounds) - 25, CGRectGetMaxY(bounds) - 25, 20, 20);
[self.view addSubview:colorView];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePan:)];
[self.view addGestureRecognizer: panGesture];
}
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender
{
if (sender.numberOfTouches)
{
CGPoint lastPoint = [sender locationOfTouch: sender.numberOfTouches - 1 inView: sender.view];
CGRect bounds = self.view.bounds;
CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGPoint delta = CGPointMake(lastPoint.x - center.x, lastPoint.y - center.y);
CGFloat angle = (delta.y == 0 ? delta.x >= 0 ? 0 : M_PI : atan2(delta.y, delta.x));
angle = fmod(angle, M_PI * 2.0);
angle += angle >= 0 ? 0 : M_PI * 2.0;
UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:1. brightness:1. alpha:1];
colorView.backgroundColor = color;
CGFloat r,g,b,a;
if ([color getRed: &r green: &g blue:&b alpha: &a])
{
NSLog(#"Color value - R : %g G : %g : B %g", r, g, b);
}
}
}
#end
What I see is that as I drag my finger over the gradient, I get a steady stream of messages to console with RGB values that correspond to the location of my finger. I've also added code to show the last color in a small view in the lower right. It also doesn't use bitmap contexts. Hope this helps.

Related

How to make UI with round image and round text, also add ratting icon on same circle. in iOS application

How to make UI with round image and round text, also add ratting icon on same circle. in iOS application
Import roundImageView.h class in your view class and set background image on your UIButton. Please change button type Custom.
After Following these steps try this code .
CGRect frame = CGRectMake(0, 0, 200, 200);
roundImageView *roudImage = [[roundImageView alloc]init];
UIImage *image1 = [roudImage createMenuRingWithFrame:frame :#"Your Title" labelBgColor:[UIColor colorWithRed:(191/255.f) green:(251/255.f) blue:(158/255.f) alpha:1] ringBgColor:[UIColor colorWithRed:(214/255.f) green:(214/255.f) blue:(214/255.f) alpha:1] levelUnlockShow:1 buttonObj:yourButtonObj];
[yourButtonObj setImage:image1 forState:UIControlStateNormal];
Note :- In this you can see we set only Image not background image ..
Create a class roundImageView UIImage Type and paste this code
in roundImageView.h file code
#import <UIKit/UIKit.h>
#interface roundImageView : UIImage
- (UIImage*) createMenuRingWithFrame:(CGRect)frame : (NSString*) sectionTitle labelBgColor : (UIColor*)labelBgColor ringBgColor : (UIColor *)ringBgColor levelUnlockShow: (NSInteger) levelUnloackNm buttonObj : (UIButton *)buttonObj;
Paste code in roundImageView.m file
#import "roundImageView.h"
#implementation roundImageView
#define DegreesToRadians(x) (M_PI * x / 180.0)
- (void) drawStringAtContext:(CGContextRef) context string:(NSString*) text atAngle:(float) angle withRadius:(float) radius
{
CGSize textSize = [text sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:18]}];
float perimeter = 2 * M_PI * radius;
float textAngle = textSize.width / perimeter * 2 * M_PI;
angle += textAngle / 2;
for (int index = 0; index < [text length]; index++)
{
NSRange range = {index, 1};
NSString* letter = [text substringWithRange:range];
char* c = (char*)[letter cStringUsingEncoding:NSASCIIStringEncoding];
CGSize charSize = [letter sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:18]}];
NSLog(#"Char %# with size: %f x %f", letter, charSize.width, charSize.height);
float x = radius * cos(angle);
float y = radius * sin(angle);
float letterAngle = (charSize.width / perimeter * -2 * M_PI);
CGContextSaveGState(context);
CGContextTranslateCTM(context, x, y);
CGContextRotateCTM(context, (angle - 0.5 * M_PI));
CGContextShowTextAtPoint(context, 0, 0, c, strlen(c));
CGContextRestoreGState(context);
angle += letterAngle;
}
}
- (void)drawRect:(CGRect)rect contextData:(CGContextRef) context {
CGContextSetLineWidth(context, 30);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 50);
CGContextAddCurveToPoint(context, 0, 180, 0, 0, -80, 0);
CGContextStrokePath(context);
}
- (UIImage*) createMenuRingWithFrame:(CGRect)frame : (NSString*) sectionTitle labelBgColor : (UIColor*)labelBgColor ringBgColor : (UIColor *)ringBgColor levelUnlockShow: (NSInteger) levelUnloackNm buttonObj : (UIButton *)buttonObj
{
CAShapeLayer *circle = [CAShapeLayer layer];
// Make a circular shape
UIBezierPath *circularPath=[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, buttonObj.frame.size.width, buttonObj.frame.size.height) cornerRadius:MAX(buttonObj.frame.size.width, buttonObj.frame.size.height)];
circle.path = circularPath.CGPath;
// Configure the apperence of the circle
circle.fillColor = [UIColor blackColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 0;
buttonObj.layer.mask = circle;
CGPoint centerPoint = CGPointMake(frame.size.width / 2, frame.size.height / 2);
char* fontName = (char*)[[UIFont fontWithName:#"Helvetica" size:18].fontName cStringUsingEncoding:NSASCIIStringEncoding];
const CGFloat* ringColorComponents = CGColorGetComponents([ringBgColor CGColor]);
// const CGFloat* textBGColorComponents = CGColorGetComponents([[UIColor colorWithRed:80/255.0 green:160/255.0 blue:15/255.0 alpha:1] CGColor]) ;
const CGFloat* textColorComponents = CGColorGetComponents([[UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:1] CGColor]);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, frame.size.width, frame.size.height, 8, 4 * frame.size.width, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextSelectFont(context, fontName, 18, kCGEncodingMacRoman);
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
CGContextSetLineWidth(context, 25);
CGContextStrokeEllipseInRect(context, CGRectMake(10, 10, frame.size.width - (10 * 2), frame.size.height - (10 * 2)));
CGContextSetRGBFillColor(context, textColorComponents[0], textColorComponents[1], textColorComponents[2], 1.0);
CGContextSaveGState(context);
CGContextTranslateCTM(context, centerPoint.x, centerPoint.y);
// float angleStep = 2 * M_PI ;
float angle = DegreesToRadians(135);
float textRadius = 95;
textRadius = textRadius - 12;
// [self drawImageAtContext:context string:text atAngle:angle withRadius:textRadius];
[self drawLblBackGroundAtContext:context string:sectionTitle atAngle:angle withRadius:textRadius withLabelBackgroudColor:labelBgColor ];
//angle -= angleStep;
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
CGContextSetLineWidth(context, 25);
[self drawStringAtContext:context string:sectionTitle atAngle:angle withRadius:textRadius];
//angle -= angleStep;
angle = DegreesToRadians(315);
// [self drawImageAtContext:context string:text atAngle:angle withRadius:textRadius];
[self drawImageAtContext:context atAngle:angle withRadius:textRadius levelUnlock: levelUnloackNm];
//angle -= angleStep;
CGContextRestoreGState(context);
CGImageRef contextImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
//[self saveImage:[UIImage imageWithCGImage:contextImage] withName:#"test.png"];
return [UIImage imageWithCGImage:contextImage];
}
- (void) drawImageAtContext:(CGContextRef) context atAngle:(float) angle withRadius:(float) radius levelUnlock:(NSInteger )levelUnlock
{
CGSize textSize = [#"MMMMMM" sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:18]}];
float perimeter = 2 * M_PI * radius;
float textAngle = (textSize.width+1) / perimeter * 2 * M_PI;
angle += textAngle / 2;
// UIImageView *image = [[UIImageView alloc]initWithFrame:CGRectMake(angle, 0, 20, 20)];
if (levelUnlock != 0) {
for (int index = 0; index < 6; index++)
{
NSRange range = {index, 1};
NSString* letter = [#"MMMMMM" substringWithRange:range];
CGSize charSize = [letter sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:18]}];
NSLog(#"Char %# with size: %f x %f", letter, charSize.width, charSize.height);
float x = radius * cos(angle);
float y = radius * sin(angle);
float letterAngle = ((charSize.width+1) / perimeter * -2 * M_PI);
CGContextSaveGState(context);
CGContextTranslateCTM(context, x, y);
CGContextRotateCTM(context, (angle - 0.5 * M_PI));
// CGContextShowTextAtPoint(context, 0, 0, c, strlen(c));
const CGFloat* ringColorComponents;
NSInteger raiting = 6 - levelUnlock ;
if (index + 1 > raiting) {
ringColorComponents = CGColorGetComponents([[UIColor colorWithRed:0/255.0 green:170/255.0 blue:216/255.0 alpha:1] CGColor]);
}else{
ringColorComponents = CGColorGetComponents([[UIColor colorWithRed:150/255.0 green:150/255.0 blue:150/255.0 alpha:1] CGColor]);
}
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
CGContextSetRGBFillColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
CGContextSetLineWidth(context, 8);
//Line Changed for border
CGContextStrokeEllipseInRect(context, CGRectMake(2, 1, 8, 8));
CGContextRestoreGState(context);
angle += letterAngle;
}
}
}
- (void) drawLblBackGroundAtContext:(CGContextRef) context string:(NSString*) text atAngle:(float) angle withRadius:(float) radius withLabelBackgroudColor: (UIColor *)labelBgColor
{
// text = [NSString stringWithFormat:#"%#sdsad",text];
CGSize textSize = [text sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:20]}];//[text sizeWithFont:[UIFont fontWithName:#"Helvetica" size:20]];
float perimeter = 2 * M_PI * radius;
float textAngle = textSize.width / perimeter * 2 * M_PI;
angle += textAngle / 2;
for (int index = 0; index < [text length]; index++)
{
NSRange range = {index, 1};
NSString* letter = [text substringWithRange:range];
// char* c = (char*)[letter cStringUsingEncoding:NSASCIIStringEncoding];
CGSize charSize = [letter sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:18]}];
NSLog(#"Char %# with size: %f x %f", letter, charSize.width, charSize.height);
float x = radius * cos(angle);
float y = radius * sin(angle);
float letterAngle = ((charSize.width+1) / perimeter * -2 * M_PI);
CGContextSaveGState(context);
CGContextTranslateCTM(context, x, y);
CGContextRotateCTM(context, (angle - 0.5 * M_PI));
const CGFloat* ringColorComponents = CGColorGetComponents([ labelBgColor CGColor]);
CGContextSetRGBStrokeColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
CGContextSetRGBFillColor(context, ringColorComponents[0], ringColorComponents[1], ringColorComponents[2], 1.0);
if (index + 1 == [text length]){
CGContextSetLineWidth(context, 15);
CGContextStrokeRect(context, CGRectMake(0, 2, 15, 15));
}else{
CGContextSetLineWidth(context, 15);
CGContextStrokeRect(context, CGRectMake(0, 2, 15, 15));
}
CGContextRestoreGState(context);
if (index +1 == [text length]) {
angle += letterAngle ;
}else{
angle += letterAngle;
}
}
}
#end
Try this code its working fine ...
Well,i didnt got your question completely..,if u want ur image view to be a proper circle,then use layer property.
Add QuartzCore framework to your project
#import <QuartzCore/QuartzCore.h>
then,in viewDidLoad ,add the following code.
myImageView.layer.cornerRadius = (myImageView.bounds.size.height/2);
myImageView.layer.masksToBounds = YES;
The rest is upto you,use your logic to do the remaining.
EDIT
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CALayer_class/index.html go through these.
You can take a look on WWDC2014 videos: "What's new in interface builder."
They are creating class similar to what you need.
https://developer.apple.com/videos/wwdc/2014/

Drawing anti-aliased line

I'm drawing a line on the screen which includes diagonal lines which in turn are drawing like this:
Notice how it doesn't look smooth at all. I've read a few articles on this and it would seem this looks the one closer to the issue I'm having, but the solution is not working for me.
Here's how I setup the layer:
- (void)viewDidLoad
{
[super viewDidLoad];
// Instantiate the navigation line view
CGRect navLineFrame = CGRectMake(0.0f, 120.0f, self.view.frame.size.width, 15.0f);
self.navigationLineView = [[HyNavigationLineView alloc] initWithFrame:navLineFrame];
// Make it's background transparent
self.navigationLineView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
self.navigationLineView.opaque = NO;
HyNavigationLineLayer * layer = [[HyNavigationLineLayer alloc] init];
layer.shouldRasterize = YES;
layer.rasterizationScale = [UIScreen mainScreen].scale;
layer.contentsScale = [[UIScreen mainScreen] scale];
layer.needsDisplayOnBoundsChange = YES;
[[self.navigationLineView layer] addSublayer:layer];
[self.view addSubview:self.navigationLineView];
[self.navigationLineView.layer setNeedsDisplay];
}
Here's how I'm drawing in the layer:
- (void)drawInContext:(CGContextRef)ctx
{
CGFloat bottomInset = 1.0f / [[UIScreen mainScreen] scale] * 2.0f;
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
GLfloat padding = kHyNavigationLineViewPadding * 4.0f;
GLfloat searchSpace = self.frame.size.width - padding - kHyNavigationLineViewPointerSize * 2.0f;
GLfloat x = kHyNavigationLineViewPadding * 2.0f + searchSpace * self.offset;
CGContextSetLineWidth(ctx, 2.0f);
CGContextMoveToPoint(ctx, kHyNavigationLineViewPadding, 0.0f);
CGContextAddLineToPoint(ctx, x, bottomInset);
CGContextAddLineToPoint(ctx, x + kHyNavigationLineViewPointerSize, self.frame.size.height);
CGContextAddLineToPoint(ctx, x + kHyNavigationLineViewPointerSize * 2.0f, bottomInset);
CGContextAddLineToPoint(ctx, self.frame.size.width - kHyNavigationLineViewPadding, 0.0f);
// Draw
CGContextStrokePath(ctx);
}
Any hints on how to solve this?
Edit: forgot to mention the reason I was drawing in the layer in the first place: I need to animate a property which causes this line to animate was well, so drawing in drawRect doesn't work.
Instead of using quartz to render the code, you can use UIBezierPath to render instead:
UIBezierPath* path = [UIBezierPath bezierPath];
[[UIColor whiteColor] setStroke];
GLfloat padding = kHyNavigationLineViewPadding * 4.0f;
GLfloat searchSpace = self.frame.size.width - padding - kHyNavigationLineViewPointerSize * 2.0f;
GLfloat x = kHyNavigationLineViewPadding * 2.0f + searchSpace * self.offset;
path.lineWidth = 2.0;
[path moveToPoint:CGPointMake(kHyNavigationLineViewPadding, 0)];
[path addLineToPoint:CGPointMake(x, bottomInset)];
[path addLineToPoint:CGPointMake(x + kHyNavigationLineViewPointerSize, self.frame.size.height)];
[path addLineToPoint:CGPointMake(x + kHyNavigationLineViewPointerSize * 2.0f, bottomInset)];
[path addLineToPoint:CGPointMake(self.frame.size.width - kHyNavigationLineViewPadding, 0.0f)];
[path stroke];

Why isn't this random color method working?

I have a for loop inside the drawRect method that draws a number of circles to fill the screen. I'm trying to make it so each circle has a new random stroke. For some reason nothing is showing up. Here is my randomColor method:
-(UIColor *) randomColor
{
int red, green, blue, alpha;
red = arc4random_uniform(255);
green = arc4random_uniform(255);
blue = arc4random_uniform(255);
alpha = arc4random_uniform(255);
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red green:green blue:blue alpha:alpha];
return colorToReturn;
}
and I try implementing it here:
-(void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
// Firgure out the center of the bounds rectangle
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
// The radius of the circle should be nearly as big as the view
float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
// The thickness of the line should be 10 points wide
CGContextSetLineWidth(ctx, 10);
// The color of the line should be gray (red/green/blue = 0.6, alpha = 1.0)
// CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);
// The same as
// [[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] setStroke];
// The same as
// [[UIColor redColor] setStroke];
// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
// Add a path to the context
CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
[[self randomColor] setStroke];
// Perform drawing instructions; removes path
CGContextStrokePath(ctx);
}
UIColor takes a float between 0 and 1 as a value for its RGB components:
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:alpha];
I use the two macros below to get a random color. The first one is a straightforward macro that I often use while setting colors. The second one returns a random color using it:
#define _RGB(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
#define kCLR_RANDOM_COLOR _RGB(arc4random()%255, arc4random()%255, arc4random()%255, 1)

glReadPixels() not updating

i'm using code to render a circular gradient and create a crosshair (subview) on the gradient via touch. I now want to read the pixels at touch position and have it return the RGB value, but it always gives me the same value..
EDIT : added the code that renders the gradient
COMPLETELY NEW CODE :
viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
int sectors = 180;
float radius = MIN((size.width - 100), (size.height - 100))/2;
float angle = 2 * M_PI/sectors;
UIBezierPath *bezierPath;
for ( int i = 0; i < sectors; i++)
{
CGPoint center = CGPointMake((size.width/2), (size.height/2));
bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:i * angle endAngle:(i + 1) * angle clockwise:YES];
[bezierPath addLineToPoint:center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:((float)i)/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
img = UIGraphicsGetImageFromCurrentImageContext();
iv = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:iv];
[self.view addSubview:ch];
}
My pan gesture recognizer :
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender {
CGPoint translation = [sender translationInView:self.view];
[sender setTranslation:CGPointZero inView:self.view];
CGPoint center = sender.view.center;
center.x += translation.x;
center.y += translation.y;
sender.view.center = center;
CGPoint colorPoint = [sender.view.superview convertPoint:center toView:iv];
[sender setTranslation:CGPointMake(0, 0) inView:self.view];
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(img.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
int pixelInfo = (img.size.width * colorPoint.y ) +colorPoint.x ;
float red = data[pixelInfo];
float green = data[(pixelInfo + 1)];
float blue = data[pixelInfo + 2];
float alpha = data[pixelInfo + 3];
UIColor *pixelcolor = [UIColor colorWithRed:red/255 green:green/255 blue:blue/255 alpha:alpha]; // The pixel color info
CFRelease(pixelData);
NSLog(#"Color Value : %f, %f, %f, %f",red,green,blue,alpha);
}
Some of the NSLogs :
2013-07-05 10:04:20.913 ColorPicker[614:11603] pixel color: 156, 212, 255
2013-07-05 10:04:20.929 ColorPicker[614:11603] pixel color: 156, 212, 255
2013-07-05 10:04:20.947 ColorPicker[614:11603] pixel color: 156, 212, 255
2013-07-05 10:04:21.014 ColorPicker[614:11603] pixel color: 156, 212, 255
2013-07-05 10:04:21.047 ColorPicker[614:11603] pixel color: 156, 212, 255
2013-07-05 10:04:21.447 ColorPicker[614:11603] pixel color: 156, 212, 255
EDIT : The Colors are also incorrect. I get a different RGB value at the very first move, then the value changes once and stays the same.
Is glReadPixels just this slow, or is something wrong with my frame buffer?
You are resetting the gesture recognizer's translation after every detected event. This means that the coordinates in colorPoint do not vary much.
You should calculate colorPoint by using sender.view.center and converting this into iv's coordinate system.
CGPoint translation = [sender translationInView:self.view];
[sender setTranslation:CGPointZero inView:self.view];
CGPoint center = sender.view.center;
center.x += translation.x;
center.y += translation.y;
sender.view.center = center;
CGPoint colorPoint = [sender.view.superview convertPoint:center toView:iv];
Now colorPoint is the current position of the gesture recognizer's view, expressed in iv's coordinate system.
Alright, the issue of it not updating was solved by myself.
I am using a whole different reading method now.
Thanks to Nikolai for getting me started on the centering
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender {
CGPoint translation = [sender translationInView:iv];
[sender setTranslation:CGPointZero inView:self.view];
CGPoint center = sender.view.center;
center.x += translation.x;
center.y += translation.y;
sender.view.center = center;
CGPoint colorPoint = [sender.view.superview convertPoint:center toView:iv];
[sender setTranslation:CGPointMake(0, 0) inView:self.view];
CGImageRef image = img.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
char *rawData = malloc(height * width * 4);
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(
rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);
int byteIndex = (bytesPerRow * colorPoint.y) + colorPoint.x * bytesPerPixel;
unsigned char red = rawData[byteIndex];
unsigned char green = rawData[byteIndex+1];
unsigned char blue = rawData[byteIndex+2];
UIColor *hauptfarbe = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
ch.backgroundColor = hauptfarbe;
NSLog(#"Color value - R : %i G : %i : B %i",red, green, blue);
}

Draw line between two moveable circles in objective-c (iPad)

I'm new to objective-c and am trying to draw a line between moveable circles in Objective-c. I already have code that generates circles. Here is an image that I'd like to create in my app.
http://images.sciencedaily.com/2004/04/040407083832.jpg
Here's my code.
CircleViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
for (int i=0; i<5; i++) {
CGRect circleFrame = CGRectMake(arc4random() % 500, arc4random() % 500, (arc4random() % 200)+50 , (arc4random() % 200)+50);
CircleView *cirleView = [[CircleView alloc] initWithFrame: circleFrame];
cirleView.backgroundColor = [UIColor clearColor];
CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black
UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
cirleView.circleColor = color;
[self.view addSubview:cirleView];
}
}
CircleView.m
-(void) drawCircle:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)contex
{
UIGraphicsPushContext(contex);
CGContextBeginPath(contex);
CGContextAddArc(contex, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextSetLineWidth(contex, 2.0);
CGContextAddLineToPoint(contex, p.x, p.y);
CGContextDrawPath(contex, kCGPathFillStroke);
UIGraphicsPopContext();
}
- (void)drawRect:(CGRect)rect
{
CGFloat size = self.bounds.size.width/2;
if(self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height / 2;
size *= 0.90;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
[_circleColor setStroke];
[_circleColor setFill];
CGPoint point1;
point1.x = self.bounds.origin.x + self.bounds.size.width/2;
point1.y = self.bounds.origin.y + self.bounds.size.height/2;
[self drawCircle:point1 withRadius:size inContext:context];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self addGestureRecognizer:singleFingerTap];
}
Thank you for your help.
Drawing a line:
-(void) drawLine (CGRect circleViewRect1, CGRect circleViewRect2)
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
//line width
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, circleViewRect1.center.x + circleViewRect1.bounds.width/2,circleViewRect1.center.y + circleViewRect1.bounds.height/2); //start from first circle radius
CGContextAddLineToPoint(context, circleViewRect2.center.x + circleViewRect2.bounds.width/2,circleViewRect2.center.y + circleViewRect2.bounds.height/2); //draw to this point
// and now draw the Path!
CGContextStrokePath(context);
}
Note:This is only useful if two circle's centers fall in horizontal line. Also, assume that circleViewRect1 is at the left of circleViewRect2. You must figure out the values for other use cases ie if they are at positioned at different angles etc.

Resources