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?
Related
I am developing an app in which I have to stitch multiple images one by one when ever the user takes picture from camera.
This is what I am using to merge two images.
[self performSelector:#selector(joinImages:secondImage:) withObject:firstimage withObject:imageCaptured];
- (UIImage *)joinImages:(UIImage *)im1 secondImage:(UIImage *)im2
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Joins 2 UIImages together, stitching them horizontally
CGSize size = CGSizeMake(im1.size.width+im2.size.width, im2.size.height);
UIGraphicsBeginImageContext(size);
CGPoint image1Point = CGPointMake(0, 0);
[im1 drawAtPoint:image1Point];
CGPoint image2Point = CGPointMake(im1.size.width,0);
[im2 drawAtPoint:image2Point];
UIImage* finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
firstimage=finalImage;// final images updated everytime
[pool release];
return finalImage;
}
But I receive memory warning when I run this in iPhone and it works fine for iPod.
Also images are cropped in case of iPhone.
Anything I can do to resolve this problem.
Thanks..
You could do something like this.
- (UIImage *)joinImages:(UIImage *)im1 secondImage:(UIImage *)im2
{
#autoreleasepool
{
//Joins 2 UIImages together, stitching them horizontally
CGSize size = CGSizeMake(im1.size.width+im2.size.width, im2.size.height);
UIGraphicsBeginImageContext(size);
CGPoint image1Point = CGPointMake(0, 0);
[im1 drawAtPoint:image1Point];
CGPoint image2Point = CGPointMake(im1.size.width,0);
[im2 drawAtPoint:image2Point];
UIImage* finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
firstimage=finalImage;// final images updated everytime
return finalImage;
}
}
Hope this will work for you.
[self joinImages:firstimage secondImage:secondImage];
- (UIImage *)joinImages:(UIImage *)im1 secondImage:(UIImage *)im2
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Joins 2 UIImages together, stitching them horizontally
CGSize size = CGSizeMake(im1.size.width+im2.size.width, im2.size.height);
UIGraphicsBeginImageContext(size);
CGPoint image1Point = CGPointMake(0, 0);
[im1 drawAtPoint:image1Point];
CGPoint image2Point = CGPointMake(im1.size.width,0);
[im2 drawAtPoint:image2Point];
UIImage* finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
firstimage=finalImage;// final images updated everytime
[pool release];
return finalImage;
}
I wonder, how could I display UIProgressView in this case:
I do photo with UIImagePickerController then in method - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
I save the picture to UIImage object (outputImage) and hide controller, and when modalView/controller with camera is disappeared I have such code:
NSLog(#"Image is width: %f height: %f", outputImage.size.width, outputImage.size.height);
//FLIP PICTURE FROM FACETIME CAMERA
if((outputImage.size.width == 480 && outputImage.size.height == 640) || (outputImage.size.width == 640 && outputImage.size.height == 480)) {
outputImage = [UIImage imageWithCGImage:outputImage.CGImage
scale:1.0 orientation: UIImageOrientationLeftMirrored];}
//RESIZE TO 1000x1000
outputImage = [self scaleAndCropToSize:outputImage toSize:CGSizeMake(1000, 1000)];
NSLog(#"Now image is width: %f height: %f", outputImage.size.width, outputImage.size.height);
//CUTING OUT TO MASK
outputImage = [self maskImage:outputImage withMask:[UIImage imageNamed:#"mask.png"]];
//ADDING SHADOW
CGSize size = CGSizeMake(1000, 1000);
UIGraphicsBeginImageContext(size);
CGPoint thumbPoint = CGPointMake(0, 0);
[outputImage drawAtPoint:thumbPoint];
UIImage* shadow = [UIImage imageNamed:#"shadow.png"];
CGPoint starredPoint = CGPointMake(0, 0);
[shadow drawAtPoint:starredPoint];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
outputImage = result;
//ADDING TO UIIMAGEVIEW (PREVIEW)
preview.image = outputImage;
While photo is being put into UIImageView, it takes some time. In this time I'd like to display progress view. How can I do that?
EDIT: I thought to place above code in some method and then somehow implement progressview, that would base on method completion time. But dunno.
You can not use UIProgressView as its difficult to know how much time it will take to perform image operations.
you can try this MBProgressHUD
Put this code in didFinishPickingMediaWithInfo
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.labelText = #"Saving Image...";
[self.view addSubview:HUD];
HUD.delegate = self;
[HUD showWhileExecuting:#selector(savingPicture:) onTarget:self withObject:selectedImage animated:YES];
and put your resize/crop image operations code in savingPicture method.
Progress views are more appropriate when you are running a loop and you know what percentage of the work is being completed, to show the progress in the progress bar. In this case you can show a UIActivityIndicator instead, until your image is ready to be put on the image view.
I am developing an Application where I am capturing image in portrait mode and then moving to another class with Image data and showing that image in a UIImageView on a UIScrollView.
Now If I am taking image form library,it is working fine, but If I have to capture an Image it is showing data in landscape mode. Below is my code of both classes. :
Class 1:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSData *imgData = UIImagePNGRepresentation([info objectForKey:#"UIImagePickerControllerOriginalImage"]);
[picker dismissModalViewControllerAnimated:YES];
image = [[UIImage alloc] initWithData:imgData];
CGImageRef imgRefCrop = image.CGImage;
UIImage *photo = [UIImage imageWithCGImage:imgRefCrop];
PhotoCropperPage *photoCropper = [[PhotoCropperPage alloc]
initWithPhoto:photo
delegate:self
uiMode:PCPUIModePresentedAsModalViewController
showsInfoButton:YES];
[photoCropper setMinZoomScale:0.3f];
[photoCropper setMaxZoomScale:4.0f];
[self.navigationController pushViewController:photoCropper animated:YES];
}
Class 2:
- (void) loadPhoto
{
if (self.photo == nil) {
return;
}
CGFloat w = self.photo.size.width;
CGFloat h = self.photo.size.height;
CGRect imageViewFrame = CGRectMake(0.0f, 0.0f, roundf(w / 2.0f), roundf(h / 2.0f));
self.scrollView.contentSize = imageViewFrame.size;
UIImageView *iv = [[UIImageView alloc] initWithFrame:imageViewFrame];
iv.image = self.photo;
[self.scrollView addSubview:iv];
self.imageView = iv;
[iv release];
}
I am not getting where I am doing a mistake? Can anybody point me out? Thanks in advance.
Just found an awesome answer to your question. Here's the link: https://stackoverflow.com/a/5427890/1047258
And then you can do something like that:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *theImage = [[info objectForKey:#"UIImagePickerControllerOriginalImage"]fixOrientation];
//rest of your code
}
and theImage will be your image with correct orientation. It worked in my project
Hope it helps.
be careful not to throw away the orientation data... Try this:
image = [[UIImage alloc] initWithData:imgData];
CGImageRef imgRefCrop = image.CGImage;
UIImage *photo = [UIImage imageWithCGImage:imgRefCrop scale:image.scale orientation:image.orientation ];
also, you'll want to make sure you're cropping the right pixels depending in the image's orientation.
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();
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.