2012-12-17
Core Image の全エフェクトを試せるサンプルコードを公開しました
ライブラリ, iPhone, Objective-C, iOS6
Core Image のフィルタ(画像にエフェクトをかけたり、色を調整したりするもの)を一通り試せるサンプルプロジェクトをgithubに上げました。
というか、これ、1年以上前にアップしてこちらの記事に書いたのですが、ほとんど認知されることがなかったので、改めて紹介させていただきます。
こんな感じでフィルターを試せます。
(フィルタのパラメータはランダムに生成されるので、かける度に変わる場合もあります)
プロジェクト一式、こちらからダウンロードできます。
https://github.com/shu223/FilterDemo
注意点として、選んでも何も起こらないフィルターがたくさんあります。
詳細は後述しますが、こちら、Apple の PocketCoreImage というサンプルコードを数行いじっただけのものなので、あんまり多種多様なフィルタに対応したつくりになってはいないのです。。
そういうフィルタはリストから除いてもよかったのですが、「どんなフィルタがあるのか?」を一覧できる意味もあるので、残してあります。
PocketCoreImageからの改変点
CIFilterは、下記のように、NSString型の名前を引数に渡してインスタンスを生成します。
CIFilter *newFilter = [CIFilter filterWithName:name];
で、ここに渡せる名前をずらずらっと列挙するために、awakeFromNibで次のようなコードで全ビルトインフィルタの名前を取得しています。
NSArray *filterNames; filterNames = [CIFilter filterNamesInCategory:kCICategoryBuiltIn]; _availableFilters = [NSArray arrayWithArray:filterNames];
それと、PocketCoreImageでは、フィルタをかける箇所で、次のようにKVCを利用して元画像をフィルタに渡しています。
[filter setValue:_filteredImage forKey:@"inputImage"];
ここで、inputImageというアクセサを持たないフィルタもあるので、
if (![filter respondsToSelector:NSSelectorFromString(@"inputImage")]) { continue; }
とチェックを入れて例外を回避しています。
(詳細はこちらの記事をご参照ください)
その他、コードの解説
もともと PocketCoreImage にあった部分なのですが、多種多様なパラメータを持つ不特定多数のフィルタに対してランダム値を設定する部分はこうなっているよ、というのを紹介させていただきます。
まず、CIFilterのattributesメソッドでパラメータ一覧を取得します。
(このあとここでは設定しないパラメータを取り除く処理が入りますが割愛)
NSDictionary *filterAttributes = [filter attributes];
NSNumber型のパラメータだけを取り出し、
for (NSString *key in editableAttributes) { NSDictionary *attributeDictionary = [editableAttributes objectForKey:key]; if ([[attributeDictionary objectForKey:kCIAttributeClass] isEqualToString:@"NSNumber"]) { // 後述 } }
BOOL/Decimal/Integerそれぞれの型に応じて、ランダム値を設定しています。
(下記は、上記コードのif文の中身)
if ([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeBoolean)
{
NSInteger randomValue = (rand() % 2);
NSLog(@"Setting %i for key %@ of type BOOL", randomValue, key);
[filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
}
else if([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeScalar ||
[attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeDistance ||
[attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeAngle)
{
// Get the min and max values
float maximumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMax] floatValue];
float minimumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMin] floatValue];
float randomValue = randFloat(minimumValue, maximumValue);
NSLog(@"Setting %f for key %@ of type Decimal", randomValue, key);
[filter setValue:[NSNumber numberWithFloat:randomValue] forKey:key];
}
else
{
// Get the min and max values
NSInteger maximumValue = [[attributeDictionary valueForKey:kCIAttributeMax] integerValue];
NSInteger minimumValue = [[attributeDictionary valueForKey:kCIAttributeMin] integerValue];
NSInteger randomValue = (rand() % (maximumValue - minimumValue)) + minimumValue;
NSLog(@"Setting %i for key %@ of type Integer", randomValue, key);
[filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
}
Core Image の参考書籍
iOS Core Frameworksテクニカルガイド
2012年9月と比較的最近出版されたものですが、原著の出版は2011年9月。したがって iOS5 時代のものです。『Core Image』の章があるのですが、広く浅く、という感じです。
iOS5プログラミングブック
Core Imageの章あり。この本は全体的に説明が詳しく、あまり他の書籍やブログにないところまで踏み込んだ情報も多いので、個人的にはこちらの方がおすすめです。
おまけ:CIFilterのフィルタ名一覧(iOS 6 版)
前回記事(2011年11月)時点では 48 個だったものが、なんと 94 個に増えていました。
CIAdditionCompositing
CIAffineClamp
CIAffineTile
CIAffineTransform
CIBarsSwipeTransition
CIBlendWithMask
CIBloom
CIBumpDistortion
CIBumpDistortionLinear
CICheckerboardGenerator
CICircleSplashDistortion
CICircularScreen
CIColorBlendMode
CIColorBurnBlendMode
CIColorControls
CIColorCube
CIColorDodgeBlendMode
CIColorInvert
CIColorMap
CIColorMatrix
CIColorMonochrome
CIColorPosterize
CIConstantColorGenerator
CICopyMachineTransition
CICrop
CIDarkenBlendMode
CIDifferenceBlendMode
CIDisintegrateWithMaskTransition
CIDissolveTransition
CIDotScreen
CIEightfoldReflectedTile
CIExclusionBlendMode
CIExposureAdjust
CIFalseColor
CIFlashTransition
CIFourfoldReflectedTile
CIFourfoldRotatedTile
CIFourfoldTranslatedTile
CIGammaAdjust
CIGaussianBlur
CIGaussianGradient
CIGlideReflectedTile
CIGloom
CIHardLightBlendMode
CIHatchedScreen
CIHighlightShadowAdjust
CIHoleDistortion
CIHueAdjust
CIHueBlendMode
CILanczosScaleTransform
CILightenBlendMode
CILightTunnel
CILinearGradient
CILineScreen
CILuminosityBlendMode
CIMaskToAlpha
CIMaximumComponent
CIMaximumCompositing
CIMinimumComponent
CIMinimumCompositing
CIModTransition
CIMultiplyBlendMode
CIMultiplyCompositing
CIOverlayBlendMode
CIPinchDistortion
CIPixellate
CIRadialGradient
CIRandomGenerator
CISaturationBlendMode
CIScreenBlendMode
CISepiaTone
CISharpenLuminance
CISixfoldReflectedTile
CISixfoldRotatedTile
CISmoothLinearGradient
CISoftLightBlendMode
CISourceAtopCompositing
CISourceInCompositing
CISourceOutCompositing
CISourceOverCompositing
CIStarShineGenerator
CIStraightenFilter
CIStripesGenerator
CISwipeTransition
CITemperatureAndTint
CIToneCurve
CITriangleKaleidoscope
CITwelvefoldReflectedTile
CITwirlDistortion
CIUnsharpMask
CIVibrance
CIVignette
CIVortexDistortion
CIWhitePointAdjust
2012-05-25
Assets Library を利用した高速フォトビューア
iPhone, Objective-C, 作ったアプリ, iOS
1年以上前にこちらの記事で Assets Library の読み込みを高速化する試行錯誤について書かせていただきましたが、そのときに作った『i走馬灯』という高速フォトビューアアプリを作り直して再リリースしました。
※無料です
再リリースの経緯
もともと iPhone 4 のカメラの解像度でも高速表示は厳しかったのですが、iPhone4S になってさらにカメラの解像度が上がり、もはや「走馬灯」といえるスピードは出せなくなっていました。(iPhone 4Sの処理速度でも)
描画をOpenGLで行うことも検討してみましたが、
ALAsset *aseet = (ALAsset *)[self.assets objectAtIndex:currentAssetIndex];
ALAssetRepresentation *representation = [asset defaultRepresentation];
UIImage *img = [UIImage imageWithCGImage:[representation fullResolutionImage]
scale:[representation scale]
orientation:[representation orientation]];
結局この ALAssetRepresentation から fullScreenImage なり fullResolutionImage なりで CGImageRef を取り出しているところが時間かかってるっぽくて、描画を高速化してもここがボトルネックになるんではと思い断念しました。
で、
ALAsset *asset = (ALAsset *)[self.assets objectAtIndex:currentAssetIndex_];
UIImage *img = [UIImage imageWithCGImage:[asset thumbnail]];
このように『ALAsset から直接 thumbnail メソッドで CGImageRef を取り出す』方式だと非常に高速で、それを6個、12個、24個と増やしても相変わらずチョッパヤだったので、もうサムネイル表示だけでいこうってことで、「サムネイルを高速表示するアプリ」として作り直した次第です。
ちょっといい感じの写真が iPhone に入ってなくてスクリーンショットを用意しなかったのですが、上記6分割、12分割の他にも、24分割モードがあります。
無料なのでぜひお試しいただけると幸いです!
2012-05-12
逆ジオコーディングで取得した CLPlacemark の住所情報の内容
先日CLGeocoder を用いた逆ジオコーディングの記事を書きましたが、その結果得られる CLPlacemark 型の addressDictionary プロパティに入っている住所情報について、どのキーがどういう情報なのか、国ごとにどういう違いがあるのか、毎回調べるのが面倒なのでここに書いておきます。
近所で位置情報を取得し逆ジオコーディングし、addressDictionaryの内容をログ出力するとこんな感じでした。(エンコードおかしいですが気にしないでください・・・)
City = "\U938c\U5009\U5e02";
Country = "\U65e5\U672c";
CountryCode = JP;
FormattedAddressLines = (
"\U3012248-0007 \U795e\U5948\U5ddd \U938c\U5009\U5e02 \U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7"
);
Name = "\U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7";
State = "\U795e\U5948\U5ddd";
Street = "\U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7";
SubLocality = "\U5927\U753a";
SubThoroughfare = "6\U756a13\U53f7";
Thoroughfare = "\U5927\U753a 2\U4e01\U76ee";
ZIP = "\U3012248-0007";
ここからわかることは、
- FormattedAddressLines には、"ZIP", "State", "City", "Street"の順に入っている
- 日本でいうと、"State"は都道府県、"City"は市区町村にあたり、"Street"には「小町 2丁目3番1号」といったような町名地番が入る
- "Street" は、"Thoroughfare" と "SubThoroughfare" を繋げたもので、"SubLocality" は町名(市区町村以降の地名。"Thoroughfare" にも含まれる)
ただどの国でもこれらの項目が得られるかというとそうではなく、たとえばチュニジアの緯度経度で逆ジオコーディングすると、
Country = "\U30c1\U30e5\U30cb\U30b8\U30a2"; CountryCode = TN; FormattedAddressLines = ( "RN 3E", "\U30c1\U30e5\U30cb\U30b8\U30a2" ); Name = "RN 3E"; State = "\U30b7\U30c7\U30a3\U30d6\U30b8\U30c3\U30c9"; Street = "RN 3E"; Thoroughfare = "RN 3E";
addressDictionaryにはこういう感じの結果が返ってきました。
"City" や "SubThoroughfare" 、"SubLocality" といった項目がはいっていません。データがないのか、もともと住所の構造がシンプルなのかわかりませんが、日本と同様に市区町村にあたる項目があるという前提で処理を書くとおかしなことになりそうです。
そもそもこういうのは世界共通で規格みたいなものがあるのかもしれないので、こういう場当たり的な調べ方は的外れなのかもしれません。悪しからず・・・
2012-05-06
iOS 5.0 より追加された CLGeocoder を使用して逆ジオコーディング
Appleのドキュメントによると
iOS 5.0では、MKReverseGeocoderとMKReverseGeocoderDelegateは非推奨になっているの で、新たにアプリケーションを開発する場合はCLGeocoderを使ってください。
とのことなので、逆ジオコーディングを CLGeocoder を使用してやってみたのでその手順をこちらにメモしておきます。
(上記Appleのドキュメントのコードは少しずつ変数名が間違ってたり、独自定義のクラスが引数の型に指定されていたりして、そのままでは使いづらい・・・)
で、手順といってもヘッダのインポートやオブジェクトの生成とかを除けば、
- reverseGeocodeLocation:completionHandler: を呼ぶ
これしかありません・・・
僕の場合は下記のようにクラスメソッドを定義しました。
+ (void)reverseGeocodeLocation:(CLLocation *)location { CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder reverseGeocodeLocation:location completionHandler: ^(NSArray* placemarks, NSError* error) { if ([placemarks count] > 0) { CLPlacemark *placemark = (CLPlacemark *)[placemarks lastObject]; // 取得したplacemarkを格納したNSNotificationを発行 } }]; }
Blocksで非同期に処理されるので、CLPlacemarkオブジェクトを取得したらNSNotificationを発行して必要なオブジェクトに通知するようにしました。
なお、reverseGeocodeLocation:completionHandler: で得られる値が NSArray 型になっていますが、CLGeocoderのクラスリファレンスによると
Contains an array of CLPlacemark objects. For most geocoding requests, this array should contain only one entry. However, forward-geocoding requests may return multiple placemark objects in situations where the specified address could not be resolved to a single location.
とあり、逆ジオコーディングのときは基本的に1つしかオブジェクトが入ってこないと思ってよさそうです。(正ジオコーディングのときはアドレス→緯度経度なので、1つとは限らないため、NSArrayになっている)
2012-04-01
クロスディゾルブで画面遷移
Tips, Objective-C, iOS, iPhone
UIView に用意されている画面遷移用エフェクトとして、カールアップ/ダウンやフリップ(クルッとまわる)以外にも、iOS4.0以降ではクロスディゾルブ(アルファで入れ替わる)も利用できます。
2つの UIView (下記サンプルでは fromView, toView)を用意して、 transitionFromView:toView:duration:options:completion: メソッドの options 引数に UIViewAnimationOptionTransitionCrossDissolve を渡してやるだけ。
[UIView transitionFromView:fromView
toView:toView
duration:1.0
options:options
completion:^(BOOL finished) {
// animation completed
}];
アクのない一般的なエフェクトなので比較的使い勝手がいいと思うのですが、UIViewAnimationOptionTransitionCrossDissolve で検索してみたら意外にも日本語で触れられているページがヒットしなかったのでご紹介しました。
(参考:Appleのサンプルコード)
https://developer.apple.com/library/ios/#samplecode/ViewTransitions/Introduction/Intro.html














