Fastest way to handle UIImagePickerController compression

Steven Fisher picture Steven Fisher · Oct 1, 2009 · Viewed 7.3k times · Source

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?

Answer

Steven Fisher picture Steven Fisher · Oct 3, 2009

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.)