my colour bitmap is only black and white in drawRect (iPhone) - iphone

I want to preserve previous drawing in drawRect (the system clears it down each time) and it seems that the way to go is to use a bitmap context and sure enough, this works except that now my colour is gone leaving only black and white instead.
Here is my "static" context
-(id)initWithCoder:(NSCoder *)aDecoder {
...
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
contextRef = CGBitmapContextCreate(NULL,
320,
640,
8,
320*4,
colorSpace,
kCGImageAlphaPremultipliedLast);
...
}
and here is my replacement context:
-(void)drawRect:(CGRect)rect {
myDrawRoutine();
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, rect, CGBitmapContextCreateImage(contextRef));
}
And this is the draw routine's guts:
...
// CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRef context = contextRef;
if( !(context) )
return;
CGContextSetFillColor(context, CGColorGetComponents([co CGColor]));
CGContextSetStrokeColor(context, CGColorGetComponents([co CGColor]));
CGContextFillEllipseInRect(context, CGRectMake((*i)->x,
(*i)->y,
(*i)->diam,
(*i)->diam));
...
}

Thanks tonclon
That has made a hell of an increase in speed :)
But it still draws in black and white :(
Here is the above code + modifications...
Here is my "static context":
-(id)initWithCoder:(NSCoder *)aDecoder {
...
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
contextRef = CGBitmapContextCreate(NULL,
320,
640,
8,
320*4,
colorSpace,
kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
cglayer = CGLayerCreateWithContext(contextRef, CGSizeMake(320.0f, 640.0f), NULL);
contextRef = CGLayerGetContext(cglayer);
...
}
and here is my "replacement context" i.e. the cglayer is used instead (the context is no longer replaced).
-(void)drawRect:(CGRect)rect {
for(std::vector<Body*>::iterator i = bodyVec.begin(); i < bodyVec.end(); ++i)
move(i);
CGContextRef context = UIGraphicsGetCurrentContext();
// CGContextDrawImage(context, rect, CGBitmapContextCreateImage(contextRef));
CGContextDrawLayerInRect(context, rect, cglayer);
}
(The "draw routine's guts" remain the same.)

At last! Thanks to this thread
Extracting rgb from UIColor
I got the answer - use CGContextSetRGBFillColor instead and then feed it with the RGB from CGColorGetComponents indirectly.
CGColorRef color = [co CGColor];
int numComponents = CGColorGetNumberOfComponents(color);
CGFloat red;
CGFloat green;
CGFloat blue;
CGFloat alpha;
if (numComponents == 4)
{
const CGFloat *components = CGColorGetComponents(color);
red = components[0];
green = components[1];
blue = components[2];
alpha = components[3];
}
// CGContextSetFillColor(context, CGColorGetComponents([co CGColor]));
// CGContextSetStrokeColor(context, CGColorGetComponents([co CGColor]));
CGContextSetRGBFillColor(context, red, green, blue, alpha);
CGContextSetRGBStrokeColor(context, red, green, blue, alpha);
CGContextFillEllipseInRect(context, CGRectMake((*i)->x,
(*i)->y,
(*i)->diam,
(*i)->diam));
}

Related

CGContextShowTextAtPoint producing non-Retina output on Retina device

I'm trying to add a text to an UIImage and I'm getting a pixelated drawing.
I have tried some other answers with no success:
Drawing on the retina display using CoreGraphics - Image pixelated
Retina display core graphics font quality
Drawing with Core Graphics looks chunky on Retina display
My code:
-(UIImage *)addText:(UIImage *)imgV text:(NSString *)text1
{
int w = self.frame.size.width * 2;
int h = self.frame.size.height * 2;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate
(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), imgV.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSelectFont(context, "Arial", 24, kCGEncodingMacRoman);
// Adjust text;
CGContextSetTextDrawingMode(context, kCGTextInvisible);
CGContextShowTextAtPoint(context, 0, 0, text, strlen(text));
CGPoint pt = CGContextGetTextPosition(context);
float posx = (w/2 - pt.x)/2.0;
float posy = 54.0;
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 255, 255, 255, 1.0);
CGContextShowTextAtPoint(context, posx, posy, text, strlen(text));
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}
Like Peter said, use UIGraphicsBeginImageContextWithOptions. You might want to pass image.scale to the scale attribute (where image.scale is the scale of one of the images you're drawing), or simply use [UIScreen mainScreen].scale.
This code can be made simpler overall. Try something like:
// Create the image context
UIGraphicsBeginImageContextWithOptions(_baseImage.size, NO, _baseImage.scale);
// Draw the image
CGRect rect = CGRectMake(0, 0, _baseImage.size.width, _baseImage.size.height);
[_baseImage drawInRect:rect];
// Get a vertically centered rect for the text drawing
rect.origin.y = (rect.size.height - FONT_SIZE) / 2 - 2;
rect = CGRectIntegral(rect);
rect.size.height = FONT_SIZE;
// Draw the text
UIFont *font = [UIFont boldSystemFontOfSize:FONT_SIZE];
[[UIColor whiteColor] set];
[text drawInRect:rect withFont:font lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentCenter];
// Get and return the new image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
Where text is an NSString object.
I was facing the exact same problem and posted a question last night to which no-one replied. I have combined fnf's suggested changes with Clif Viegas's answer in the following question:
CGContextDrawImage draws image upside down when passed UIImage.CGImage
to come up with the solution. My addText method is slightly different from yours:
+(UIImage *)addTextToImage:(UIImage *)img text:(NSString *)text1{
int w = img.size.width;
int h = img.size.height;
CGSize size = CGSizeMake(w, h);
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(size);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0,h);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];// \"05/05/09\";
CGContextSelectFont(context, "Times New Roman", 14, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
//rotate text
CGContextSetTextMatrix(context, CGAffineTransformMakeRotation( -M_PI/8 ));
CGContextShowTextAtPoint(context, 70, 88, text, strlen(text));
CGColorSpaceRelease(colorSpace);
UIGraphicsEndImageContext();
return newImg;
}
In summary, what I have done is add
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(size);
}
Remove
// CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
and put
CGContextRef context = UIGraphicsGetCurrentContext();
instead. But this causes the image to be upside down. Hence I put
CGContextTranslateCTM(context, 0,h);
CGContextScaleCTM(context, 1.0, -1.0);
just before
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
This way you can use CG functions instead of using drawInRect etc.
Don't forget
UIGraphicsEndImageContext
at the end. Hope this helps.

How to change size of CGContextRef

How can I increase size of CGContextRef after its creation.
if(UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0);
}
else {
UIGraphicsBeginImageContext(CGSizeMake(width, height));
}
CGContextRef ctr = UIGraphicsGetCurrentContext();
Can i change size of ctr?
Try doing it without the if-else conditions. Create a CGContext using that last line of code only.
Here's a simple example
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 100,100);
CGContextAddLineToPoint(context, 200, 200);
CGContextStrokePath(context);
}

Draw line between two different point

I want to draw line between two points. Here is my code. but context memory is 0.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 300, 400);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
You need to call your code within a UIView subclass in the method drawRect:.
UIGraphicsGetCurrentContext() will get NULL (0) when your are not in a drawing context.
You might also check the docs.
Here is a very useful tutorial for your need.
http://trailsinthesand.com/exploring-iphone-graphics-part-1/
Go through it once..!

iPhone App - Why do my CGContext circles look like black squares?

What is wrong with this drawRect method in my iPhone app custom UIView class? It's supposed to draw a colored circle, however it draws a black square of proper width and height.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
UIColor *c = [UIColor redColor];
const CGFloat *components = CGColorGetComponents([c CGColor]);
CGFloat red = components[0];
CGFloat green = components[1];
CGFloat blue = components[2];
CGFloat al = components[3];
CGContextSetRGBFillColor(context, red, green, blue, al);
CGContextFillEllipseInRect(context, CGRectMake(x, y, width, width));
}
Try this:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, CGRectMake(x, y, width, width));
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor redColor] CGColor]));
CGContextFillPath(ctx);
}
Hope this works fine.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetFillColorWithColor(context , [UIColor redColor].CGColor;
CGContextFillEllipseInRect(context, CGRectMake(x, y, width, width));
}

Issue with Transparency

We have an issue with transparency. While writing an image to Context with gradient, transparency (which is unwanted) is getting applied. We are not sure why this has been getting applied. We need the context to be "ONLY" with Gradient but not with "TRANSPARENCY".
Attaching the snippet of the code for your reference.
- (UIImage *)ReflectImage:(CGFloat)refFract {
int reflectionHeight = self.size.height * refFract;
CGImageRef gradientMaskImage = NULL;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef gradientBitmapContext = CGBitmapContextCreate(nil, 1, reflectionHeight,
8, 0, colorSpace, kCGImageAlphaNone);
CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
CGColorSpaceRelease(colorSpace);
CGPoint gradientStartPoint = CGPointMake(0, reflectionHeight);
CGPoint gradientEndPoint = CGPointZero;
CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(grayScaleGradient);
CGContextSetGrayFillColor(gradientBitmapContext, 0.0, 0.5);
CGContextFillRect(gradientBitmapContext, CGRectMake(0, 0, 1, reflectionHeight));
gradientMaskImage = CGBitmapContextCreateImage(gradientBitmapContext);
CGContextRelease(gradientBitmapContext);
CGImageRef reflectionImage = CGImageCreateWithMask(self.CGImage, gradientMaskImage);
CGImageRelease(gradientMaskImage);
CGSize size = CGSizeMake(self.size.width, self.size.height + reflectionHeight);
UIGraphicsBeginImageContext(size);
[self drawAtPoint:CGPointZero];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, self.size.height, self.size.width, reflectionHeight), reflectionImage);
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(reflectionImage);
return result;
}
So, can someone please let me know why this is so? It would be of great help if this issue gets resolved.
Thanks!!
I didn't try running any of this, but you do seem to be passing an alpha value to CGContextSetGrayFillColor.
Also, the use of "device gray" has been generally discouraged. You might want to double check to make sure that the color space you're getting back has the same number of components as you expect it to.