glReadPixels() not updating - ios

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);
}

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/

RGB Values retrieved from Pixels incorrect

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.

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.

Striped Lines appear out of nowhere

I am trying to code a routine that would allow me to create a UIImage that is a rectangle filled with stripes on a gradient background.
My code is below and works fine for most of the cases I tried it out. Interestingly, and this is the hook, it doesn't work when I pass it 21 as height and 5 as stripedWidth.
Once I do this, the stripes appear as they should... horizontally.. but vertically they start at like (y=) -40 and end at about (y=) 4 or so. To see this better, each this image showing the effect in question:
Has anyone any idea why this is happening, or even better, what I can do against it?
-(UIImage*) stripedTextureWithStartingColor:(UIColor*) startColor withEndingColor:(UIColor*) endColor withHeight:(NSUInteger) height withStripeWidth:(NSUInteger) stripeWidth withStripeColor:(UIColor*) stripedColor {
CGSize size = CGSizeMake(2 * stripeWidth, height);
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
#try {
CGContextSetAllowsAntialiasing(context, true);
CGContextSetShouldAntialias(context, true);
NSArray* colors = [NSArray arrayWithObjects:(id) startColor.CGColor, (id) endColor.CGColor, nil];
CGFloat locations[2];
locations[0] = 0.0;
locations[1] = 1.0;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
CGColorSpaceRelease(colorSpace);
CGContextDrawLinearGradient(context, gradient, CGPointZero, CGPointMake(0, size.height - 1), 0);
CGGradientRelease(gradient);
CGContextFillPath(context);
int lineWidth = (int) stripeWidth;
CGContextSetLineWidth(context, lineWidth / 2);
int lineCount = (float) size.height / (float) lineWidth;
lineCount -= 2;
for (int i=0; i<lineCount; i++) {
CGContextSetStrokeColorWithColor(context, stripedColor.CGColor);
float x1 = -size.height + i * 2 * lineWidth - lineWidth;
float y1 = size.height - 1 + lineWidth;
float x2 = -size.height + i * 2 * lineWidth + size.height - lineWidth;
float y2 = -lineWidth;
CGContextMoveToPoint(context, x1, y1);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
}
UIColor* lineTopColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
UIColor* lineBottomColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.5];
CGContextSetStrokeColorWithColor(context, lineTopColor.CGColor);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, size.width + 1, 0);
CGContextStrokePath(context);
CGContextSetStrokeColorWithColor(context, lineBottomColor.CGColor);
CGContextMoveToPoint(context, 0, size.height - 1);
CGContextAddLineToPoint(context, size.width + 1, size.height - 1);
CGContextStrokePath(context);
}
#finally {
CGContextRestoreGState(context);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Found it, my algorithm was slightly incorrect with the starting of the lines

Drawing MKMapView Overlay like Google Maps Directions

iOS 5 changed the way the built-in Google Maps App draws routes:
I would now like to replicate the design of the route overlay in my own app but I am currently only able to draw a plain blue line. I would like to add the 3D-effect with the gradient, borders and the glow. Any ideas on how to accomplish this?
Currently I'm using the following code:
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextAddPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextFillPath(context);
Resulting in a rather ugly line:
Thanks!
Update: The solution should work on iOS 4.0 and up.
I think that #ChrisMiles is correct in that the segments are probably being drawn individually. (I initially thought that this might have been doable using CGPatternRef but you don't have any access to the CTM or path endpoints inside the pattern drawing callback.)
With this in mind, here is an exceedingly crude, back-of-the-envelope example of how you might begin such an effort (filling the segments individually). Note that:
gradient colors are guessed
end caps are nonexistent and will need to be separately implemented
some aliasing artifacts remain
not a great deal of attention was paid to performance
Hopefully this can get you started at least (and works through some of the analytic geometry).
- (CGGradientRef)lineGradient
{
static CGGradientRef gradient = NULL;
if (gradient == NULL) {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef white = [[UIColor colorWithWhite:1.f
alpha:0.7f] CGColor];
CGColorRef blue = [[UIColor colorWithRed:0.1f
green:0.2f
blue:1.f
alpha:0.7f] CGColor];
CGColorRef lightBlue = [[UIColor colorWithRed:0.4f
green:0.6f
blue:1.f
alpha:0.7f] CGColor];
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault,
8,
NULL);
CFArrayAppendValue(colors, blue);
CFArrayAppendValue(colors, blue);
CFArrayAppendValue(colors, white);
CFArrayAppendValue(colors, white);
CFArrayAppendValue(colors, lightBlue);
CFArrayAppendValue(colors, lightBlue);
CFArrayAppendValue(colors, blue);
CFArrayAppendValue(colors, blue);
CGFloat locations[8] = {0.f, 0.08f, 0.14f, 0.21f, 0.29f, 0.86f, 0.93f, 1.f};
gradient = CGGradientCreateWithColors(colorSpace,
colors,
locations);
CFRelease(colors);
CGColorSpaceRelease(colorSpace);
}
return gradient;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetShouldAntialias(context, YES);
// Fill background color
[[UIColor whiteColor] setFill];
UIRectFill(rect);
// Build a path
CGFloat strokeWidth = 10.f;
CGContextSetLineWidth(context, strokeWidth);
CGGradientRef gradient = [self lineGradient];
CGPoint points[9] = {
CGPointMake(10.f, 25.f),
CGPointMake(100.f, 100.f),
CGPointMake(100.f, 150.f),
CGPointMake(22.f, 300.f),
CGPointMake(230.f, 400.f),
CGPointMake(230.f, 200.f),
CGPointMake(300.f, 200.f),
CGPointMake(310.f, 160.f),
CGPointMake(280.f, 100.f)
};
for (NSUInteger i = 1; i < 9; i++) {
CGPoint start = points[i - 1];
CGPoint end = points[i];
CGFloat dy = end.y - start.y;
CGFloat dx = end.x - start.x;
CGFloat xOffset, yOffset;
// Remember that, unlike Cartesian geometry, origin is in *upper* left!
if (dx == 0) {
// Vertical to start, gradient is horizontal
xOffset = 0.5 * strokeWidth;
yOffset = 0.f;
if (dy < 0) {
xOffset *= -1;
}
}
else if (dy == 0) {
// Horizontal to start, gradient is vertical
xOffset = 0.f;
yOffset = 0.5 * strokeWidth;
}
else {
// Sloped
CGFloat gradientSlope = - dx / dy;
xOffset = 0.5 * strokeWidth / sqrt(1 + gradientSlope * gradientSlope);
yOffset = 0.5 * strokeWidth / sqrt(1 + 1 / (gradientSlope * gradientSlope));
if (dx < 0 && dy > 0) {
yOffset *= -1;
}
else if (dx > 0 && dy < 0) {
xOffset *= -1;
}
else if (dx < 0 && dy < 0) {
yOffset *= -1;
xOffset *= -1;
}
else {
}
}
CGAffineTransform startTransform = CGAffineTransformMakeTranslation(-xOffset, yOffset);
CGAffineTransform endTransform = CGAffineTransformMakeTranslation(xOffset, -yOffset);
CGPoint gradientStart = CGPointApplyAffineTransform(start, startTransform);
CGPoint gradientEnd = CGPointApplyAffineTransform(start, endTransform);
CGContextSaveGState(context);
CGContextMoveToPoint(context, start.x, start.y);
CGContextAddLineToPoint(context, end.x, end.y);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
CGContextDrawLinearGradient(context,
gradient,
gradientStart,
gradientEnd,
kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation);
CGContextRestoreGState(context);
}
CGContextRestoreGState(context);
}
I would say they are drawing a CGPath around the original line, stroking the edges and gradient filling it. The ends are capped by adding a semi circle to the CGPath.
Would be a bit more work than simply drawing a single line and stroking it, but gives them full control over the style of the rendered path.

Resources