Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

robbieduncan

Moderator emeritus
Original poster
Jul 24, 2002
25,611
893
Harrogate
In my apps I draw some custom graphics in-app. These images are drawn into CGContexts then retrieved as UIImages from the context.

Before iPhone 4 life was simple. I simply did something like this:
Code:
UIGraphicsBeginImageContext(size);
CGContextRef c = UIGraphicsGetCurrentContext();
// Do some drawing
UIImage *toReturn = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return toReturn

The problem with this is that it draws at equivalent display resolution, rather than the hardware resolution of the device. So on the iPhone 4 it all looks a bit blocky/pixelated.

The solution is relatively simply. Change the first line to
Code:
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);

This works beautifully. My images are now rendered at the correct resolution and everything looks great. The problem is that UIGraphicsBeginImageContextWithOptions was only added in iOS 4.0. I have set my iPhone OS Deployment Target build variable to 3.0 and I don't get any errors/warnings about using this function but that doesn't seem to cover it: on an iOS 3.x device this function will not exist.

So the question is do I need have some sort of conditional to handle this? Week link the references to the function so as the code loads on 3.x without linker errors? Any insight appreciated :)
 
To reply to my own question! Apple's documentation tells me that the SDK settings will cause the additional symbols to be weak linked. So changing the line as I described above would still allow the code to load, but it would not work correctly on an iOS <4.0 device.

Changing the code to this should make it work on either:

Code:
if (UIGraphicsBeginImageContextWithOptions!=NULL)
{
	UIGraphicsBeginImageContextWithOptions(size,NO,0.0); 
}
else 
{
	UIGraphicsBeginImageContext(size);
}
 
I have similar code with the same solution.

Curiously I also have code that uses UIKeyboardFrameEndUserInfoKey, which is a string. I need to check for it like this

Code:
BOOL     hasKeyboardFrameEndUserInfoKey = NULL != &UIKeyboardFrameEndUserInfoKey;
which is slightly different. Without the & this crashes on an OS without that symbol.
 
The apple page you linked says

If a weakly linked symbol is not available in a framework, the linker sets the address of the symbol to NULL.

A symbol has an address and a value. For a function pointer it really only has an address. Its value is its address. For a variable it does really have both an address and a value. But if the address is NULL then asking for the value is a null dereference.

The C-language syntax for function pointers is the difference here.

Code:
if (MyWeakLinkedFunction != NULL)

is the same as

Code:
if (&MyWeakLinkedFunction != NULL)

But

Code:
if (MyWeakLinkedVariable != NULL)  // checks value

is not the same as

Code:
if (&MyWeakLinkedVariable != NULL) // checks address

The apple docs should explain this but don't.
 
// Do some drawing

Will you please help me with the //do some drawing part? Before iPhone 4, I drew like this:

Code:
- (void) displaySubview:(CGRect)rect
{
	CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipLast;
	CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
	size_t components = 4;
	size_t bitsPerComponent = 8;
	size_t dotsPerRow = rect.size.width;
	size_t numRows = rect.size.height;
	size_t bytesPerRow = dotsPerRow * components;
	
	CGContextRef bimage 
	= CGBitmapContextCreate(colorSet, dotsPerRow, numRows, bitsPerComponent, 
							bytesPerRow, colorspace, alphaInfo);
	CGColorSpaceRelease(colorspace);
	
	CGImageRef image = CGBitmapContextCreateImage(bimage);
	CGContextRelease(bimage);
	
	UIImage *myImage = [UIImage imageWithCGImage:image];
	UIImageView *uiv = [[UIImageView alloc] initWithImage:myImage];
	CGImageRelease(image);
	
	[self addSubview:uiv];
	[uiv release];
}

where colorSet is my RGBA set of bytes.
With the new
Code:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(pointsAcross, pointsDown), NO, 0.0);

How do I get my colorSet into a CGImageRef or UIImage?
Am I right to use points instead of pixels?
And these points should reflect the screen resolution right?

Regards,
Dan
 
Dan,

I changed my code from using a bitmap context to use UIGraphicsBeginImageContextWithOptions/UIGraphicsBeginImageContext but all my drawing is UIString drawing or core graphics calls. I couldn't figure out how to set the scale on the bitmap context and it was simple for me to convert the existing code to use UIGraphicsBeginImageContext, so I went that way.

In your case you have bitmap data that comes from "somewhere else" that you're drawing into an image context. How you should go depends on how you get that bitmap data. If it's at all possible to use UIGraphicsBeginImageContextWithOptions and draw into that context then you should do that. If not then maybe you should use the code that you've got but then draw the resulting image into a context created with UIGraphicsBeginImageContextWithOptions. You might need to double the size of your bitmap context to get the correct scale. I haven't tried this at all.
 
Thank you for your replies.
My RGBA data is generated by the program. So it's getting the RGBA byte set into a context that is my sticking point.

Dan
 
From the documentation:


For bitmaps created in iPhone OS 3.2 and later, the drawing environment uses the premultiplied ARGB format to store the bitmap data. If the opaque parameter is YES, the bitmap’s alpha channel is ignored.
For bitmaps created in iPhone OS 3.1.x and earlier, the drawing environment uses the premultiplied RGBA format to store the bitmap data.


Sounds like that may effect you.
 
That's for the context created with UIGraphicsBeginImageContextWithOptions, which has its own defaults. I assume that doesn't apply to bitmaps created with CGBitmapCreate, where you specify the format.

I think that Dan needs to just use the code he has on OS 4. Maybe check the scale value of UIView and make the bitmap twice as big if on a device with a scale factor of 2.0.

Sounds like that may effect you.

Or affect you, as the case may be.
 
That's for the context created with UIGraphicsBeginImageContextWithOptions, which has its own defaults. I assume that doesn't apply to bitmaps created with CGBitmapCreate, where you specify the format.

I think that Dan needs to just use the code he has on OS 4. Maybe check the scale value of UIView and make the bitmap twice as big if on a device with a scale factor of 2.0.

Yes. That's what I ended up doing. I found a way to make the program work with my current bitmap code.

I'm working on my Mandelbrot set (Mbrot7) and I use the screenscale to calculate points (not pixels) and I color the points.
I found that it works when I initWithFrame the UIScrollViews using the low res frame sizes. I also found that the tapPoint returned from locationInView comes in low res coordinates.

These may not be the correct approaches. The WWDC session on high res (134) does not address these issues.

Dan
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.