iOS CGContext drawing a line graph in a for loop cocos2d - ios

I have a for loop and within the for loop i do the following, this creates a line graph on the background of my chart, however it displays the same image of a line on each background exactly the same even though the data is different.
UIGraphicsBeginImageContext(test.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextFlush(c);
CGContextSetAllowsAntialiasing(c, true);
CGContextTranslateCTM(c, 0, test.size.height);
CGContextScaleCTM(c, 1.0, -1.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(c, color);
CGContextMoveToPoint(c, 0, 0);
if(maxPoints > 0)
{
float xSpacing = (float)330.0f/(float)[allScorePointsSubset count];
int currentPoint;
float currentX;
float currentY;
for (int j = 0; j < [allScorePointsSubset count]; j++)
{
NSString *currentPointString = [allScorePointsSubset objectAtIndex:j];
currentPoint = (int)[currentPointString intValue];
if(currentPoint < 0)
currentPoint = 0;
currentX = (j+1)*xSpacing;
currentY = currentPoint / 100.0f * 200.0f;
CGContextAddLineToPoint(c, (int)currentX, (int)currentY);
}
}
CGContextStrokePath(c);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
UIImage *graphImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CCSprite* answerMenuNormalSprite = [CCSprite spriteWithCGImage:graphImage.CGImage key: [NSString stringWithFormat:#"answerMenuNormalSprite_%f", i]];
[answerMenuNormalSprite setPosition:ccp(176,66)];
[[background objectAtIndex:0] addChild:answerMenuNormalSprite z:0 tag:i];
Has anyone got any ideas what i am doing wrong and does this have to be in the following method
-(void)draw
{
[super draw];
}
Thanks

It turns out that my counter was not incrementing properly and the problem was simply down to not giving the image a unique key in the following line
CCSprite* answerMenuNormalSprite = [CCSprite spriteWithCGImage:graphImage.CGImage key: [NSString stringWithFormat:#"answerMenuNormalSprite_%f", i]];

Related

Draw dashed line in iOS

I used CGContext to draw dashed lines in iOS.
My code is as follow.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGFloat dashes[] = {5,5};
CGContextSetLineDash(context, 0, dashes, 2);
float startx = x_percentileValues[0];
float starty = orgy-numskipPixels_v*(3-minWeight);
for(int i=0; i<[MeasuredInfos.retval count]; i++) {
float x = numskipPixels_h*hoursBetweenDates*3+orgx;
float y = orgy-([[MeasuredInfos.retval objectAtIndex: i] getWeight] - minWeight)*numskipPixels_v;
CGContextMoveToPoint(context, startx, starty);
CGContextAddLineToPoint(context, x, y);
CGContextStrokePath(context);
startx = x;
starty = y;
}
It is fine if the slope of the line is steep. If not steep, the dashed line has problem as shown in the attached pictures.
I checked in this link, nothing much discussion for the CGContextSetLineDash.
I found the problem. The problem is that I used two CGContextRef in two separate functions. One is in
- (void)drawRect:(CGRect)rect {
//Get the CGContext from this view
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the stroke (pen) color
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
//Set the width of the pen mark
CGContextSetLineWidth(context, 2.0);
float startx = x_percentileValues[0];
float starty = orgy-numskipPixels_v*(3-minWeight);
for(int i=0; i<[MeasuredInfos.retval count]; i++) {
float x = numskipPixels_h*hoursBetweenDates*3+orgx;
float y = orgy-([[MeasuredInfos.retval objectAtIndex: i] getWeight] - minWeight)*numskipPixels_v;
CGContextMoveToPoint(context, startx, starty);
CGContextAddLineToPoint(context, x, y);
CGContextStrokePath(context);
startx = x;
starty = y;
[self drawStar_atX:x andatY:y];
}
}
Another one in drawStar_atX
-(void)drawStar_atX:(float)xCenter andatY:(float)yCenter
{
int aSize = 5.0;
CGFloat color[4] = { 1.0, 0.0, 0.0, 1.0 }; // Red
CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color);
CGContextRef context1 = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context1, aSize);
float w = 15.0;
double r = w / 2.0;
float flip = -1.0;
CGContextSetFillColorWithColor(context1, aColor);
CGContextSetStrokeColorWithColor(context1, aColor);
double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextMoveToPoint(context1, xCenter, r*flip+yCenter);
for (NSUInteger k=1; k<5; k++)
{
float x = r * sin(k * theta);
float y = r * cos(k * theta);
CGContextAddLineToPoint(context1, x+xCenter, y*flip+yCenter);
}
CGContextClosePath(context1);
CGContextFillPath(context1);
return;
}
I called drawStar_atX from drawRect. context and context1 in two functions have some problems and start from the second segment the dashed line's width becomes bigger. Actually they are declared in different functions with different widths, shouldn't have any relationship. Now I solved the problem as context and context1 has same width. Still learning why they have some relations.

iOS drawing over UIImage

I need to draw over an image graffiti style, as below. My problem is that I need to have the capability to erase the lines I've drawn without erasing sections of the UIImage. At the moment I'm considering using one image for the background image and another image, with a transparent background, for the graffiti drawing, then combining the two once the drawing is complete. Is there a better way?
- (void)drawRect:(CGRect)rect
{
//Get drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
//Create drawing layer if required
if(drawingLayer == nil)
{
drawingLayer = CGLayerCreateWithContext(context, bounds.size, NULL);
CGContextRef layerContext = CGLayerGetContext(drawingLayer);
CGContextScaleCTM(layerContext, scale, scale);
self.viewRect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.width);
NSLog(#"%f %f",self.viewRect.size.width,self.viewRect.size.width);
}
//Draw paths from array
int arrayCount = [pathArray count];
for(int i = 0; i < arrayCount; i++)
{
path = [pathArray objectAtIndex:i];
UIBezierPath *bezierPath = path.bezierPath;
CGContextRef layerContext = CGLayerGetContext(drawingLayer);
CGContextAddPath(layerContext, bezierPath.CGPath);
CGContextSetLineWidth(layerContext, path.width);
CGContextSetStrokeColorWithColor(layerContext, path.color.CGColor);
CGContextSetLineCap(layerContext, kCGLineCapRound);
if(activeColor == 4)
{
CGContextSetBlendMode(layerContext, kCGBlendModeClear);
}
else
{
CGContextSetBlendMode(layerContext, kCGBlendModeNormal);
}
CGContextStrokePath(layerContext);
}
if (loadedImage == NO)
{
loadedImage = YES;
CGContextRef layerContext = CGLayerGetContext(drawingLayer);
CGContextSaveGState(layerContext);
UIGraphicsBeginImageContext (self.viewRect.size);
CGContextTranslateCTM(layerContext, 0, self.viewRect.size.height);
CGContextScaleCTM(layerContext, 1.0, -1.0);
CGContextDrawImage(layerContext, self.viewRect, self.image.CGImage);
UIGraphicsEndImageContext();
CGContextRestoreGState(layerContext);
}
[pathArray removeAllObjects];
CGContextDrawLayerInRect(context, self.viewRect, drawingLayer);
}

How to draw a table in a PDF file in iOS.

Currently I am developing an Expense Management App. In this app, I want retrive data from the local database and make a pdf file for it in a tabular format.Guidance needed on how should I proceed on doing this.
Thanks.
You can create table in PDF by following below steps:
Step 1. Create UIGraphics PDF Context:
UIGraphicsBeginPDFContextToFile(filePath, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kPageWidth, kPageHeight), nil);
[self drawTableAt:CGPointMake(6,38) withRowHeight:30 andColumnWidth:120 andRowCount:kRowsPerPage andColumnCount:5];
UIGraphicsEndPDFContext();
Step 2. Add these two helper functions to the same file (or same class implementation):
-(void)drawTableAt: (CGPoint)origin withRowHeight: (int)rowHeight andColumnWidth: (int)columnWidth andRowCount: (int)numberOfRows andColumnCount:(int)numberOfColumns{
for (int i = 0; i <= numberOfRows; i++) {
int newOrigin = origin.y + (rowHeight*i);
CGPoint from = CGPointMake(origin.x, newOrigin);
CGPoint to = CGPointMake(origin.x + (numberOfColumns*columnWidth), newOrigin);
[self drawLineFromPoint:from toPoint:to];
}
for (int i = 0; i <= numberOfColumns; i++) {
int newOrigin;
if(i==0){
newOrigin = origin.x ;
}
if(i==1){
newOrigin = origin.x + 30;
}
if(i==2){
newOrigin = origin.x + 150;
}
if(i==3){
newOrigin = origin.x + 270;
}
if(i==4){
newOrigin = origin.x + 480;
}
// newOrigin = origin.x + (columnWidth*i);
CGPoint from = CGPointMake(newOrigin, origin.y);
CGPoint to = CGPointMake(newOrigin, origin.y +(numberOfRows*rowHeight));
[self drawLineFromPoint:from toPoint:to];
}
}
-(void)drawLineFromPoint:(CGPoint)from toPoint:(CGPoint)to
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.2, 0.2, 0.2, 0.3};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, from.x, from.y);
CGContextAddLineToPoint(context, to.x, to.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
How about this tutorial. Exactly what you needed. Create the Table format
http://www.raywenderlich.com/6581/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-1
http://www.raywenderlich.com/6818/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-2

Drawing Text on UILabel with a gradient image

I have an UILabel subclass that draws some text in drawinRect method using a pattern image. This pattern image is a gradient image I am creating.
-(void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor colorWithPatternImage:[self gradientImage]];
[color set];
[someText drawInRect:rec withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:someAlignment];
}
The gradient image method is
-(UIImage *)gradientImage
{
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:#"myColor"];
UIColor *co = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
colors = [NSArray arrayWithObjects:co,co,[UIColor whiteColor],co,co,co,co,nil];
NSArray *gradientColors=colors;
CGFloat width;
CGFloat height;
CGSize textSize = [someText sizeWithFont:font];
width=textSize.width; height=textSize.height;
UIGraphicsBeginImageContext(CGSizeMake(width, height));
// get context
CGContextRef context = UIGraphicsGetCurrentContext();
// push context to make it current (need to do this manually because we are not drawing in a UIView)
UIGraphicsPushContext(context);
//draw gradient
CGGradientRef gradient;
CGColorSpaceRef rgbColorspace;
//set uniform distribution of color locations
size_t num_locations = [gradientColors count];
CGFloat locations[num_locations];
for (int k=0; k<num_locations; k++)
{
locations[k] = k / (CGFloat)(num_locations - 1); //we need the locations to start at 0.0 and end at 1.0, equaly filling the domain
}
//create c array from color array
CGFloat components[num_locations * 4];
for (int i=0; i<num_locations; i++)
{
UIColor *color = [gradientColors objectAtIndex:i];
NSAssert(color.canProvideRGBComponents, #"Color components could not be extracted from StyleLabel gradient colors.");
components[4*i+0] = color.red;
components[4*i+1] = color.green;
components[4*i+2] = color.blue;
components[4*i+3] = color.alpha;
}
rgbColorspace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(context, gradient, topCenter, midCenter, 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(rgbColorspace);
// pop context
UIGraphicsPopContext();
// get a UIImage from the image context
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
// clean up drawing environment
UIGraphicsEndImageContext();
return gradientImage;
}
Everything is working fine. The text is drawn with nice glossy effect. Now my problem is if I change the x or y position of the text inside the UILabel and then call the
[someText drawinRect:rec]... to redraw, the gloss effect is generated differently. It seems that the pattern image is changing with change of text position..
The following is the effect for the frame rec = CGRectMake(0, 10, self.frame.size.width, self.frame.size.height);
The following is the effect for the frame rec = CGRectMake(0, 40, self.frame.size.width, self.frame.size.height);
I hope I have explained my question well. Could not find any exact answer elsewhere. Thanks in advance.
You might want to look at using an existing 3rd party solution like FXLabel.

CGContext donesn't work correctly in thread

I'm trying to make infinite drawing in custom UIView from another thread using Core Graphics. It's impossible to obtain current CGContext so I try to create a new one. But I have no idea how to apply it to the view.
Here is the code I use in my custom view:
CG_INLINE CGContextRef CGContextCreate(CGSize size)
{
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(nil, size.width, size.height, 8, size.width * (CGColorSpaceGetNumberOfComponents(space) + 1), space, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(space);
return ctx;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = CGContextCreate(self.bounds.size);
if(context)
{
[self.layer renderInContext:context];
[self drawSymbolsInContext:context];
CGContextRelease(context);
}
}
- (void)drawSymbolsInContext:(CGContextRef)context
{
for (int x = 0; x<[cellsArray count];x++)
{
for(int y=0; y<[[cellsArray objectAtIndex:x] count]; y++)
{
NSLog(#"lol %d", y);
float white[] = {1.0, 1.0, 1.0, 1.0};
CGContextSetFillColor(context, white);
CGContextFillRect(context, [self bounds]);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSelectFont(context, "Times", 12.0, kCGEncodingMacRoman);
CGAffineTransform xform = CGAffineTransformMake(
1.0, 0.0,
0.0, -1.0,
0.0, 0.0);
CGContextSetTextMatrix(context, xform);
CGContextShowTextAtPoint(context, 100.0, 100.0 + 15*y, "test", strlen("test"));
}
}
}
Here is code I use to run thead(in ViewController):
- (void)viewDidLoad
{
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(SomeAction:) toTarget:self withObject:self.view];
}
- (void) SomeAction:(id)anObject
{
NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
DrawView *drawView = (DrawView *)anObject;
while (1)
{
COLOR col;
col.blue = 100;
col.red = 100;
col.green = 200;
int cellX = 0;
int cellY = [[rowsArray objectAtIndex:0] count];
CELL cel;
cel.x = cellX;
cel.x = cellY;
SymbolAlive *s = [[SymbolAlive alloc] initWithColor:col andFrame:cel];
[[rowsArray objectAtIndex:0] addObject:s];
[drawView drawRect:drawView.bounds];
[NSThread sleepForTimeInterval: 0.1];
}
[NSThread exit];
[autoreleasepool release];
}
Loop runs correctly. But nothing is displayed on the screen.
Any ideas?
I'm guessing you have to do your drawing on the main thread. Instead of
[drawView drawRect:drawView.bounds];
Do this
[self performSelectorOnMainThread:#selector(doDraw:) withObject:nil waitUntilDone:NO];
and then create a draw function like
- (void)doDraw:(id)notused
{
[drawView drawRect:drawView.bounds];
}
That will allow you to do the processing in the background but do the drawing on the main thread.
Also, you should be using the standard graphics context in this case.
One more comment, you can probably also move all your drawing-into-the-context into the background thread, but then call renderInContext on the main thread.

Resources