(前回)Cocoaの日々: BlogAssistant(6) - リファクタリング 〜 クラス構成の見直し
バグ取りやCoreDataの不審な挙動、画像のflipped問題などなどでずいぶんと手間取ってしまったが、ようやく動く様になってきた。
こんな感じ。
以下、開発ログ。
縮小画像を奇麗にする
NSImage を lock して別の NSImage へ描画する方法で縮小を行う場合、デフォルトではあまり奇麗な画像にならない。
[thumnailImage lockFocus];
[viewImage drawInRect:thumnailRect
fromRect:clippedRect
operation:NSCompositeSourceOver fraction:1.0];
[thumnailImage unlockFocus];
こんな感じ。
この方法で縮小する場合は -[NSGraphicsContext setImageInterpolation:] を使うと良い。
[thumnailImage lockFocus];
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[viewImage drawInRect:thumnailRect
fromRect:clippedRect
operation:NSCompositeSourceOver fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
[thumnailImage unlockFocus];
するとこうなる。
アンチエイリアスが効いていい感じ。
他のケースも置いておく。
これが
こうなる。
-[NSGraphicsContext setImageInterpolation:] は以前紹介したことがある。興味がある方はそちらもどうぞ。
Cocoaの日々: キャプチャ画像を縮小して保存する
なお設定するタイミングは -[NSImage lockFocus] の後にする。そうでないと目的のコンテキスト内で有効にならない。
CoreDataの不審な挙動
xcdatamodel ファイル編集画面で、エンティティのクラスを指定することができる。
右上のやつ。
当初クラスは NSManagedObject なのだが、今回サブクラスである Resourceを作ったので、ここを Resource に変えた。すると挙動がおかしくなった。具体的には NSTableView にモデル内のデータが表示されなくなった。ただ見た目は空なのだがデータ件数分レコードが存在し編集もできる。編集すると突然そのレコードだけ表示されるようになる。原因がわからず困っていたが、一旦ファイル(Resource.h/m)を削除して、Xocdeの新規ファイル作成から「管理オブジェクトクラス」として作り直すと問題が出なくなった。
原因わからず。うーむ。
NSImage のフリップ対応
以前 Mac OS X v10.6 から -[NSImage setFlipped] が Deprecated になったことを紹介した。
Cocoaの日々: NSImage の isFlipped/setFlipped: が Deprecated
その対策として座標系を上下反転させて描画すれば良い、とのことだったが座標系が変わると座標計算をし直す必要があり、これに手間取った。
上下反転には NSAffineTransform を使う。こんな感じ。
[NSGraphicsContext saveGraphicsState];
NSAffineTransform* xform = [NSAffineTransform transform];
[xform translateXBy:0.0 yBy:viewSize.height];
[xform scaleXBy:1.0 yBy:-1.0];
[xform concat];
[image drawInRect:imageFrame
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
+[NSGraphicContext saveGraphicState] しておかないと、同じビューで描画する他のところでおかしなことになる(座標系が変わるため)。
座標の補正イメージ:
フリップしているVIEWの特定の位置に NSImage を描く場合。そのままだと逆さに表示される。今までは -[NSImage setFlipped:YES] で終わりだったのだが、Deprecated 扱いとなったので自前で反転させる。
NSAffinTransform によって描画時のみ原点が左下に戻る(Cocoaはデフォルトで左下が原点、ビューがフリップさせると左上になる)。この場合、画像の描画位置は先ほどの (ix, iy) ではなく (ix', iy')を指定する必要がある。
計算はこんな感じ。
ix' = ix iy' = vh - iy - ih
※先の投稿の時は描画位置を気にしていないので特に問題にならなかった。
バグ
表示対象の画像(NSImage)に autoreleaeを付けたため、表示する時にアプリがクラッシュしていた。初歩的ミス。
- (NSImage*)image
{
if (!image && self.imageFilename) {
NSString* path = [[PathManager sharedManager] imagePath];
image = [[[NSImage alloc] initWithContentsOfFile:
[path stringByAppendingPathComponent:self.imageFilename]] autorelease]; <--ここ
}
return image;
}
なお画像は NSManagedObject のサブクラス Resourceで持っている。これは CoreData とは関係なしにインスタンス変数として存在する。
@interface Resource : NSManagedObject
{
NSImage* image;
}
@property (retain) NSString * imageFilename;
@property (retain) NSString * title;
@property (retain) NSString * url;
@property (retain) NSImage * image;
@end
インスタンスが解放される時に image を解放する(release)必要がるが、普通に dealloc に書けばいいのだろうか(今はそうしている)。NSManagedObjectは特殊なのでちょっと気になる。※後日しらべる。
Mac Dev Center: NSManagedObject Class Reference - Subclassing Notes
ソース
GitHubからどうぞ。
xcatsan's BlogAssistant at 2010-01-20 - GitHub
- - - -
画像の扱いをどうするか。ブログへアップロードする時にファイル名が UUID じゃさっぱり区別が付かないし。自前でアップロードできると一番いいのだが。