Cocoaでいこう! Macらしく 第22回
Yoshiki(DreamField)
この記事は、MOSAが発行するデベロッパ向けのデジタルマガジンMOSADeN 第83号(2003年9月30日発行)に掲載された記事です。2〜3ヶ月遅れで、ここに掲載して行きます。

TinyViewは、拡張して行く内に必用無くなった部分が残ったままになっていますし、操作性に問題がある所も残っています。そこで今回から数回に分けて、この辺りの棚卸しをしてしまおうと思います。そしてこれが片付きましたら、次は画像表示に手を入れて行く予定です。

カテゴリでNSImageにJPEG変換を追加しよう

棚卸しの前に、前回残した課題を片付けてしまいましょう。前回、余裕のある方はJPEG変換もNSImageに組み込んでみましょう、と書きましたが、実際に組み込んだ方はおられますでしょうか。この様な応用問題を自分で解かれますと、より一層理解が深まると思います。

JPEG変換の組み込みの要領は、PICT変換と同じですので、簡単に書いておきます。まずは、ImageProducingData.mに次のメソッドを追加します。

- (NSData *)JPEGRepresentation{
    NSData *theTiffData;
    NSBitmapImageRep *theBitmapImageRep;
    NSDictionary *theProperty;

    theTiffData = [ self TIFFRepresentation];
    theBitmapImageRep = [ NSBitmapImageRep imageRepWithData:theTiffData ];
    theProperty = [ NSDictionary dictionaryWithObjectsAndKeys:
                      [ NSNumber numberWithFloat:0.5],
                        NSImageCompressionFactor,
                        nil ];
    return [ theBitmapImageRep representationUsingType:NSJPEGFileType
                                            properties:theProperty];
}

このメソッドの宣言をImageProducingData.hに追加して、次の様にします。

@interface NSImage (ImageProducingData)
- (NSData *)PICTRepresentation;
- (NSData *)JPEGRepresentation;
@end

そして、このメソッドを活用すべく、MyDocument.mのdataRepresentationOfType:を次の様に修正します。

- (NSData *)dataRepresentationOfType:(NSString *)aType
{
    NSData *theData;

    theData = nil;
    if( [ aType isEqualToString:@"JPEG"]){
        theData = [ image JPEGRepresentation];
    }else if( [ aType isEqualToString:@"PICT"]){
        theData = [ image PICTRepresentation];
    }
    return theData;
}

以上です。とてもシンプルになりましたね。

ところで、今回採用したインターフェースは、圧縮率の指定が出来ません。実用的な実装にするためには、様々なパラメタを渡せるようにする必用があるでしょう。では、どの様なインターフェースにすれば良いのでしょうか。この様なことを考える時は、既存のメソッドの仕様が参考になります。例えばNSImageのTIFFRepresentationUsingCompression:factor:の様なパラメタの渡し方にしても良いと思いますし、いっそNSBitmapImageRepのrepresentationUsingType:properties:の様に、NSDictionaryクラスで何でも渡せるようにしてしまっても良いかもしれません。前者の方がより簡単に扱えますし、後者の方がより拡張性があります。どちらが良いかは、メリットとデメリットのトレードオフになりますので、正解は無いでしょう。自分自身にとって、より現実的な解がどちらかということになると思います。それから、現在の実装では間にTIFFを挟んでいますが、これは明らかにオーバーヘッドがあります。性能を重視するなら、もっと良い方法があるかもしれません。本連載では、これ以上の拡張は行いませんが、興味を持たれた方は、さらに調べてみるのも面白いと思います。

※もっと良い方法をご存じの方は、是非教えて下さいませ。

必用が無くなった処理を削除しよう

それでは、もう本日の記事は半ばを過ぎてしまいましたが、棚卸しを行って行きます。まずは拡張して行く内に、必用無くなってしまった処理を削除します。

最初にTinyViewに保存機能を組み込んだ時は、読み込んだデータをとっておいて、それをそのまま保存していました。今では、NSImageから各フォーマットに変換するようにしましたので、読み込んだデータをとっておく必用がありません。そこで、この処理を削除しましょう。まずはMyDocument.mのloadDataRepresentation:を見て下さい。

- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
    [ data retain];
    documentData = data;
    image = [ [ NSImage alloc] initWithData:data];
    return ( image != nil)?( YES):( NO);
}

データをとっておく処理は3行目と4行目でした。これを削除しましょう。次にdeallocを見て下さい。

- (void)dealloc
{
    [ documentData release];
    [ super dealloc];
}

3行目は、ドキュメントを閉じる時にとっておいたデータを解放するようにしたものでした。この部分が必用無くなりますから、deallocのオーバライド自体必用無いことになります。そこで、このメソッドごと削除してしまいましょう。最後に、MyDocument.hを見て下さい。

@interface MyDocument : NSDocument
{
    IBOutlet id imageView;

    NSImage *image;
    NSData *documentData;
}
@end

documentDataは、読み込んだデータのアドレスを格納しておくためのインスタンス変数でした。格納の必用はもう無いので、これも削除しましょう。以上で、必用が無くなった処理は全て削除できました。念のために、ビルドして、動作を確認して下さい。

それでは、本日はここまでとしまして、次回は起動した時に勝手に開いてしまう空のウィンドウを片付けようと思います。

前頁目次次頁