how to set a context to NSString drawAtPoint? - iphone

I currently working on encapsulation many [NSString drawAtPoint:withFont:] function calls to a method so that I could draw lots of strings by a single call, but how can I tell the method where to draw these strings?
What if I pass a CGContextRef to it, how to set a CGContextRef as current context?

On iOS 4 and later, wrap the NSString drawAtPoint calls with UIGraphicsPushContext(context) and UIGraphicsPopContext().
See accepted answer for "Using NSStrings drawAtPoint method in place of CGContextShowGlyphsAtPoint..."

Maybe you need this part of code:
CGContextRef context = UIGraphicsGetCurrentContext();

Related

issues with CGContextRef

I am working with drawing project, as we know to draw something we need to get call this function, UIGraphicsGetCurrentcontext, So I am also calling it wherever, I need it, either its clear, or erase . What I am doing is in every function, I am calling it this way
CGContextRef context = UIGraphicsGetCurentContext()
What I want to know, is whether I get the same context whenever I call this function? whether the pointer points to same context?
Because my eraser works in some cases and fails in some cases.
Below is my eraser function
- (void)erase
{
[m_curImage drawAtPoint:CGPointMake(0, 0)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
}
Regards
Ranjit
You can only use UIGraphicsGetCurentContext() inside of the drawRect method, outside of that it will not be configured with a valid context.
You have to create a custom view and write your erase() method code in the drawRect method.

Having trouble with releases in core graphics

I've just started with releasing in core graphics, so I might need a little help.
I have code which looks like this:
UIImage *buttonImage() {
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGMutablePathRef outerPath;
CGMutablePathRef midPath;
CGMutablePathRef innerPath;
CGMutablePathRef highlightPath;
//Some button stuff
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGContextRelease(context);
return image;
}
That release line, I've put in. I'm getting an error with it though:
context_reclaim: invalid context
context_finalize: invalid context
Any thoughts as to where i should put the release in this instance?
You only need to do CGContextRelease(context) if you have previously done a CFRetain(context) or a CGContextRetain(context), or if you created the context yourself. In your example, you are calling UIGraphicsBeginImageContextWithOptions(), which is handling the creation of the context for you, thus, calling CGContextRelease() yourself is over-releasing it.
You do need to balance the CGColorSpaceCreateDeviceRGB() with either a:
CGColorSpaceRelease(baseSpace)
or a :
if (baseSpace) CFRelease(baseSpace)
You don't own the context when using UIGraphicsGetCurrentContext. Therefore you should not be releasing it. If you were to use CGContextRetain() then you would release. More information of this is available here:
Memory Management Guide for Core Foundation
I highly suggest reading the Memory Management programming guide to get an understanding of how it works.

How to access CGContext for creating CGLayer offscreen

Intention: creating CGLayer offscreen, draw some complicated stuff on it from second thread and use it later for quick drawing on main thread
Problem: CGLayerCreateWithContext(context, size, info) expects an already existing CGContext so that it knows for what kind of context it needs to be optimized.
Solution I found so far: CGContextRef ctx = UIGraphicSetCurrentContext()
but this function doesn't seem to exist anymore.
Question: Isn't there another way to access something like a default context? Or do i really need to wait for the first drawRect: call just for accessing UIGraphicsGetCurrentContext() and creating all CGLayers from main thread with one wasted drawing run?
you can create an image context by doing something like:
UIGraphicsBeginImageContext(rect);
// your drawing code
UIGraphicsEndImageContext();
with that said, i'm not sure you can do this from a thread other than main. worth a try, though.

Using GCD/asynchronous code in drawRect:

I'm trying to load an image from a url inside of drawRect:. Our image-loading code is a method that looks like this: - (void) loadImage:(NSURL*)url done:(void(^)(UIImage*))done;, which creates an asynchronous NSURLConnection and calls back with the image.
So, my code in drawRect: looks like this:
CGContextRef context = UIGraphicsGetCurrentContext()
[service loadImage:url done:^(UIImage * image){
CGContextDrawImage(context, frame, image.CGImage);
}];
Unfortunately, this doesn't work. The image is never drawn.
I've also tried using synchronous connections ([NSData dataWithContentsOfUrl:]), but it blocks the thread and slows things down unnecessarily. I don't want to use a UIImageView.
What is the correct way to do this? Thanks!
I think the correct way would either be to load the image beforehand or draw the image as soon as you receive it by either calling "setNeedsDisplayInRect:" or doing your own drawing handling in a separate method (iOS might discourage you from doing this though, I am not sure). Obviously the setNeedsDisplayInRect variation would require you to have the image at hand for drawing the second time around (cache it).
If you load the image asynchronously your drawRect method will moste likely have exited before the image is loaded and the draw focus is no longer locked on your drawRect, thus making it impossible to draw the image in the context. Did you try to set a breakpoint to verify this though? I might be wrong about the locking, but thought I read something alike this at some point.
Think it through--why would it run? There's no guarantee that context is still the current context (or even that its backing store is still fully valid) by the time the block is entered. By using an asynchronous callback, be it a block or a delegate method or something else, you're intentionally deferring code to a later point in time. The call to -drawRect: has ended and is off the stack long before your block is entered.
The first thing I would try is to make sure the async handler runs on the main thread:
[service loadImage:url done:^(UIImage * image) {
dispatch_async(dispatch_get_main_queue(), ^{
CGContextDrawImage(context, frame, image.CGImage);
});
}];
If that does not help, I would start to wonder if the context is still valid. The pointer is, but the context probably not. Maybe you could move the context acquisition to the handler:
[service loadImage:url done:^(UIImage * image) {
dispatch_async(dispatch_get_main_queue(), ^{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, frame, image.CGImage);
…
});
}];
Not sure if that makes sense API-wise, I don’t do much stuff like this.
Have you tried:
__block CGContextRef context = UIGraphicsGetCurrentContext()
[service loadImage:url done:^(UIImage * image){
CGContextDrawImage(context, frame, image.CGImage);
}];
You may have to do the same thing with frame, so when the block returns it knows what context and frame it should modify.

Most efficent way to create a CALayer with an image in it?

I am wondering what the most efficient way is to make a CALayer with an image in it.
I know you can load a UIImage and then call [image CGImage] but is this the best way of going about it? As far as I can tell from Apple's documentation this is the only way you can do it.
Try this:
layer.contents = (__bridge id)[ uiimage CGImage ] ;
HTH
Well, a CGImage isn't a CALayer, so you are obviously leaving some steps out there, but I assume you know what you're talking about, as far as drawing to a CALayer or whatnot.
If your question is about creating CGImages without using a UIImage, you can try looking into the following functions:
CGImageCreateWithJPEGDataProvider
CGImageCreateWithPNGDataProvider
If you happen to know beforehand what sort of image it is, just use the appropriate method. Otherwise, you'd need to look at the file signature to see if it contains PNG or JFIF. Of course, this requires you implement a CGDataProvider.
I assume this is exactly what the UIImage class is already doing. If you want to squeeze out every bit of efficiency from that, you can use one of the following methods in the UIImage class:
+ (UIImage *)imageWithContentsOfFile:(NSString *)path
+ (UIImage *)imageWithData:(NSData *)data
The only difference between these methods and
+ (UIImage *)imageNamed:(NSString *)name
is that imageNamed: caches the image. If you use one of the first methods, it does not.