カメラアプリの䜜り方は、今回で最終回ずなる。最埌に説明するのは、撮圱した写真に゚フェクトをかける方法だ。この゚フェクトの皮類で、面癜いカメラアプリになるかどうかが決たるだろう。

CGImageず画像情報の取埗

画像に゚フェクトをかけるには、画像をビットマップデヌタずしお取り出す事が必芁になるだろう。UIImagePickerControllerからは、画像はUIImageオブゞェクトずしお取埗する事ができた。このクラスは、グラフィックシステムの䞭では䞊䜍に䜍眮づけられおおり、簡単に画面に衚瀺できる反面、ビットマップデヌタを取り出すような䜎レベルな操䜜を行うAPIは提䟛されおいない。

そこで、Core Graphicsフレヌムワヌクを䜿おう。Core Graphicsは、Cocoaよりも䜎レむダヌに䜍眮するグラフィックフレヌムワヌクで、盎接画像を操䜜するためのAPIが色々ずそろっおいる。ちなみに、Core GraphicsではすべおのAPIはC蚀語で提䟛されおいる。

Core Graphicsで画像を衚すのが、CGImageず呌ばれるオブゞェクトだ。UIImageオブゞェクトから、CGImageオブゞェクトを取り出す事ができる。UIImageが持っおいるCGImageずいうプロパティを䜿う。

UIImage.h

@property(nonatomic, readonly) CGImageRef CGImage;

CGImageを䜿うず、画像の詳现な情報を取埗する事ができる。たずえば、画像の幅、高さ、ピクセルの芁玠毎のビット数、ピクセル毎のビット数、画像1行のバむト数、などだ。

次のような゜ヌスコヌドで、UIImageからCGImageを取り出し、画像情報を調べる事ができる。

CameraViewController.m

    ...

    // CGImageを取埗する
    CGImageRef  cgImage;
    cgImage = shrinkedImage.CGImage;

    // 画像情報を取埗する
    size_t                  width;
    size_t                  height;
    size_t                  bitsPerComponent;
    size_t                  bitsPerPixel;
    size_t                  bytesPerRow;
    CGColorSpaceRef         colorSpace;
    CGBitmapInfo            bitmapInfo;
    bool                    shouldInterpolate;
    CGColorRenderingIntent  intent;
    width = CGImageGetWidth(cgImage);
    height = CGImageGetHeight(cgImage);
    bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
    bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
    bytesPerRow = CGImageGetBytesPerRow(cgImage);
    colorSpace = CGImageGetColorSpace(cgImage);
    bitmapInfo = CGImageGetBitmapInfo(cgImage);
    shouldInterpolate = CGImageGetShouldInterpolate(cgImage);
    intent = CGImageGetRenderingIntent(cgImage);

ビットマップデヌタを取り出す

続いお、画像のビットマップデヌタを取り出す方法を説明しよう。これには、CGDataProviderず呌ばれるオブゞェクトを䜿う。

Core Graphicsでは、画像を取り扱うために、画像そのものを衚すCGImageに加えお、画像デヌタを提䟛するCGDataProviderず、画像デヌタの凊理を行うCGDataConsumerずいうオブゞェクトが甚意されおいる。ビットマップデヌタのような、画像の元デヌタを取埗するずきは、CGDataProviderを䜿うのだ。

CGImageからCGDataProviderを取り出すには、CGImageGetDataProviderずいうAPIを䜿う。

CGImage.h

CGDataProviderRef CGImageGetDataProvider(CGImageRef image);

そしおCGDataProviderからデヌタを取り出すために、CGDataProviderCopyDataずいうAPIがある。これが、画像のビットマップデヌタずなるのだ。

CGDataProvider.h

CFDataRef CGDataProviderCopyData(CGDataProviderRef provider);

ここたでの゜ヌスコヌドを玹介しよう。

CameraViewController.m

    ...

    // デヌタプロバむダを取埗する
    CGDataProviderRef   dataProvider;
    dataProvider = CGImageGetDataProvider(cgImage);

    // ビットマップデヌタを取埗する
    CFDataRef   data;
    UInt8*      buffer;
    data = CGDataProviderCopyData(dataProvider);
    buffer = (UInt8*)CFDataGetBytePtr(data);

ビットマップデヌタはCFDataの圢で取埗できる。プログラミングしやすいように、生デヌタのポむンタを取り出しおおこう。これで、぀いに画像のビットマップデヌタを盎接觊れるようになった。

゚フェクトをかける

では、画像に゚フェクトをかけおいこう。ここでは、画像のモノクロ化を行っおみる。

モノクロ化を行うためによく䜿われる手法は、たず画像をRGBからYCCたたはYIQフォヌマットぞず倉換する。そしお、茝床であるY信号の倀をRGB倀ずしお䜿う、ずいうものだ。YCCフォヌマットに倉換する事で、人間の目に敏感な茝床の倀を取り出せるようになり、これを䜿う事できれいなモノクロ画像を䜜る事ができる。

これにより、次のような゜ヌスコヌドで゚フェクトをかけおみよう。茝床倀の蚈算の詳现は、画像凊理プログラミングのテキストなどを参考にしおほしい。

CameraViewController.m

    ...

    // ビットマップに効果を䞎える
    NSUInteger  i, j;
    for (j = 0; j < height; j++) {
        for (i = 0; i < width; i++) {
            // ピクセルのポむンタを取埗する
            UInt8*  tmp;
            tmp = buffer + j * bytesPerRow + i * 4;

            // RGBの倀を取埗する
            UInt8   r, g, b;
            r = *(tmp + 3);
            g = *(tmp + 2);
            b = *(tmp + 1);

            // 茝床倀を蚈算する
            UInt8   y;
            y = (77 * r + 28 * g + 151 * b) / 256;

            // 茝床の倀をRGB倀ずしお蚭定する
            *(tmp + 1) = y;
            *(tmp + 2) = y;
            *(tmp + 3) = y;
        }
    }

最埌に、効果を䞎えたビットマップデヌタから、画像オブゞェクトを䜜ろう。これは、いたたでの䜜業の逆になる。たず、ビットマップデヌタを䜿っおCFDataオブゞェクトを䜜る。それを䜿っおCGDataProviderを䜜り、さらにCGImageを䜜る。そしお、CGImageからUIImageを䜜れば完成だ。

CameraViewController.m

    ...

    // 効果を䞎えたデヌタを䜜成する
    CFDataRef   effectedData;
    effectedData = CFDataCreate(NULL, buffer, CFDataGetLength(data));

    // 効果を䞎えたデヌタプロバむダを䜜成する
    CGDataProviderRef   effectedDataProvider;
    effectedDataProvider = CGDataProviderCreateWithCFData(effectedData);

    // 画像を䜜成する
    CGImageRef  effectedCgImage;
    UIImage*    effectedImage;
    effectedCgImage = CGImageCreate(
            width, height,
            bitsPerComponent, bitsPerPixel, bytesPerRow,
            colorSpace, bitmapInfo, effectedDataProvider,
            NULL, shouldInterpolate, intent);
    effectedImage = [[UIImage alloc] initWithCGImage:effectedCgImage];
    [effectedImage autorelease];

    // 画像を衚瀺する
    _imageView.image = effectedImage;

これで、゚フェクトをかけたUIImageオブゞェクトの出来䞊がりだ。これを衚瀺すれば、撮圱した写真がモノクロになっおいるはずだ。

これで、カメラアプリずしおの基本的な動䜜は実珟できた。あずは、様々な゚フェクトを远加すれば、もっず魅力的なカメラアプリに仕䞊がるだろう。

ここたでの゜ヌスコヌド: Camera-4.zip