Skip to content

Instantly share code, notes, and snippets.

@beloso
Created February 11, 2012 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beloso/1802341 to your computer and use it in GitHub Desktop.
Save beloso/1802341 to your computer and use it in GitHub Desktop.
//
// KenBurnsView.m
// KenBurns
//
// Created by Javier Berlana on 9/23/11.
// Copyright (c) 2011, Javier Berlana
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
#import "JBKenBurnsView.h"
#include <stdlib.h>
#define enlargeRatio 1.2
#define imageBufer 3
// Private interface
@interface KenBurnsView()
@property (nonatomic) BOOL animationInCurse;
@property (nonatomic, strong) NSOperationQueue *queue;
- (void) _animate:(NSNumber*)num;
- (void) _startAnimations:(NSArray*)images;
- (void) _startInternetAnimations:(NSArray *)urls;
- (UIImage *) _downloadImageFrom:(NSString *)url;
@end
@implementation KenBurnsView
@synthesize imagesArray, timeTransition, isLoop, isLandscape;
@synthesize animationInCurse, currentImage;
@synthesize queue = _queue;
- (NSOperationQueue *)queue{
if (!_queue){
_queue = [[NSOperationQueue alloc] init];
}
return _queue;
}
- (id)init
{
self = [super init];
if (self) {
self.layer.masksToBounds = YES;
self.currentImage = 0;
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.layer.masksToBounds = YES;
}
return self;
}
- (void) animateWithImages:(NSMutableArray *)images
transitionDuration:(float)duration
loop:(BOOL)shouldLoop
isLandscape:(BOOL)inLandscape;
{
self.imagesArray = images;
self.timeTransition = duration;
self.isLoop = shouldLoop;
self.isLandscape = inLandscape;
self.animationInCurse = NO;
self.layer.masksToBounds = YES;
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(_startAnimations:)
object:images];
[self.queue addOperation:operation];
}
- (void) animateWithURLs:(NSArray *)urls
transitionDuration:(float)duration
loop:(BOOL)shouldLoop
isLandscape:(BOOL)inLandscape;
{
self.imagesArray = [[NSMutableArray alloc] init];
self.timeTransition = duration;
self.isLoop = shouldLoop;
self.isLandscape = inLandscape;
self.animationInCurse = NO;
int bufferSize = (imageBufer < urls.count) ? imageBufer : urls.count;
// Fill the buffer.
for (uint i=0; i<bufferSize; i++) {
NSString *url = [[NSString alloc] initWithString:[urls objectAtIndex:i]];
[self.imagesArray addObject:[self _downloadImageFrom:url]];
}
self.layer.masksToBounds = YES;
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(_startInternetAnimations::)
object:urls];
[self.queue addOperation:operation];
}
- (void)_startAnimations:(NSArray *)images
{
@autoreleasepool {
for (uint i = 0; i < [images count]; i++) {
self.currentImage = i;
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(_animate:)
object:[NSNumber numberWithInt:self.currentImage]];
[mainQueue addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
sleep(self.timeTransition);
i = (i == [images count]-1) && isLoop ? -1 : i;
}
}
}
- (UIImage *) _downloadImageFrom:(NSString *) url
{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
return image;
}
- (void) _startInternetAnimations:(NSArray *)urls
{
@autoreleasepool {
BOOL wrapping = NO;
int bufferIndex = 0;
for (int urlIndex=self.imagesArray.count; urlIndex < [urls count]; urlIndex++) {
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(_animate:)
object:[NSNumber numberWithInt:0]];
[mainQueue addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[self.imagesArray removeObjectAtIndex:0];
[self.imagesArray addObject:[self _downloadImageFrom:[urls objectAtIndex: urlIndex]]];
if ( bufferIndex == self.imagesArray.count -1)
{
NSLog(@"Wrapping!!");
wrapping = YES;
bufferIndex = -1;
}
bufferIndex++;
urlIndex = (urlIndex == [urls count]-1) && isLoop ? -1 : urlIndex;
sleep(self.timeTransition);
}
}
}
- (void) _animate:(NSNumber*)num
{
UIImage* image = [self.imagesArray objectAtIndex:[num intValue]];
UIImageView *imageView;
float resizeRatio = -1;
float widthDiff = -1;
float heightDiff = -1;
float originX = -1;
float originY = -1;
float zoomInX = -1;
float zoomInY = -1;
float moveX = -1;
float moveY = -1;
float frameWidth = MAX(self.superview.frame.size.height, self.superview.frame.size.width) + 25;
float frameHeight = isLandscape? self.frame.size.height : self.frame.size.width;
// Widder than screen
if (image.size.width > frameWidth) {
widthDiff = image.size.width - frameWidth;
// Higher than screen
if (image.size.height > frameHeight) {
heightDiff = image.size.height - frameHeight;
if (widthDiff > heightDiff)
resizeRatio = frameHeight / image.size.height;
else
resizeRatio = frameWidth / image.size.width;
// No higher than screen
} else {
heightDiff = frameHeight - image.size.height;
if (widthDiff > heightDiff)
resizeRatio = frameWidth / image.size.width;
else
resizeRatio = self.bounds.size.height / image.size.height;
}
// No widder than screen
} else {
widthDiff = frameWidth - image.size.width;
// Higher than screen
if (image.size.height > frameHeight) {
heightDiff = image.size.height - frameHeight;
if (widthDiff > heightDiff)
resizeRatio = image.size.height / frameHeight;
else
resizeRatio = frameWidth / image.size.width;
// No higher than screen
} else {
heightDiff = frameHeight - image.size.height;
if (widthDiff > heightDiff)
resizeRatio = frameWidth / image.size.width;
else
resizeRatio = frameHeight / image.size.height;
}
}
// Resize the image.
float optimusWidth = (image.size.width * resizeRatio) * enlargeRatio;
float optimusHeight = (image.size.height * resizeRatio) * enlargeRatio;
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, optimusWidth, optimusHeight)];
// Calcule the maximum move allowed.
float maxMoveX = optimusWidth - frameWidth;
float maxMoveY = optimusHeight - frameHeight;
float rotation = (arc4random() % 9) / 100;
switch (arc4random() % 4) {
case 0:
originX = 0;
originY = 0;
zoomInX = 1.25;
zoomInY = 1.25;
moveX = -maxMoveX;
moveY = -maxMoveY;
break;
case 1:
originX = 0;
originY = frameHeight - optimusHeight;
zoomInX = 1.10;
zoomInY = 1.10;
moveX = -maxMoveX;
moveY = maxMoveY;
break;
case 2:
originX = frameWidth - optimusWidth;
originY = 0;
zoomInX = 1.30;
zoomInY = 1.30;
moveX = maxMoveX;
moveY = -maxMoveY;
break;
case 3:
originX = frameWidth - optimusWidth;
originY = frameHeight - optimusHeight;
zoomInX = 1.20;
zoomInY = 1.20;
moveX = maxMoveX;
moveY = maxMoveY;
break;
default:
NSLog(@"def");
break;
}
CALayer *picLayer = [CALayer layer];
picLayer.contents = (id)image.CGImage;
picLayer.anchorPoint = CGPointMake(0, 0);
picLayer.bounds = CGRectMake(0, 0, optimusWidth, optimusHeight);
picLayer.position = CGPointMake(originX, originY);
[imageView.layer addSublayer:picLayer];
CATransition *animation = [CATransition animation];
[animation setDuration:1];
[animation setType:kCATransitionFade];
[[self layer] addAnimation:animation forKey:nil];
// Remove the previous view
if ([[self subviews] count] > 0){
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
[self addSubview:imageView];
// Generates the animation
[UIView animateWithDuration:self.timeTransition + 2
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
CGAffineTransform rotate = CGAffineTransformMakeRotation(rotation);
CGAffineTransform moveRight = CGAffineTransformMakeTranslation(moveX, moveY);
CGAffineTransform combo1 = CGAffineTransformConcat(rotate, moveRight);
CGAffineTransform zoomIn = CGAffineTransformMakeScale(zoomInX, zoomInY);
CGAffineTransform transform = CGAffineTransformConcat(zoomIn, combo1);
imageView.transform = transform;
}
completion:nil];
}
- (void)pauseLayer
{
if ([self.subviews count] > 0) {
CALayer *layer = [[self.subviews objectAtIndex:0] layer];
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
}
- (void)resumeLayer
{
if ([self.subviews count] > 0) {
CALayer *layer = [[self.subviews objectAtIndex:0] layer];
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment