UIGraphicsGetImageFromCurrentImageContext() retain cause crash - objective-c

This is a weird one, but I think I'm just missing something simple.
I have an Objective C class called Theme.
Themes load all the art for my game from files and stores them in a NSMutableArray.
When the app launches it reates a new Theme object.
Part of the loading process does something like this:
UIImage *image = [self mergeImage: bg toImage: overlay];
[imageArray addObject: image];
I take a background image and place the overlay on top of it, creating a new UIImage, by using this code:
- (UIImage *)mergeImage:(UIImage *)image1 toImage:(UIImage *)image2 {
UIGraphicsBeginImageContext(image1.size);
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
[image2 drawInRect:CGRectMake(0, 0, image2.size.width, image2.size.height)];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
//[resultingImage retain];
UIGraphicsEndImageContext();
return resultingImage;
}
All of this happens in the init function of Theme.
Here's the problem, when I call [[Theme alloc] init] from
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
The app crashes a second later, leaving me with no stack or anything(I figure it screws up some memory and crashes later when it uses it again or something).
Here's the weird part. If I don't add the newly merged image to the imageArray, it never crashes. I don't have the image anymore, but there's no crash. Also, if I don't add the image to the array, but I retain it in the mergeImage function, it does crash, which makes me think that retaining this newly-made image is causing the problem.
Weirder still, if I don't call mergeImage until later on in the app, outside of teh [Theme init] and didFinishLaunchingWithOptions, it's OK.
Any idea why? What's wrong with retaining this image when the app first launches?

Try this Below Code:
UIGraphicsBeginImageContext(drawImage.bounds.size);
[drawImage.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage
Thanks..!

Related

Can't get a screenshot of UIView to be displayed inside UIImageView

Here's my code to get the screenshot of the view:
if (NULL != UIGraphicsBeginImageContextWithOptions){
UIGraphicsBeginImageContextWithOptions(pagedScrollView.frame.size, NO, [[UIScreen mainScreen] scale]);
}else{
UIGraphicsBeginImageContext(pagedScrollView.frame.size);
}
[pagedScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:screenshotImage];
imageView.frame = CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height);
imageView.backgroundColor = [UIColor greenColor];
[self.view addSubview:imageView];
I'm 100% sure I have the right frame and the right view - the size of UIImageView say about it - but the thing is I can't get my UIImage to be displayed on the UIImageView.
The UIImageView is added on the view and I see a green region on it - but no image inside it, what can be wrong?
I'm using iOS 6 and ARC.
Well, I just tested your code running on my view controller's view and the capture and display worked fine. This leads me to believe that pagedScrollView is probably nil, or has a zero frame.
Either way, you'll be creating an image from a blank context and then passing it to your image view resulting in there not being any visible image.
It turns out I've been taking a screenshot of a long UIScrollView and I was always taking its first page - it had a lot of pages in it and sometimes the layer had nothing in it. It also turns out that UIImage was never released and the memory can effectively store dozens of them.

Objective C - UIImage resizing not working

I have a program that fetches an image from the library, but I'm using code I found online to resize that image so that it can fit on the screen (basically making it 640x960), but then it would still be too big to display, so in another UIImage I'm copying the first resized image and re-resizing this one to make it about 1/4 of the screen (or 160x240). The code is this:
for ViewController.h:
UIImage *img;
UIImage *thumb;
-(UIImage*) scaleImage: (UIImage*)image toSize:(CGSize)newSize;
(this of course, is only the code related to my problem)
for ViewController.m
-(UIImage*) scaleImage: (UIImage*)image toSize:(CGSize)newSize {
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
and in the same m file on another function, the scaleImage function is called when pressing a button with these lines:
[self scaleImage:img toSize:CGSizeMake(640, 960)];
thumb = img;
[self scaleImage:thumb toSize:CGSizeMake(160, 240)];
In the project I've previously been able to successfully provide an image for img using [info objectForKey:UIImagePickerControllerOriginalImage]; which would be the image chosen from the library. I've already "file owned" everything so that this function takes place (and it does because I create an UIAlert within it and it shows, and a NSLog to print out when scaleImage starts and it does, twice), but the image is never re-sized!! Does anyone know why?? Please let me know, thank you for anyone who comments with help or suggestions!!
Your scaleImage method returns the scaled image, for example
thumb = [self scaleImage:img toSize:CGSizeMake(640, 960)];

Add a background image to TTWebController's UIToolbar

I would like to add a nice background image to the UIToolbar of a subclass of Three20's TTWebController.
Since I don't mind all UIToolbars of my app sharing the same background, I tried using UIColor colorWithPatternImage in my style sheet and that doesn't seem to work (toolbar end up solid black).
I've also tried doing something like this:
#implementation UIToolbar (MyCustomToolbarBG)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: kBackgroundImage];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
with little success..
I certainely don't want to copy and paste the entire TTWebController code just to make my own class out of it since I actually don't modify anything else, but I don't really see anything else I can do. Anyone have a suggestion?
Ok, found my way like this: I subclassed the TTWebController to subclass the loadView: method.
-(void)loadView{
[super loadView];
[_toolbar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed: kBackgroundImage]] autorelease] atIndex:0];
}
Better than nothing. Not extremely handy if they decide to change anything about the protected attribute _toolbar though...

Can't draw UImage in UIView::drawRect

I know this seems like a simple task, which is why I don't understand why I can't get the image to render.
When I set up my UIView, I do the following:
myUiView.backgroundColor = [UIColor clearColor];
myUiView.opaque = NO;
I create and retain the UIImage in the init function of my UIView:
image = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"test" ofType:#"png"]] retain];
then my drawRect looks like this:
- (void) drawRect:(CGRect) rect
{
[image drawInRect:self.bounds];
}
Ultimately I'll be manipulating that UIImage via bitmap context, and then in drawRect create a CGImage out of the context, and render that, but for now I'm just trying to get it rendering a known image.
I've been digging through this site, as well as the documentation. I've gone down the CG path and tried drawing it with CGContextDrawImage by following the numerous examples other people have posted, but that didn't work either.
So I've come back to what seems to be the most straightforward way to draw an image, but it isn't working.
Any help would be greatly appreciated.
Thanks in advance.
First of all, verify that the size and position of self.bounds are what you want them to be. If the size is {0,0} nothing will display. Check using this function:
NSLog(#"%#", NSStringFromCGRect(self.bounds));
Also make sure that the image is not nil:
NSLog(#"%#", image);

imageWithCGImage and memory

If I use [UIImage imageWithCGImage:], passing in a CGImageRef, do I then release the CGImageRef or does UIImage take care of this itself when it is deallocated?
The documentation isn't entirely clear. It says "This method does not cache the image object."
Originally I called CGImageRelease on the CGImageRef after passing it to imageWithCGImage:, but that caused a malloc_error_break warning in the Simulator claiming a double-free was occurring.
According to the fundamental rule of Cocoa memory management, an owning object should release the owned object when it no longer needs it. Other objects are responsible for taking and releasing ownership on their own. If a UIImage needs an object to persist but doesn't retain or copy it, it's a bug in UIImage's implementation and should be reported as such.
I have the same problem in XCode 3.2.1 on Snow Leopard. I have pretty much the same code as Jason.
I have looked at the iPhone sample code which uses imageWithCGImage and they always release the CGImageRef using CGImageRelease after a call to imageWithCGImage.
So, is this a bug in the simulator? I always get the malloc_error_break warning on the console when I use CGImageRelease.
The ownership in UIImage about CGImage is unclear. It seems like don't copy the CGImage but it's not guaranteed by documentation. So we have to handle that ourselves.
I used a new subclass of UIImage to handle this problem. Just retaining passing CGImage, and releasing it when the dealloc.
Here is sample.
#interface EonilImage : UIImage
{
#private
CGImageRef sourceImage;
}
- (id)initWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation;
#end
#implementation EonilImage
- (id)initWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
{
self = [super initWithCGImage:imageRef scale:scale orientation:orientation];
if (self)
{
sourceImage = imageRef;
CGImageRetain(imageRef);
}
return self;
}
- (void)dealloc
{
CGImageRelease(sourceImage);
[super dealloc];
}
#end
Because the CGImage returned by -[UIImage CGImage] property is not guaranteed to be same CGImage passed into init method, the class stores CGImage separately.
I agree with you -- the documentation is muddled at best for this API. Based on your experiences, then, I would conclude that you are responsible for the lifetime of both objects - the UIImage and the CGImageRef. On top of that you have to make sure the lifetime of the CGImageRef is at least as long as the UIImage (for obvious reasons).
Are you using Xcode 3.1 on Snow Leopard? I am experiencing the same issue:
CGContextRef ctx = ...;
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
UIImage * newImage = [[UIImage imageWithCGImage:cgImage] retain];
CGImageRelease(cgImage); // this should be OK, but it now crashes in Simulator on SL
I'm guessing that upgrading to Xcode 3.2 will fix the issue.
Not sure if this helps, but I had a similar problem.
I read the answers and then did the following which appears to have fixed it:
CGImageRef cgImage = [asset thumbnail];
UIImage *thumbImage = [[UIImage imageWithCGImage:cgImage ]retain];
UIImageView *thumbImageView = [[UIImageView alloc] initWithImage:thumbImage];
CGImageRelease(cgImage);
I used the autorelease as suggested but it was not enough.
One I had added the image to the UIImageView I then released the cgImage.
It didn't crash and deallocated nicely. Why -- I have no idea but it worked.
The asset thumbnail part is from the ALAsset Library by the way, you might need something else there.
<>
Not my opinion. I had the same problem. According to documentation
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
imho keeps all references correct. If you are using a CGDataProvider please have a look at
CGDataProviderReleaseDataCallback
and set a breakpoint in your callback. You can see that is is correctly called after you [release] your image and you can free() your image data buffer there.
"This method does not cache the image object."
So the UIImage take the ownership, and thus you should not release the CGImageRef.