Search code examples
iphonecocoa-touchuiimagepickercontrolleruiimagejpegrepresentation

Fastest way to handle UIImagePickerController compression


What's the fastest way of getting a picture into a SQLite data store for compression, so I can return control to the user?

  • I'm using UIImagePickerController to take pictures in my application. The problem is using the picture is quite slow, because of the speed of UIImageJPEGRepresentation.
  • I want to push JPEG compression into a background thread, but before trying this I need to satisfy myself that I can persist the picture in a way that will survive across runs. That means either a blob in SQLite or a file. Which as far as I can tell, takes me right back to doing slow picture encoding right away.

What I want to achieve is speed fast enough that it feels instant to the user.

How should I be handling this? Is there anything else I should know?


Solution

  • Based on comments and tests, here's what I'm currently doing:

    When I get the image from the UIImageController, I retain it in a class ivar and dismiss the image picker. I show a view that blocks my main view and schedule a NSTimer event to do the compression in a second, then return to the caller.

    This lets the animation run that dismisses the image controller. My blocker view is revealed under it.

    (The blocker view fills the entire content area of the navigation controller, and is solid black with a UIActivityIndicatorView.)

    - (void)imagePickerController: (UIImagePickerController *)picker
            didFinishPickingImage: (UIImage *)selectedImage
                      editingInfo: (NSDictionary *)editingInfo;
    {
        busyView.userInteractionEnabled = YES;
        busyView.alpha = 0.7f;
        mainView.userInteractionEnabled = NO;
        [self dismissModalViewControllerAnimated: YES];
        [NSTimer scheduledTimerWithTimeInterval: 1.0f
                                         target: self
                                       selector: @selector(compress:)
                                       userInfo: selectedImage
                                        repeats: NO];
    }
    

    When the timer fires, I compress the image using JPEG (because it's faster than PNG, despite intuition) and fade away the blocker view.

    - (void)compress: (NSTimer *)inTimer;
    {
        [self gotJPEG: UIImageJPEGRepresentation( inTimer.userInfo, 0.5f )];
        [UIView beginAnimations: @"PostCompressFade" context: nil];
        [UIView setAnimationDuration: 0.5];
        busyView.userInteractionEnabled = NO;
        busyView.alpha = 0.0f;
        [UIView commitAnimations];
        mainView.userInteractionEnabled = YES;
    }
    

    Although this adds a second do the processing, it gets the image picker out of the way faster so it no longer feels like my application has frozen. The animation from the UIActivityIndicatorView does run while UIImageJPEGRepresentation is working.

    A better answer than using the NSTimer with 1 second delay would be to get an event when the animation from dismissModalViewControllerAnimated: finishes, but I'm not sure how to do this.

    (I don't consider this solved yet.)