NSSetとライフゲーム(その5、NSColor) [プログラミング - NSSetとライフゲーム]
ライフゲームの続きで、専用カラーテーブルの話。
カラーテーブルは人の作ってくれたのを流用できるようにしようと思ったが、きれいなグラデーションに限ってファイルに書き出せなかったりしたので、結局あきらめて自分で作れるようにした。いいものはなかなか只では手に入らないと言うことか。gnuよ、反論しない?
さて、それでは適当に作りますか。前回にちょっとだけ出たGoLColorTableは
@interface GoLColorTable : NSObject { NSMutableArray *colorTable; } + (NSArray *)supportedFileTypes; - (NSColor *)colorAtIndex:(int)index; - (int)numberOfColors; - (BOOL)load:(NSString *)fileName; - (void)save:(NSString *)fileName; - (NSMutableArray *)colorTable; ...
としよう。インスタンス変数のcolorTableと言う配列はNSColorインスタンスを保持する。プロパティリストの形式でファイルを読み書きするようにしたい。
ところが、NSColorはプロパティリストの形式では保存できないらしい。色を保存することって普通にあるのになぜ無いかは良くわからない。これはきっと汎用のものを用意するには色空間の変換の実装がめんどくさい(カラーマッチングの問題を抱え込む)ためだろうと思っている。programing guideでは、NSUserDefaultsにNSColorを含めるときはアーカイブしてNSDataに入れたものをNSUserDefaultsに登録しろ、となっている。
NSUserDefaultsならこれでもいいけど、中途半端でほかのprogramとやり取りしたいと思ったらこれでは厳しい。index-colorをサポートしてるファイル形式をまねるのが手っ取り早くていろんなのが手に入るだろうけどGIFやBMPをまねてもあまり役に立たないし。
結局いろいろ考えて、あとで簡単にテキストエディタなんかで編集できるようにNSStringとして色を保存することにした。ということでNSColorにカテゴリでメソッド
@interface NSColor (cltColorConversion) + (NSColor *)colorFromCltString:(NSString *)cltString; - (NSString *)cltString; @end
を追加しよう。archiveからNSDataを作ってファイルにするとNSColorの全情報がセーブできるけど、そのファイルを編集することはできないので割り切ってNSColorのインスタンスが保持している情報のうち
1.カラースペース
2.各コンポーネントの値(floatで)
だけをファイルすることにする。
実際の実装は
static NSString *cltColorSpaceSep = @":"; static NSString *cltColorValueSep = @","; + (NSColor *)colorFromCltString:(NSString *)cltString { NSArray *divstr = [cltString componentsSeparatedByString:cltColorSpaceSep]; if ([[divstr objectAtIndex:0] isEqualToString:NSCalibratedRGBColorSpace]) { NSArray *values = [[divstr lastObject] componentsSeparatedByString:cltColorValueSep]; if ([values count] != 4) return nil; return [NSColor colorWithCalibratedRed:[[values objectAtIndex:0] floatValue] green:[[values objectAtIndex:1] floatValue] blue:[[values objectAtIndex:2] floatValue] alpha:[[values objectAtIndex:3] floatValue]]; } else if ([[divstr objectAtIndex:0] isEqualToString:NSCalibratedWhiteColorSpace]) { NSArray *values = [[divstr lastObject] componentsSeparatedByString:cltColorValueSep]; if ([values count] != 2) return nil; return [NSColor colorWithCalibratedWhite:[[values objectAtIndex:0] floatValue] alpha:[[values objectAtIndex:1] floatValue]]; } return nil; } - (NSString *)cltString { NSString *colspace = [self colorSpaceName]; if ([colspace isEqualToString:NSCalibratedRGBColorSpace]) { return [NSString stringWithFormat:@"%@:%f,%f,%f,%f", NSCalibratedRGBColorSpace, [self redComponent], [self greenComponent], [self blueComponent], [self alphaComponent]]; } else if ([colspace isEqualToString:NSCalibratedWhiteColorSpace]) { return [NSString stringWithFormat:@"%@:%f,%f", NSCalibratedWhiteColorSpace, [self whiteComponent], [self alphaComponent]]; } return nil; }
ごちゃごちゃしてるけど、ようするに
<colorSpaceName> : <component1>, <component2>,...
の形で読み書きすることに。これをNSArrayにして、トップレベルはNSDictionaryにして普通のプロパティリストにセーブする。カラースペースはいっぱいあるけどとりあえずNSCalibratedRGBColorSpaceとNSCalibratedWhiteColorSpaceの二つだけをサポートした。今回の目的にはこれで十分でしょ。読み込みのときの文字列の切り出しにNSStringのcomponentsSeparatedByString:メソッドを使った。あまり賢いメソッドではないがこのような使い方(フォーマット決めうち)にはこれでエラーを起こしたりはしない。
セーブしたファイルは
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>colorTableFileKey</key> <array> <string>NSCalibratedRGBColorSpace:0.0000,0.0000,0.0000,0.0000</string> <string>NSCalibratedRGBColorSpace:0.0000,0.0000,0.0000,1.0000</string> ; </array> </dict> </plist>
みたいな感じになる。これなら数字を編集できるし、行を増やしても読み込みには問題は発生しない。とりあえずこれで我慢する。
このあと、これを実際に使うときはColor Spaceは無視してしまうけど。
コメント 0