32

Since iOS 9 and Xcode 7 I am no longer able to implemet a UIImagePickerController on an iPad (both device and simulator). The code below works on the iPad but only prior to iOS 9. When using iOS 9+ the presented image (after the UIImagePickerController is dismissed) is an incorrect version of the selected image. Without re-sizing or cropping the final image is only the top right corner of the original image ?? Plus another problem - If imagePicker.allowsEditing = false, you are unable to select images from the PhotoLibrary ??

@IBAction func photoButton(sender: AnyObject) {    

    imagePicker.allowsEditing = true
    imagePicker.sourceType = .PhotoLibrary

    self.presentViewController(imagePicker, animated: false, completion: nil)

}


func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
    if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {

    self.imageView.image = pickedImage

    dismissViewControllerAnimated(true, completion: { () -> Void in
            })    

}

Heres an example of a selected image presented in a UIImagePickerController. (notice how the selected image is presented very small and not full size/width of screen as before)

enter image description here

After selecting the use button within the UIImagePickerController the final image is only the top right of the original image. What am I doing wrong or is UIImagePickerController broken on iOS 9 ?

enter image description here

Nicolas Miari
  • 16,006
  • 8
  • 81
  • 189
pete
  • 2,980
  • 4
  • 22
  • 34

7 Answers7

11

This is a bug from Apple: http://openradar.appspot.com/radar?id=5032957332946944

Current lousy workaround:

 if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
         imagePicker.allowsEditing = false
     } else {
         imagePicker.allowsEditing = true
     }

Swift 3.0:

if UIDevice.current.userInterfaceIdiom == .pad {
}
StrawHara
  • 1,301
  • 19
  • 33
MPaulo
  • 1,491
  • 14
  • 19
  • This should be the accepted answer. All the other longwinded answers are misleading and a waste of time to read, because they "fix" the problem by either setting allowsEditing to `false` or they're running on the iPhone not the iPad. – chetstone Oct 19 '16 at 21:40
  • 1
    Do the same check in 'didFinishPickingMediaWithInfo' and set UIImagePickerControllerOriginalImage/UIImagePickerControllerEditedImage respectively for the other half of this workaround.. at least you can still have the functionality you like for iPhone devices until they fix this... – edhnb Mar 13 '17 at 19:26
4

Refer the below coding

@IBAction func photoButton(sender: AnyObject)
{
   if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
   {
     picker!.sourceType = UIImagePickerControllerSourceType.Camera
     self .presentViewController(picker!, animated: true, completion: nil)
   }
   else
   {
     let alertWarning = UIAlertView(title:"Warning", message: "You don't have camera", delegate:nil, cancelButtonTitle:"OK", otherButtonTitles:"")
     alertWarning.show()
   }
}
func openGallary()
{
   picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
   self.presentViewController(picker!, animated: true, completion: nil)
}

//PickerView Delegate Methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])
{
   picker .dismissViewControllerAnimated(true, completion: nil)
   imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
   println("picker cancel.")
}
user3182143
  • 9,459
  • 3
  • 32
  • 39
  • 1
    Yes, the issue is with the `UIImagePickerControllerEditedImage` key in the info dictionary. Using `UIImagePickerControllerOriginalImage` will work, even if it's not ideal. – fedoroffn Jul 25 '16 at 20:01
3

You need to make sure you have the correct frame for your imageview and the contentmode for your imageview should be aspectfit and the image returned by the picker is of type [UIImagePickerControllerOriginalImage]

[imageView setFrame:imageViewRect];
[imageView setContentMode:UIViewContentModeScaleAspectFit];

Swift:

 imageView.setFrame(imageViewRect)
 imageView.setContentMode(UIViewContentModeScaleAspectFit)

and coming to the allowsEditing property, It is not related to photo selection.

It is a Boolean value indicating whether the user is allowed to edit a selected still image or movie.

If you want to select photos from camera library, then you need to modify the source type to

    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

Update:

LEts say you have selected one image and display it on the image view. I assume you have one imageview on the view, and the imageview frame is equal to the view frame. If the IB is of freeform , I assume the size 600x600 for the imageview frame in the IB.

if you simply do:

     _startImageView.image=_img;

The result will be:

enter image description here

Now let's make some changes to the image to be displayed in the imageview:

  CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(_img.size, CGRectMake(0, 0, self.startImageView.frame.size.width, self.startImageView.frame.size.height));
UIGraphicsBeginImageContext(CGSizeMake(_startImageView.frame.size.width,_startImageView.frame.size.height));
 [_img drawInRect:scaledRect];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

_startImageView.image=scaledImage;

and now the image will be:

enter image description here

The original image choosen is of size 640x426, when not scaled.

The original image choosen is of size 1536x1286 when scaled to max(with two finger zoom action).

As you can see, still there is no huge change in the image, it is because the image is already cropped/scaled by the time your imageview recieved the image!!!

So even though you try to do:

      [_img drawInRect:_startImageView.frame];

The image will not be drawn as per our need, as the image is already scaled right at them moment as the image given by the picker is the edited image.

Solution:

To fix this, you need to select the original image from picker in didFinishPickingMediaWithInfo: method

       info[UIImagePickerControllerOriginalImage];

which gives you the image:

enter image description here

Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109
  • the imageView is an iboutlet (tested both iboutlet and property ) and I've tried self.imageView.contentMode = UIViewContentMode.ScaleAspectFit but again no luck (not sure how [imageView setFrame:imageViewRect]; in swift ). Is there any chance you try a UIImagePickerController in a simple app to see if UIImagePickerController with IOS9 is broken ?? – pete Oct 23 '15 at 18:51
  • I used imagepicker in ios9 too, but in obj-c.I dont think there is an issue with the language. – Teja Nandamuri Oct 23 '15 at 18:55
  • Try setting imageViewRect something like cgrectmake(0,0,50,50), if it is an iboutlet, try to constriant its width and height – Teja Nandamuri Oct 23 '15 at 18:56
  • Just tried that but again no luck. Are you using xocde 7+ plus IOS9 in swift ? – pete Oct 23 '15 at 19:10
  • I'm having the same problem. But to verify if the problem lies with the UIImagePickerController, I downloaded and slightly modified a sample provided by Apple - https://developer.apple.com/library/ios/samplecode/PhotoPicker/Introduction/Intro.html. Set allowsEditing to YES and it works fine. – Vitali Tchalov Nov 17 '15 at 17:24
  • 2
    An update to my comment above: I narrowed down the problem - it is specific to iPad. Select iPhone in the Deployment Info of the PhotoPicker demo app project and it works as expected. However, when set to iPad, the editedImage returned from the info in imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *) info method is cropped to an upper-left corner. (the original image is fine). Modifications to the sample app to reproduce: 1) add imagePickerController.allowsEditing = YES; after line 118 – Vitali Tchalov Nov 18 '15 at 15:02
  • and 2) replace line 251 with: UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage]; – Vitali Tchalov Nov 18 '15 at 15:02
  • I have the same thing, is seems that only happens on iPad Air or Air2, the iPad mini is fine. – lxzhh Dec 10 '15 at 13:52
  • @Mr.T Yeah, use UIImagePickerControllerOriginalImage can solve the problem, but is so wired that it's special to iPad! – lxzhh Dec 10 '15 at 14:10
2

This code is relatively similar to @pkc456, just a little shorter.

This works perfectly for me:

   import UIKit

   class PostImageViewController: UIViewController,    UINavigationControllerDelegate, UIImagePickerControllerDelegate {

  @IBOutlet var imageToPost: UIImageView!

   @IBAction func chooseImage(sender: AnyObject) {

    var image = UIImagePickerController()
    image.delegate = self
    image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    image.allowsEditing = false //or true additional setup required.

    self.presentViewController(image, animated: true, completion: nil)

}

         func imagePickerController(picker: UIImagePickerController,    didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {



    self.dismissViewControllerAnimated(true, completion:nil)

}

Does this work?

Lukesivi
  • 2,206
  • 4
  • 25
  • 43
1

I am working on xcode 7.1(Swift) and found your code appropriate. I also wrote the below code on my project and it is working successfully.

func showPicker(){
    let type = UIImagePickerControllerSourceType.PhotoLibrary
    if(UIImagePickerController.isSourceTypeAvailable(type)){
        let pickerController = UIImagePickerController()
        pickerController.delegate = self
        pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
        pickerController.allowsEditing = false
        self.presentViewController(pickerController, animated: true, completion: nil)
    }
}

func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!) {
    let imageView = self.view.viewWithTag(20) as! UIImageView
    let selectedImage : UIImage = image
    imageView.image=selectedImage
    self.dismissViewControllerAnimated(true, completion: nil)
}

The only difference in your code and my code is about visibility of ImagePickerController instance. For your reference, I upload my code at:- https://www.dropbox.com/s/pe0yikxsab8u848/ImagePicker-Swift.zip?dl=0

My idea is just look at my code once, may be you will get an idea about which section of your code malfunctioning.

pkc456
  • 8,350
  • 38
  • 53
  • 109
  • 1
    Really appreciate your time to help and upload an example but unfortunately your answer requires the pickerController.allowsEditing = false. I need the user to be able to resize the image within the UIImagePickerController. I have now read that this problem has been reported to apple - heres the link https://forums.developer.apple.com/thread/19999 – pete Oct 26 '15 at 17:15
  • Yes, when I set allowsEditing = true, Your issue is reproducible. Good work that you posted over developer forum. – pkc456 Oct 27 '15 at 04:55
  • No, it does not look like an iOS 9 bug - I downloaded and slightly modified a UIImagePickerController sample provided by Apple from https://developer.apple.com/library/ios/samplecode/PhotoPicker/Introduction/Intro.html. Set allowsEditing to YES and also modified the didFinishPickingMediaWithInfo method to get the edited image. Result? It actually works fine. A problem must be on a way we are using it. – Vitali Tchalov Nov 17 '15 at 17:29
  • @vitaliTchalov The code Apple have provided also has the allowsEditing set to NO. – Groot Jan 07 '16 at 07:45
  • @VitaliTchalov The code Apple provides also is iPhone only. If you set the project to universal and run it on iPad, set allows editing to true and use the edited image. It doesn't work. – Daniel T. Mar 16 '16 at 13:56
1

It seems like you are using IB and auto layout but have set a right constraint. Try to add some constraint in your storyboard.

MatthewLuiHK
  • 691
  • 4
  • 10
1

for me I was solved, showing mode as popover

  @IBAction func photoButton(sender: AnyObject) {

    imagePicker.allowsEditing = true
    imagePicker.sourceType = .PhotoLibrary

    let controller = self.imagePicker


    controller.modalPresentationStyle = UIModalPresentationStyle.Popover
    controller.modalTransitionStyle = UIModalTransitionStyle.CoverVertical
    let popover = controller.popoverPresentationController

    popover?.sourceView = self
    controller.preferredContentSize = CGSize(
        width: self.frame.width * 0.6,
        height: self.frame.height * 0.6
    )

    popover?.sourceRect = CGRectMake(
        CGRectGetMidX(self.bounds),
        CGRectGetMidY(self.bounds),
        0,
        0
    )


    self.presentViewController(self.imagePicker, animated: true, completion: nil)
}
Carlos Chaguendo
  • 2,895
  • 19
  • 24