iPhoneで画像を扱うときは、CocoaのNSImageに変わって、UIImageを使います。
UIImageはproperty、.CGImageでCGImageRefを取得できます。
で、UIImageはいろんな方法で作れたり取得できるのですが、retain関係がどうなってるのか、いまいちよくわからない!
@property(nonatomic,readonly) CGImageRef CGImage;
こうなっております。
readonlyはgetterのみ。入れ替えできない、という意味ですね。
nonatomicって何よ?ということで調べてみると
Objective-C 2.0プログラミング言語: プロパティの宣言と実装
nonatomic
合成されるアクセサが非アトミックになるように指定します。
デフォルトでは、合成されるアクセサはすべてアトミックです。これは、マルチスレッド環境でプロパティへの堅牢なアクセスを可能にすることを意図しています。つまり、getterから返される値やsetterを通じて設定される値は、ほかのスレッドが同時に実行しているかどうかに関係なく必ず完全に取得または設定されます。
アトミックな実装の目的は堅牢なアクセサを提供することであり、コードの正確性を保証することではないことを理解することが重要です。「アトミック」とは、プロパティへのアクセスがスレッドセーフであるという意味ですが、単にクラス内のすべてのプロパティをアトミックにするだけでそのクラス(一般にはオブジェクトグラフ)が「スレッドセーフ」になるということではありません。
とのこと。全般的によくわかりませんが
@property(readonly)
は
@property(atomic,readonly)
という意味(atomicってpropertyは無いけど)
ということがわかる。
ということで、non atomicなので、atomicじゃないよ、ということになる。
そうすると、スレッドセーフじゃない代わりにスピードが早いということか?
@synchronized(property)しないよ、ってな意味ですかいね。
そうすっと、main threadからのみアクセスしろ!ということ?
よくわからん。誰か頭いい人おしえて。
ともあれ、retain countには関係無い様子。
次。CGImageをCrop(Clip)できる関数。
CGImageRef CGImageCreateWithImageInRect(CGImageRef image, CGRect rect)
Thumbnail作るときなんかに便利です。こいつはどうなんだ。
The resulting image retains a reference to the original image, so you may release the original image after calling this function.
と書いてあるのに、original imageをrelease(CGImageRelease)したらBugります。すばらしい。意味がわからない。
英語の読み方が間違っているのだろうか。
次に、いろいろ登場の出番が多そうな
UIImage* UIGraphicsGetImageFromCurrentImageContext(void);
はDocumentによると
Return Value
An autoreleased image object containing the contents of the current bitmap graphics context.
なので、autoreleaseされたUIImageが返ってきます。
UIImageのallocしないmethodもautoreleaseで返ってきます(たぶん)。
例えば、imageNamedとか。
UIImage/CGImageRefの保存
UIImage/CGImageRefの作成を見たので、次は保存です。
QuartzでCGImageRefの保存といえば、CGImageDestinationなのですが
iPhoneでは
ImageIO.frameworkがPrivate.frameworkです。
つ、ま、り
ImageIO.h
CGImageProperties.h
CGImageSource.h
CGImageDestination.h
が使えなーい。
ImageIO.frameworkをリンクして、CGImageSource関係を呼び出してみたけど、nullが返ってきます。
iPhoneでは、前ここで書いた保存方法がつかえなーい。
ということで、UIImage関係のAPIを使います。
こんな感じで書き出しできます。
BOOL writeCGImageTo(NSString *path, CGImageRef cgImage){
NSURL *url = [NSURL fileURLWithPath:path];
UIImage *saveImage = [UIImage imageWithCGImage:cgImage];
NSData *data = UIImagePNGRepresentation(saveImage);
BOOL result = [data writeToURL:url atomically:YES];
return result;
}
これで書き出しできるなら、特別なことでもやらない限り、CGImageDestinationとかいらんよねぇということですかね。
iPhoneはファイルをセーブできる領域が限られているので、こんな感じで使います。
//CGImageRef targetImageが保存するCGImageRef
//pngでhoge.pngという名前で保存する
NSString *path = nil;
NSArray *directories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,YES);
if([directories count] == 1){
NSString *documentDirectory = [directories objectAtIndex:0];
NSString *imageName = @"hoge.png";
path = [documentDirectory stringByAppendingPathComponent:imageName];
}
if(path){
writeCGImageTo(path,targetImage);
}
上の例はじゃっかんアホなコードなので、pngしか保存できませんが
UIImageJPEGRepresentation
で、jpgで保存もできます。tiffは無いのか。
iPhoneは画像のリサイズとか死ぬほど遅いので、何度も使うことになりそうなthumbnailなんかは、こういうAPIあたりを駆使してキャッシュしておくと、ずいぶん早くなります。
OpenGL ESのTexture
Image系といえば、OpenGL ESのTexture.
描画は、Textureの描画がぶっちぎりで高速です。Quartzは全般的に遅くて、frame rate 10fpsも出ればがんばってるなーという感じでしょう(とうぜんものによります)。
速さが求められる場合、読み込みまでも考慮するならば、PVRTC formatのtextureがダントツ速いです。
Technical Q&A QA1611 Creating textures in the PVRTC compression format
(iPhone dev Centerでログインしないと見れません)
問題は、この変換がめんどくさいこと。
高frame rateが必要ない、GUIなんかならQuartzが圧倒的に便利。UIKitが用意しているGUIはcustomViewってな感じで独自のUIViewを貼れるようになっているものが多数あります。
ゲームなどでスピードとパフォーマンスが求められるならOpenGL ES。けど、そうするとGUIもほとんどOpenGLで用意せにゃなりません。
(ドキュメントにOpenGL context以外のものを混ぜるな危険!って書いてあったけど、どうなるんだろう)
そんなわけで、iPhoneやる上ではQuartzを覚えておいて損は無いと思います。