2011年8月12日金曜日

iOS で ImageIO を使ってアニメーションGIFファイルを生成してみる

参考にしたのはこちら。
http://pojos-devlog.blogspot.com/2005/08/saving-animated-gif-using-coregraphics.html

iOS 4以降でよければImageIOフレームワークが使えるためむちゃくちゃ簡単です。任意のUIImage / CGImageRefから好きなようにアニメーションGIFを生成できます。

#import <UIKit/UIKit.h>
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
- (void)exportAnimatedGif
{
UIImage *shacho = [UIImage imageNamed:@"shacho.png"];
UIImage *bucho = [UIImage imageNamed:@"bucho.jpeg"];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"animated.gif"];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path],
kUTTypeGIF,
2,
NULL);
NSDictionary *frameProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:2] forKey:(NSString *)kCGImagePropertyGIFDelayTime]
forKey:(NSString *)kCGImagePropertyGIFDictionary];
NSDictionary *gifProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCGImagePropertyGIFLoopCount]
forKey:(NSString *)kCGImagePropertyGIFDictionary];
CGImageDestinationAddImage(destination, shacho.CGImage, (CFDictionaryRef)frameProperties);
CGImageDestinationAddImage(destination, bucho.CGImage, (CFDictionaryRef)frameProperties);
CGImageDestinationSetProperties(destination, (CFDictionaryRef)gifProperties);
CGImageDestinationFinalize(destination);
CFRelease(destination);
NSLog(@"animated GIF file created at %@", path);
}
view raw gistfile1.m hosted with ❤ by GitHub


iOS 3以前の場合は・・・頑張れとしか・・・

メモ: CoreDataで更新処理をするときは、lockをわすれずに

単なるメモ書きです><

http://twitter.com/#!/akisutesama/status/83521489382555650
http://twitter.com/#!/akisutesama/status/83521729380626433
ある一つのCore Dataのモデルを非同期的に複数箇所から更新するときは、たとえどんなに軽微な、プロパティ一つだけの、他からは触られない様な変更ですら、きちんとlockを取らないと危険ということがわかった。API実行クラスだけでは不十分であった。非同期であればロック必須。
変更を行うコードブロックを渡して、内部で安全にロックして実行、必要に応じてロールバックや失敗通知も行える様にする仕組みを作ろうと思った。
CoreDataのモデルオブジェクトの更新はただのsetterプロパティの使用だけで発生してしまうのでついつい忘れがちになるのですが、これが原因で実際にクラッシュしたアプリもあるので油断禁物。

UIPanGestureRecognizerはiOS4.0ではtranslationプロパティを正しく返さない

UIPanGestureRecognizerのtranslationプロパティは、iOS 4.0でかつUIScrollViewの配下になっているviewに対して取り付けた場合、常にCGPointZeroを返してしまうようです。iOS 4.1のシミュレータで確認したら直ってましたので、iOS 4.0限定だと思われます。というわけでvelocityプロパティをかわりに使っておくことをお進めします。

検証結果はこちら
// Assume "self" is added to a UIScrollView
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
NSLog(@"%s", __func__);
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
// Ignore horizontal or vertical pans depending on the orientation property
UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint translation = [panGesture translationInView:self];
NSLog(@" * self.frame = %@", NSStringFromCGRect(self.frame));
NSLog(@" * translation = %@", NSStringFromCGPoint(translation));
NSLog(@" * velocity = %@", NSStringFromCGPoint([panGesture velocityInView:self]));
NSLog(@" * location = %@", NSStringFromCGPoint([panGesture locationInView:self]));
NSLog(@" * superview.frame = %@", NSStringFromCGRect(self.superview.frame));
NSLog(@" * supertranslation = %@", NSStringFromCGPoint([panGesture translationInView:self.superview]));
NSLog(@" * supervelocity = %@", NSStringFromCGPoint([panGesture velocityInView:self.superview]));
NSLog(@" * superlocation = %@", NSStringFromCGPoint([panGesture locationInView:self.superview]));
switch (orientation)
{
case Holizontal:
{
return fabs(translation.x) > fabs(translation.y);
}
case Vertical:
{
return fabs(translation.x) < fabs(translation.y);
}
default:
{
NSAssert1(NO, @"orientation value %d is invalid.", orientation);
return NO;
}
}
}
return YES;
}
/*
Result in iOS 4.0.0
-[MyView gestureRecognizerShouldBegin:]
* self.frame = {{856, 0}, {107, 380}}
* translation = {0, 0}
* velocity = {-256.336, -427.227}
* location = {0, 218}
* superview.frame = {{0, 0}, {320, 380}}
* supertranslation = {0, 0}
* supervelocity = {-256.336, -427.227}
* superlocation = {856, 218}
-[MyView gestureRecognizerShouldBegin:]
* self.frame = {{856, 0}, {107, 380}}
* translation = {0, 0}
* velocity = {-126.199, 25.2398}
* location = {4, 196}
* superview.frame = {{0, 0}, {320, 380}}
* supertranslation = {0, 0}
* supervelocity = {-126.199, 25.2398}
* superlocation = {860, 196}
Result in iOS 4.3.4
-[MyView gestureRecognizerShouldBegin:]
* self.frame = {{749, 0}, {107, 380}}
* translation = {0, -6.5}
* velocity = {15.7758, -260.301}
* location = {58, 300.5}
* superview.frame = {{0, 0}, {320, 380}}
* supertranslation = {0, -6.5}
* supervelocity = {15.7758, -260.301}
* superlocation = {807, 300.5}
-[MyView gestureRecognizerShouldBegin:]
* self.frame = {{642, 0}, {107, 380}}
* translation = {8, 0}
* velocity = {283.102, 78.5224}
* location = {107.5, 122}
* superview.frame = {{0, 0}, {320, 380}}
* supertranslation = {8, 0}
* supervelocity = {283.102, 78.5224}
* superlocation = {749.5, 122}
*/
view raw gistfile1.m hosted with ❤ by GitHub