Camera Overlay with User-Photo not saving as edited - ios

I am using a transparent image with a cut out for a user to insert / take their own image. For some reason, while using the UIImagePickerControllerEditedImage and cropping the user-taken photo, the image does not save as it was edited; see photo for example.
My issue is that the image does not save exactly how the photo was edited. (i.e: cropped / resized).
Setting up the UIImagePicker
-(void)choosePhotoDialog:(id)sender
{
OverlayView * overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH_IPHONE, SCREEN_HEIGTH_IPHONE) andPhoto:[dict objectForKey:#"imageUrl"]];
[overlay setUserInteractionEnabled: NO];
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
[picker setSourceType: UIImagePickerControllerSourceTypeCamera];
[picker setDelegate: self];
[picker setAllowsImageEditing: YES];
[picker setShowsCameraControls: YES];
[picker setNavigationBarHidden: YES];
[picker setWantsFullScreenLayout: YES];
[picker setCameraOverlayView: overlay];
[self presentModalViewController:picker animated:YES];
[picker release];
}
After the image is edited:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
SDWebImageManager * manager = [SDWebImageManager sharedManager];
UIImage * cachedImage = [manager imageWithURL: [NSURL URLWithString: #"http://www.someurl.com/test.png"]];
UIImage * userOriginal = [info valueForKey:UIImagePickerControllerEditedImage];
/* combining the overlay and the user-photo */
UIGraphicsBeginImageContext( CGSizeMake(640,960) );
/* for some reason I have to push the user-photo
down 60 pixels for it to show correctly as it
was edited.
*/
[userOriginal drawAtPoint:CGPointMake(0,60)];
[cachedImage drawAtPoint:CGPointMake(0,0)];
UIImage * draft = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum( draft, self, #selector(image:didFinishSavingWithError:contextInfo:), nil );
}
As well, there are white spaces from the editing "crop" portion as demonstrated in the following:

I believe this is because the edited photo does not include the parts obscured by the semi-transparent framing overlay that is shown as part of the standard iOS image editor. (The 60px you've found you must offset by is the 60px of the top half of this overlay.)
You can extract and expand the UIImagePickerControllerCropRect key from the info dictionary and do the edit again yourself on the UIImagePickerControllerOriginalImage in order to get the resultant image you desire.

Related

UIImagePickerController returns bigger Image than the originial

I am working on an app that let the users choose photo from the gallery. The problem I am facing is very weird as the size of the photo(in terms of storage) changes when its picked up using UIImagePickerController.
In my case, I got a picture via air-drop. The image size is 8.7MB. but when I pick the same image via UIImagePickerController, it returns me the image of ~13MB.
Note: the resolution of the image remains the same([3024, 4032]).
I created a very simple app to test the thing. Here is sample code:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
bool flag = true;
- (void)viewDidAppear:(BOOL)animated {
if (flag) {
flag = false;
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
[self presentViewController:picker
animated:YES
completion:NULL];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
NSData *temp = UIImageJPEGRepresentation(chosenImage, 1);
NSLog(#"image: %lu", (unsigned long)temp.length);
NSLog(#"image: [%lu, %lu]", (unsigned long)chosenImage.size.width, (unsigned long)chosenImage.size.height);
[picker dismissViewControllerAnimated:YES completion:NULL];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissViewControllerAnimated:YES
completion:NULL];
}
#end
this is the link to the app, in case you want to test it for yourself.
The zip file also contains the sample photos.
Any help is appreciated.
This is because you get the image uncompressed from the picker (as a UIImage). You then convert it to jpeg with UIImageJPEGRepresentation() and you are passing in 1.0 as the compression quality which is highest quality (least compression). If you pass a lower number like 0.5 for the quality the resulting data will be smaller. See: https://developer.apple.com/reference/uikit/1624115-uiimagejpegrepresentation?language=objc
update
If you want the original file data you can use UIImagePickerControllerReferenceURL, see here: How do I get the data from UIImagePickerControllerReferenceURL?
Please refer this code
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
UIImage* chosenImage = [info valueForKey:#"UIImagePickerControllerOriginalImage"];
NSLog(#"Image Size Width %f Height %f",chosenImage.size.width,chosenImage.size.height);
UIGraphicsBeginImageContext(CGSizeMake(320, 480));
[originalImage drawInRect:CGRectMake(0,0,320,480)];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"image Size h %f Width %f",[image size].height, [image size].width);
}

UIimage not displaying image for duplicate method

I have a UImage view that opens and you can take a picture with it and view it in the uiimageview. But I added another image view and copied the code and now the image shows up the same image as the second one. I believe it may have something to do with the '[UIImagePickerControllerOriginalImage];'
- (void)imagePickerController:(UIImagePickerController *)
picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
// Get the image and store it in the image view
image = info[UIImagePickerControllerOriginalImage];
self.personimgThumbNail.image = image;
}
- (void)imagePickerControllertwo:(UIImagePickerController *)
picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
// Get the image and store it in the image view
imagetwo = info[UIImagePickerControllerOriginalImage];
self.personimgThumbNailtwo.image = imagetwo;
}
Just need a next step, been stuck on this one for quite a while.
There can be only one didFinish-Method. You have to differentiate between what to do inside the method itself. The method already gives you the UIImagePickerController, which is calling the method, so you just have to compare the pointers to it.
- (void)imagePickerController:(UIImagePickerController *)
picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
if(picker == self.pickerController1){
// Get the image and store it in the image view
image = info[UIImagePickerControllerOriginalImage];
self.personimgThumbNail.image = image;
}else if(picker == self.pickerController2){
// Get the image and store it in the image view
imagetwo = info[UIImagePickerControllerOriginalImage];
self.personimgThumbNailtwo.image = imagetwo;
}
}
Edit: You have to have 2 properties defined in the .m file of your class
#property (strong) UIImagePickerController *pickerController1;
#property (strong) UIImagePickerController *pickerController2;
What you have to do now, when instantiating your image-picker is the following
(code taken from the OPs comment under this answer)
- (IBAction)accessPhotoLibrary:(id)sender {
if(!self.pickerController1){
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
self.pickerController1 = imagePicker;
}
[self presentViewController:self.pickerController1 animated:YES completion:nil];
}

Overlaying an Image into another

i am trying to overlaying an image with another image. I have tried this But, its not exactly gives the output what i am expecting. Let me explain it clearly through below image,
Above is my ViewController where i am showing the Camera for taking the picture (Backgorund Image) using UIImagePickerController There is an Overlay Image i have placed. My overlay image can be rotate and zoom it :
if ([self isCameraAvailable] && [self doesCameraSupportTakingPhotos]) {
cameraPicker = [[UIImagePickerController alloc] init];
cameraPicker.delegate = self;
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
NSMutableArray *mediaTypes = [[NSMutableArray alloc] init];
[mediaTypes addObject:(__bridge NSString *)kUTTypeImage];
cameraPicker.mediaTypes = mediaTypes;
cameraPicker.showsCameraControls = NO;
cameraPicker.navigationBarHidden = YES;
cameraPicker.toolbarHidden = YES;
cameraPicker.delegate = self;
cameraPicker.allowsEditing = NO;
[self presentViewController:cameraPicker animated:YES completion:^{
overLayCustomView.hidden = NO;
[cameraPicker.view addSubview:overLayCustomView];
}];
}
Once, the picture has been taken, i have overlaid the image with captured image through below code :
NSString *mediaType = info[UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
UIImage *image = [self scaleAndRotateImage:[info objectForKey:UIImagePickerControllerOriginalImage]];
UIGraphicsBeginImageContextWithOptions(image.size, FALSE, 0.0);
[image drawInRect:CGRectMake( 0, 0, image.size.width, image.size.height)];
[renderedImage.image drawInRect:CGRectMake( renderedImage.frame.origin.x, renderedImage.frame.origin.y, renderedImage.frame.size.width, renderedImage.frame.size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil);
UIGraphicsEndImageContext();
[picker dismissViewControllerAnimated:YES completion:^{
[self performSegueWithIdentifier:#"previewPage" sender:newImage];
}];
}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
// Code here to support video if enabled
}
Code for scaleAndRotateImage
When, i tried these result for the image processing working weird. It gives below issues,
Captured image (Background Image) clarity has been lost.
Overlay image not placed exact point of the frame.
Frame of the overlay image changing and if its rotated not captured as rotated one.
Any, idea about my brief explanation with my code?
Update
Yeah, finally, i have achieved this and using AVCaptureSession to capture a Picture instead of using UIImagePickerController which would be an useful one. Now, the only thing is, My overlay image can be rotated though below one,
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotate:)];
[rotationRecognizer setDelegate:self];
[self.overLayImage addGestureRecognizer:rotationRecognizer];
- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
recognizer.rotation = 0;
}
I am not able to overlay the rotated the overlay image into another one. Not able to get the rotated image? How can i achieve this?

Resize UIImage from UIImagePickerController

I am currently taking a photo using this code here
- (void) cameraButtonSelected
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:picker animated:YES completion:NULL];
}
I am allowing the user to edit the the photo but when I use this delegate method for some reason the UIImagePickerController will not remove from view after the user has pressed "Use Photo"
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
I would like to know
How do I remove UIImagePickerController from view after "Use Photo" button pressed
How can I resize the photo I have just taken as I need a smaller variant to send to my server
You can get the image by querying for UIImagePickerControllerEditedImage in the info dict.
And to remove the ImagePicker from View just dismiss the picker.
Here is the code to resize.
Just call it with your image instance
You can use this function to scale the image to particular size
- (UIImage *) scaleImage:(UIImage*)image toSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
So your final code should be something like this
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:Nil];
UIImage *image = info[UIImagePickerControllerEditedImage];
image = [self scaleImage:image toSize:CGSizeMake(200,200)]; // or some other size
}
simple , you can search it here on stackoverflow
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *tempImage=[info objectForKey:UIImagePickerControllerEditedImage];
[self.dealImageView setImage:[self imageWithImage:tempImage convertToSize:CGSizeMake(200, 200)]];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size {
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *destImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return destImage;
}
whats-the-easiest-way-to-resize-optimize-an-image-size-with-the-iphone-sdk
resizing-and-cropping-a-uiimage
Call [self dismissModalViewControllerAnimated:YES completion:nil] somewhere in your - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info method. This is common practice for any modal view.
This question is probably more complicated than you might think. There are a number of ways to resize a photo in iOS and the code you use really will depend on your needs. However you can take a look at this blog post to get an understanding of photo resizing. It's very comprehensive and I would recommend reading it before you write any code.
http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
That being said this is a very simple way to achieve resizing:
The simplest way to resize an UIImage?

UIButton setBackground from image picker works on 2nd attempt only

I been stuck on this for a while since it is so weird. I present a user with image picker and on selection use the image as a button background. The problem is that it works only after image is picked for the 2nd time. Do not have to be the same image. Present image picker select picture, nothing. Try again for the same or different picture and everything works just fine. Code is below, does anyone have any suggestions?
-(void) changeProfileImage:(UIImage*) image {
profilePhoto = image;
[editPhotoButton setTitle:#"edit" forState:UIControlStateNormal];
[editPhotoButton setBackgroundImage:profilePhoto forState:UIControlStateNormal];
[editPhotoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *) imageInfo {
UIImage* imageToUse;
UIImage* editedTmpImage = [imageInfo objectForKey:#"UIImagePickerControllerEditedImage"];
if (!editedTmpImage)
imageToUse = [imageInfo objectForKey:#"UIImagePickerControllerOriginalImage"];
imageToUse = [imageToUse resizedImageWithContentMode:UIViewContentModeScaleAspectFill bounds:CGSizeMake(MIN(imageToUse.size.width,1024), MIN(imageToUse.size.width, 768)) interpolationQuality:kCGInterpolationHigh];
[self changeProfileImage:imageToUse];
[imagePicker dismissViewControllerAnimated:YES completion:Nil];
}
First, just to make sure, can you just clean it up a little bit like this and try again?
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *) imageInfo {
UIImage* imageToUse = [imageInfo objectForKey:#"UIImagePickerControllerEditedImage"];
if (!imageToUse) { // this part was confusing above, please use curvy-braces
imageToUse = [imageInfo objectForKey:#"UIImagePickerControllerOriginalImage"];
}
imageToUse = [imageToUse resizedImageWithContentMode:UIViewContentModeScaleAspectFill bounds:CGSizeMake(MIN(imageToUse.size.width,1024), MIN(imageToUse.size.width, 768)) interpolationQuality:kCGInterpolationHigh];
[self changeProfileImage:imageToUse];
[imagePicker dismissViewControllerAnimated:YES completion:nil];
}
This (Is it possible to refresh a single UITableViewCell in a UITableView?) solves the problem! Redrawing sell as recommended in the link works.

Resources