サムネイル生成機能を実装する 【QuickLook Plug-inの開発:実践的Macintoshプログラミング解説】

印刷用表示 |テキストサイズ 小 |中 |大 |

クイックルックプラグインの開発

実践的 Macintosh プログラミング解説

QuickLook Cover Flow.png

| HOME | 実際の機能を実装する | サムネイル生成機能を実装する |

更新日 2011-10-02 | 作成日 2008-01-04

サムネイル生成機能を実装する

処理の流れ

 次にサムネイル生成機能を実装しますが、基本的な流れはプレビュー機能と変わりません。

  1. 引数のチェック
  2. オートリリースプールの生成
  3. データの読み込み
  4. オブジェクトの非アーカイブ化
  5. オフスクリーンビューの準備
  6. グラフィックコンテキストの準備
  7. ビューにグラフィックコンテキストへ描画させる
  8. 後始末

といった流れで処理していきます。
 プレビューとの違いはサイズが指定されている事と紋様を一つだけ描画すればよい事ぐらいです。

コードの解説

 それではコードの解説に移ります。最初はインターフェイスファイルのインポートです。
 先ほど説明したオフスクリーンバッファの様なビューRepeatingMotifViewのインターフェイスファイルのインポートを追加します。

 次にプレビュー機能で宣言した文字列定数を使える様に、extern宣言を追加します。

#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>

#import <Cocoa/Cocoa.h>
#import "RepeatingMotifView.h"

extern  NSString    *RMGDocumentUTI;
extern  NSString    *RMGRepeatingMotifsKey;
extern  NSString    *RMGPictureWidthKey;
extern  NSString    *RMGPictureHeightKey;


 関数の頭では、読み込んだデータを入れておく変数を定義しています。また、アーカイブ化されているデータを非アーカイブ化するためのオブジェクトが必要なので、そのインスタンスを保持する変数を定義しました。
 プレビューで必要だった画像サイズを保持する変数は、サムネイル生成には不要なので省いてあります。

 オートリリースプールを作成する前にまず引数チェックをして、おかしかったら終了する様にしています。
 引数のUTIが想定しているものと違う場合は何もできないので、そのまま終了します。
 引数のURLがファイルを表すものではない場合も、やはりその後の処理ができないので終了します。

OSStatus GenerateThumbnailForURL(
    void *thisInterface,
    QLThumbnailRequestRef thumbnail,
    CFURLRef url,
    CFStringRef contentTypeUTI,
    CFDictionaryRef options,
    CGSize maxSize)
{
    NSArray             *repeatingMotifs;
    NSKeyedUnarchiver   *unarchiver;

    if(![(NSString *)contentTypeUTI isEqualToString:RMGDocumentUTI])
        return noErr;
    if(![(NSURL *)url isFileURL])
        return noErr;

 オブジェクトの生成をする前にオートリリースプールを生成します。その後、NSDataを生成してファイルの中身を読み込みます。

 NSDataから必要なオブジェクトだけを非アーカイブ化して取り出します。ここはプレビューとほぼ同じです。違いは画像サイズを読み込んでいない事ぐらいです。

    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
    NSData  *data = [NSData dataWithContentsOfFile:[(NSURL *)url path]];

    unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    repeatingMotifs = [unarchiver decodeObjectForKey:RMGRepeatingMotifsKey];
    [unarchiver finishDecoding];
    [unarchiver release];


 後は一気に最後までいきますが、中身はプレビューとほぼ一緒です。違いは画像サイズが引数で指定された値になっている事、先頭の紋様を一つ描いて終わりであることぐらいです。

    NSRect  nsRect = NSMakeRect(0,0,maxSize.width,maxSize.height);
    RepeatingMotifView *renderingView =
        [[[RepeatingMotifView alloc] initWithFrame:nsRect] autorelease];
    NSDictionary    *dict = [NSDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithInt:maxSize.width],kQLPreviewPropertyWidthKey,
        [NSNumber numberWithInt:maxSize.height],kQLPreviewPropertyHeightKey,
        nil];
    CGContextRef cgContext = QLThumbnailRequestCreateContext(
        thumbnail,maxSize,false,(CFDictionaryRef)dict);
    if(cgContext)
    {
        NSGraphicsContext* context = [NSGraphicsContext
            graphicsContextWithGraphicsPort:(void *)cgContext
                                    flipped:YES];
        if(context)
        {
            [NSGraphicsContext saveGraphicsState];
            [NSGraphicsContext setCurrentContext:context];

            [renderingView setRepeatingMotif:[repeatingMotifs objectAtIndex:0]];
            [renderingView displayRectIgnoringOpacity:nsRect
                                            inContext:context];

            [NSGraphicsContext restoreGraphicsState];
        }
        QLThumbnailRequestFlushContext(thumbnail,cgContext);
        CFRelease(cgContext);
    }

    [pool release];
    return noErr;
}

 Version 1.0をリリースした後で、プレビューの関数をコピーして作成したため、ゴミが残っている事に気づきました。QLThumbnailRequestCreateContext()の第四引数で辞書を渡していますが、これは意味がありません。
 Mac OS X 10.5ではプロパティは定義されていないそうなので、辞書オブジェクトを生成しているコードを削除して、ここはNULLにしておくべきでした。