Is it possible to use UIGraphicsBeginImageContext from connectionDidFinishLoading? - iphone

I got these errors when the code below is executed:
[Switching to process 74682 thread 0x2003]
[Switching to process 74682 thread 0x207]
[Switching to process 74682 thread 0x720f]
--
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
UIImage = [[UIImage alloc] initWithData:self.resp_data;
CGSize itemSize = CGSizeMake(150);
UIGraphicsBeginImageContext(itemSize);
CGRect image_rect = CGRectMake(0.0,0.0,itemSize.width,itemSize.height);
[image drawInRect:image_rect];
self.image_view.image = UIGraphicsGetImageFromCurrentImageContext(); // image_view ivar is connected to a UIImageView in the View associated to this controller
self.resp_data = nil;
self.imageConnection = nil;
[image release];
}
Any idea what could be the issue and how to solve it ? (and of course the expected image does not show up)
Thx for helping,
Stephane

TESTED CODE:100% WORKS
#define kAppIconHeight 48
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.resp_data];
if (image.size.width != kAppIconHeight && image.size.height != kAppIconHeight)
{
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.image_view.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
else
{
self.image_view.image = image;
}
self.resp_data = nil;
[image release];
// Release the connection now that it's finished
//self.imageConnection = nil;
// call our delegate and tell it that our icon is ready for display
// [delegate appImageDidLoad:self.indexPathInTableView];
}

Related

Memory leak on reading images from document directory

I am reading images from document directory in a loop.
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
btnImage.frame = CGRectMake(xRow, yRow, width, height);
[btnImage addTarget:self action:#selector(imageDetails:) forControlEvents:UIControlEventTouchUpInside];
btnImage.tag = iCount;
if(iCount<[arrImages count])
{
NSString *workSpacePath=[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[arrImages objectAtIndex:iCount]];
[btnImage setBackgroundImage:[UIImage imageWithData:[NSData dataWithContentsOfFile:workSpacePath]] forState:UIControlStateNormal];
[scrollImages addSubview:btnImage];
}
}
On doing so, control goes to didRecieveMemoryWarning and application crashes. If I replace the image by a image from resource folder, application does not crashes. Why so?
The problem is that your buttons are maintaining a reference to the full resolution image. What you will need to do is scale down the image to your button dimensions and set that scaled down image as your button background. Something like this should do the trick:
Create a category on UIImage... Let's call it UIImage+Scaler.h
// UIImage+Scaler.h
#import <UIKit/UIKit.h>
#interface UIImage (Scaler)
- (UIImage*)scaleToSize:(CGSize)size;
#end
And the implementation:
// UIImage+Scaler.m
#import "UIImage+Scaler.h"
#define kBitsPerComponent 8
#define kBitmapInfo kCGImageAlphaPremultipliedLast
- (UIImage*)scaleToSize:(CGSize)size
{
CGBitmapInfo bitmapInfo = kBitmapInfo;
size_t bytesPerRow = size.width * 4.0;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, size.width,
size.height, kBitsPerComponent,
bytesPerRow, colorSpace, bitmapInfo);
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
CGContextDrawImage(context, rect, self.CGImage);
CGImageRef scaledImageRef = CGBitmapContextCreateImage(context);
UIImage* scaledImage = [UIImage imageWithCGImage:scaledImageRef];
CGImageRelease(scaledImageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return scaledImage;
}
OK, now back to your code. Like the other posters said you'll need an autorelease pool.
CGSize buttonSize = CGSizeMake(width, height);
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
btnImage.frame = CGRectMake(xRow, yRow, width, height);
[btnImage addTarget:self
action:#selector(imageDetails:)
forControlEvents:UIControlEventTouchUpInside];
btnImage.tag = iCount;
if(iCount<[arrImages count])
{
NSString *workSpacePath=[[self applicationDocumentsDirectory]
stringByAppendingPathComponent:
[arrImages objectAtIndex:iCount]];
UIImage* bigImage = [UIImage imageWithData:[NSData
dataWithContentsOfFile:workSpacePath]];
UIImage* smallImage = [bigImage scaleToSize:buttonSize];
[btnImage setBackgroundImage:smallImage forState:UIControlStateNormal];
[scrollImages addSubview:btnImage];
}
[pool drain]; // must drain pool inside loop to release bigImage
}
Hope this solves for problem.
Put your for loop in an autorelease pool:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(...)
{
....
}
[pool release];
Use NSAutoreleasePool. Keep your code inside an autoreleasepool.
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
......
......
[pool drain];
}

Taking a picture from the camera and show it in a UIImageView

I have a view with some fields (name, price, category) and a segmented control, plus this button to take picture.
If I try this on the simulator (no camera) it works properly: I can select the image from the camera roll, edit it and go back to the view, which will show all the fields with their contents .
But on my iphone, when I select the image after the editing and go back to the view, all the fields are empty exept for the UIImageView.I also tried to save the content of the fields in variables and put them back in the "viewWillApper" method, but the app crashes.
Start to thinking that maybe there is something wrong methods below
EDIT
I found the solution here. I defined a new method to the UIImage class. (follow the link for more information).Then I worked on the frame of the UIImageView to adapt itself to the new dimension, in landscape or portrait.
-(IBAction)takePhoto:(id)sender {
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {
self.imgPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
self.imgPicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
} else {
imgPicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
}
[self presentModalViewController:self.imgPicker animated:YES];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
NSDate *date = [NSDate date];
NSString *photoName = [dateFormatter stringFromDate:date];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUs erDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
imagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", photoName]];
UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];
// ---------RESIZE CODE--------- //
if (picture.size.width == 1936) {
picture = [picture scaleToSize:CGSizeMake(480.0f, 720.0f)];
} else {
picture = [picture scaleToSize:CGSizeMake(720.0f, 480.0f)];
}
// --------END RESIZE CODE-------- //
photoPreview.image = picture;
// ---------FRAME CODE--------- //
photoPreview.contentMode = UIViewContentModeScaleAspectFit;
CGRect frame = photoPreview.frame;
if (picture.size.width == 480) {
frame.size.width = 111.3;
frame.size.height =167;
} else {
frame.size.width = 167;
frame.size.height =111.3;
}
photoPreview.frame = frame;
// --------END FRAME CODE-------- //
NSData *webData = UIImagePNGRepresentation(picture);
CGImageRelease([picture CGImage]);
[webData writeToFile:imagePath atomically:YES];
imgPicker = nil;
}
Now I have a new issue! If I take a picture in landscape, and try to take another one in portrait, the app crashs. Do I have to release something?
I had the same issue, there is no edited image when using the camera, you must use the original image :
originalimage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];
if ([editingInfo objectForKey:UIImagePickerControllerMediaMetadata]) {
// test to chek that the camera was used
// especially I fund out htat you then have to rotate the photo
...
If it was cropped when usign the album you have to re-crop it of course :
if ([editingInfo objectForKey:UIImagePickerControllerCropRect] != nil) {
CGRect cropRect = [[editingInfo objectForKey:UIImagePickerControllerCropRect] CGRectValue];
CGImageRef imageRef = CGImageCreateWithImageInRect([originalimage CGImage], cropRect);
chosenimage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
} else {
chosenimage = originalimage;
}
The croprect info is also present for the camera mode, you need to check how you want it to behave.
To Crop image i think this may help you
UIImage *croppedImage = [self imageByCropping:photo.image toRect:tempview.frame];
CGSize size = CGSizeMake(croppedImage.size.height, croppedImage.size.width);
UIGraphicsBeginImageContext(size);
CGPoint pointImg1 = CGPointMake(0,0);
[croppedImage drawAtPoint:pointImg1 ];
[[UIImage imageNamed:appDelegete.strImage] drawInRect:CGRectMake(0,532, 150,80) ];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
croppedImage = result;
UIImageView *mainImageView = [[UIImageView alloc] initWithImage:croppedImage];
CGRect clippedRect = CGRectMake(0, 0, croppedImage.size.width, croppedImage.size.height);
CGFloat scaleFactor = 0.5;
UIGraphicsBeginImageContext(CGSizeMake(croppedImage.size.width * scaleFactor, croppedImage.size.height * scaleFactor));
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextClipToRect(currentContext, clippedRect);
//this will automatically scale any CGImage down/up to the required thumbnail side (length) when the CGImage gets drawn into the context on the next line of code
CGContextScaleCTM(currentContext, scaleFactor, scaleFactor);
[mainImageView.layer renderInContext:currentContext];
appDelegete.appphoto = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Why image is not showing up in UIImageView

I'm having issue with a simple code downloading a remote image and adding content to an UIImageView object through its 'image' property. Instead of showing the downloaded image, it shows an old picture. Any caching responsible ? I've reset anything and removed cache files but still don't understand why this old image is still showing.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
if (image.size.width != kAppIconHeight && image.size.height != kAppIconHeight)
{
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.image_view.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
else
{
self.image_view.image = image;
}
self.activeDownload = nil;
[image release];
// Release the connection now that it's finished
self.imageConnection = nil;
// call our delegate and tell it that our icon is ready for display
[delegate appImageDidLoad:self.indexPathInTableView];
}
Try to call [imageView setNeedsDisplay] after setting image property.

Image is rotated 90 degrees when using clipToMask

I am trying to clip a portion of an image I take with a camera. Here's my clipping code:
- (UIImage*) maskImage:(UIImage *)image {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
UIImage *maskImage = [UIImage imageNamed:#"mask3.png"];
CGImageRef maskImageRef = [maskImage CGImage];
// create a bitmap graphics context the size of the image
CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
if (mainViewContentContext==NULL)
return NULL;
CGFloat ratio = 0;
ratio = maskImage.size.width/ image.size.width;
if(ratio * image.size.height < maskImage.size.height) {
ratio = maskImage.size.height/ image.size.height;
}
CGRect rect1 = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
CGRect rect2 = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};
CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);
// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
UIImage *theImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);
// return the image
return theImage;
}
I am calling above method in my captureNow method in my viewcontroller. I am using AVFoundation to capture still image:
-(void) captureNow
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in stillImageOutput.connections)
{
for (AVCaptureInputPort *port in [connection inputPorts])
{
if ([[port mediaType] isEqual:AVMediaTypeVideo] )
{
videoConnection = connection;
break;
}
}
if (videoConnection) { break; }
}
NSLog(#"about to request a capture from: %#", stillImageOutput);
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[testImageView setImage:[self maskImage:image]];
self.firstPieceView.frame = CGRectMake(0, 0, 320, 480);
self.firstPieceView.contentMode = UIViewContentModeScaleAspectFill;
// self.firstPieceView.image = image;
// [firstPieceView setNeedsDisplay];
NSLog(#"self.firstPiece.frame is %#", NSStringFromCGRect(self.firstPieceView.frame));
// [myView becomeFirstResponder];
}];
self.previewParentView.hidden = YES;
self.photoBtn.hidden=YES;
self.imageMask.hidden = NO;
//add the gesture after taking the first image.
[myView addGestureRecognizersToPiece:self.myView];
}
For some reason, my image is always rotated 90 degrees when I clip it. Does anyone know why and how to fix this? Thanks in advance.
Here alternative solution to rotate image to 90 degrees ,its code is bellow...
yourImageView.transform = CGAffineTransformMakeRotation(3.14159265/2);
when you want to share or save the picture at that time just rotate the Image With 90 Degrees and also if Required then 180 degree....
this is alternate solution if i got any other Idea then i will post again...
hope,this help you...
:)

Should repeated use of the camera crash an app?

I have an app that builds a slideshow from user images. They can grab from their library or take a picture. I have found that repeated use of grabbing an image from the library is fine. But repeated use of taking a picture causes erratic behavior. I have been getting crashes but mostly what happens seems to be a reloading of the view after "didFinishPickingMediaWithInfo", which messes things up.
I have no leaks and it seems to be releasing properly after each picture is taken. I am resizing the image and saving it in a data base. Is anyone else running into this situation? Was the camera not designed to be called this often?
Sorry for the mix up. It's not continuos, it's take a picture, remove and release the camera, then the user selects choice A, B or C (they are prompted throughout to make selections on many things) then they can take another picture, remove and release the camera...etc...and this happens several times while they complete all the data entry.
After they select the camera I call this code. I am not releasing the image picker in the dealloc method.
- (void)openCamera {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
}
}
After they "USE" a picture taken from the camera I call the following code. It resized the image based on the original size of the image.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *tempCameraImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[picker dismissModalViewControllerAnimated:YES];
CGFloat originalSize = tempCameraImage.size.width * tempCameraImage.size.height;
NSLog(#"Original Size %f", originalSize);
if (originalSize > 2500000.0) {
CGSize size = tempCameraImage.size;
CGRect rect = CGRectMake(0.0, 0.0, .23 * size.width, .23 * size.height);
UIGraphicsBeginImageContext(rect.size);
[tempCameraImage drawInRect:rect];
theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGFloat totalSize = theImage.size.width * theImage.size.height;
NSLog(#"Final Camera Size %f", totalSize);
[self resizeImageCamera];
return;
}
else {
CGSize size = tempCameraImage.size;
CGRect rect = CGRectMake(0.0, 0.0, .27 * size.width, .27 * size.height);
UIGraphicsBeginImageContext(rect.size);
[tempCameraImage drawInRect:rect];
theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGFloat totalSize = theImage.size.width * theImage.size.height;
NSLog(#"Final Camera Size %f", totalSize);
[self resizeImageCamera];
return;
}
}
-(void)resizeImageCamera {
if (editingImage1) {
NSManagedObject *image = [NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:slideshow.managedObjectContext];
slideshow.image = image;
[image setValue:theImage forKey:#"image"];
CGSize size = theImage.size;
CGRect rect = CGRectMake(0.0, 0.0, .15 * size.width, .15 * size.height);
UIGraphicsBeginImageContext(rect.size);
[theImage drawInRect:rect];
slideshow.thumbnailImage1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self finishCameraImage];
return;
}
}
-(void)finishCameraImage {
if (editingImage1) {
keyInt = #"2";
[editedObject setValue:keyInt forKey:#"script1"];
pictureView.alpha = 0;
self.navigationItem.rightBarButtonItem = nil;
editedFieldKey = #"line2Int";
editedFieldName = NSLocalizedString(#"line2Int", #"display name for line2");
self.title = editedFieldName;
linePicker.hidden = NO;
}
I realize I am doing a lot to this image. If I put in a couple of delays would that help?