Question

How do you implement a pixelate transition like this (animated gif) in iOS?

Is it possible to implement with Core Animation?

Was it helpful?

Solution

C4 - Travis' comment being correct, your best option is probably to render the animation live yourself. You'll want to take the code in QA1703 for screen capture, but adjust the size of the context you create at UIGraphicsBeginImageContextWithOptions and alter the Core Graphics current transform matrix (CTM) appropriately immediately after the call to UIGraphicsGetCurrentContext. So, just typing as I write this, your adjustments would be to result in something like:

- (UIImage*)screenshotWithScale:(CGFloat)scale
{
    // Create a graphics context with the target size
    // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
    // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
    CGSize imageSize = [[UIScreen mainScreen] bounds].size;

    /* YOU'VE ADDED: */
    imageSize.width *= scale;
    imageSize.height *= scale;

    if (NULL != UIGraphicsBeginImageContextWithOptions)
    /* ... then stuff as per the original, down to ... */

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextScaleCTM(context, scale, scale);

    // Iterate over every window from back to front
    for (UIWindow *window in [[UIApplication sharedApplication] windows]) 
        /* etc, etc, down to... */

     // Retrieve the screenshot image
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    CGContextRestoreGState(context);
    UIGraphicsEndImageContext();

    return image;
}

With scale = 1.0, you'll get back a UIImage exactly equal to the screen. With scale = 0.5 you'll get one with half as many pixels across and down, with scale = 0.25 you'll get a quarter as many pixels across and down, etc.

You can then put that UIImage into a UIImageView, and set its layer's magnification filter to kCAFilterNearest. Showing that image view should give you a deliberatedly pixellated version of the original. You can then either be lazy and just keep performing a half-size render of what's already on screen (so the live view the first time, the image view subsequently) or adapt the code not to render from the main window but rather from a nominated view and re-render from the original view hierarchy as required (which would work if you wanted to do something other than keep dividing the scale by an integer).

OTHER TIPS

There are CIPixellate and CIHexagonalPixellate filters documented in the Core Image Filter Reference, but these are currently available only for OSX... not iOS, unfortunately.

http://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html

I don't know about a good way to use this in a transition, but if you could capture a still image of your content (as a UIImage), you should be able to do a time-animated pixellation filter to produce the above effect.

I show an example of my GPUImagePixellateFilter in this answer, which could produce such an effect if you adjusted the fractionalWidthOfAPixel property on a timer.

For a still image, you'd need to pull in your UIImage as a GPUImagePicture and chain it via the pixellation filter to a GPUImageView. For every update of the pixel width, you'll want to call -processImage on the image source to update the image onscreen. After the initial setup and image upload, this animation should run at 60 FPS on every iOS device that supports OpenGL ES 2.0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top