指定した画像ファイルのサムネイル画像(NSImage)を生成する関数

フォルダー内の画像ファイルの簡単なビューアーを探していたのですが、ほとんどのアプリが私の要求する機能を満たしておらず、機能を満たしているのはGraphic ConverterとACDSee 2の2つでした。しかしどちらも有料で、Graphic Converterは機能は豊富なのですがファイルが十数個程度のフォルダーを選択してもサムネイルの一覧が表示されるまでがやたらと長く、ちょっと使い物にはなりません。ACDSee 2も操作がもたつくことがあり、メモリーリークを起こしているのか先日メモリーの使用状況を見ると2GBを超えていて、こちらも使い物にはなりません。そこで無ければ自分で作るしかないといろいろ調査を始めたのですが、その第1弾としてサムネイル画像の生成方法を調べた結果以下のコードで実現できることがわかりました。

//
// Create thumbnail image from image file's URL
//
NSImage *thumbnailImageOfImageURL( NSURL *imgURL, NSInteger size )
{
    NSImage             *thumbnailImg;
    CFURLRef            srcURL = (__bridge CFURLRef)(imgURL);
    CGImageSourceRef    srcRef;
    CFDictionaryRef     options;
    CGImageRef          imageRef;
    NSBitmapImageRep    *bitmapRep;
    
    srcRef = CGImageSourceCreateWithURL(srcURL, NULL);
    if ( srcRef == NULL ) {
        return nil;
    }
    options = (__bridge CFDictionaryRef)([NSDictionary dictionaryWithObjectsAndKeys:
                                          (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
                                          (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
                                          [NSNumber numberWithInteger:size], (id)kCGImageSourceThumbnailMaxPixelSize,
                                          (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageAlways,
                                          nil]);
    //options = (__bridge CFDictionaryRef)([NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:size] forKey:keyMaxSize]);
    imageRef = CGImageSourceCreateThumbnailAtIndex( srcRef, 0, options );
    if ( imageRef == NULL ) {
        CFRelease(srcRef);
        return nil;
    }
    bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
    CFRelease(srcRef);
    CFRelease(imageRef);
    //CFRelease(options);   // 必要?→NO! これを呼ぶと死ぬ
    thumbnailImg = [[NSImage alloc] init];
    [thumbnailImg addRepresentation:bitmapRep];
    
    return thumbnailImg;
}

//
// Create thumbnail image from image file's path
//
NSImage *thumbnailImageOfImageFile( NSString *imgPath, NSInteger size )
{
    return thumbnailImageOfImageURL( [NSURL fileURLWithPath:imgPath], size );
}

この方法にたどり着くまで、以下のサイトを参考にさせていただきました。感謝です。

なお、最初はCGImageSourceCreateThumbnailAtIndexに渡すオプションのディクショナリーにサイズしか指定していなかったのですが、これではJPEG以外のフォーマットを読み込むことができませんでした。ネットで調べたところ一番最後のサイトでもっとオプションを追加しないといけないことが分かり、それを反映したところTIFFやPNGも読み込むことができました。

(旧) Cocoaの日々
画像のサムネイル作成関数について
iphone - Any suggestions on how to handle this crash in CGImageDestinationFinalize? - Stack Overflow

p.s. ARC(Automatic Reference Counting)が導入されてからCocoaフレームワークのオブジェクトのメモリーの解放についてはあまり気にしなくて良くなりずいぶんコードを書くのが楽になりましたが、Toll Free Bridge(通行料無料の橋)と呼ばれて単純にキャストすればよかったCoreFoundationのオブジェクトとの相互変換に注意が必要になりました。

【作成・確認環境】
MacOS X v10.8.2
Xcode v4.5.2

一覧に戻る