簡単に電光掲示板を作ってみる

『[福井]iPhoneアプリ開発勉強会』(http://atnd.org/events/16933)で話して来ました。

内容は、簡単な画像処理としてUIImageのビットマップをさわってモノクロ画像にするやり方の紹介と、簡単な電光掲示板の作成について。正直、電光掲示板の一般的な作り方とか知らないけど、まぁ、こうすればそれっぽくできますよ、という感じ。

簡単な画像処理(モノクロ画像化)はこちらの記事を参照。
【コラム】実践! iPhoneアプリ開発 (4) カメラアプリの作り方 (4) - 写真にエフェクトをかける | エンタープライズ | マイコミジャーナル
注意点としては、RGB値を参照するbitに注意すること。変な色になるなら調整しましょう。

で、ここからが本題です。

簡単な電光掲示板の仕様は次のとおり。

  • 横(480x320)レイアウトで、LEDの配置は30x20
  • 1LEDあたり、LEDのサイズは12pixelでマージンが2pixel
  • 16pixelずつメッセージ画像はスクロールする
  • メッセージ画像の上に、スクロールしないマスク画像を重ねる

メッセージ画像をUILabelで作って何も画像処理しないとこうなります。

見てのとおり、LEDの一部だけ色が付いてるのが気持ち悪いので、ここで画像処理を投入し、点灯するか消えるかはっきりさせます。

  1. UILabelからUIImageを作る
  2. 作ったUIImageを加工して、LEDの中心の色をLED全体の色にする

UILabelをtargetViewに与えるとUIImageができる

+ (UIImage *)createImage:(UIView *)targetView {
    UIGraphicsBeginImageContext(targetView.bounds.size);
    [targetView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();  // autorelease済
    UIGraphicsEndImageContext();
    return viewImage;
}

UILabelをtargetViewに与えるとUIImageができる(上記処理)ので、そのビットマップを編集して、LEDの中心の色で(マスクで隠れる部分も含め)LEDを四角く塗りつぶす。

+ (UIImage *)createLEDImage:(UIView *)targetView {
    UIImage *image = [ImageUtil createImage:targetView];
	
    // CGImageを取得する
    CGImageRef cgImage = image.CGImage;
	
    // 画像情報を取得する
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
    size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
    size_t bytesPerPixel = bitsPerPixel / 8;
    size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
    bool shouldInterpolate = CGImageGetShouldInterpolate(cgImage);
    CGColorRenderingIntent intent = CGImageGetRenderingIntent(cgImage);
	
    // データプロバイダを取得する
    CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
	
    // ビットマップデータを取得する
    CFDataRef data = CGDataProviderCopyData(dataProvider);
    UInt8* buffer = (UInt8*)CFDataGetBytePtr(data);
	
    // ビットマップに効果を与える
    // 2 top margin, 2 bottom margin, 12 LED area, check LED center
    // check y = 8, 24, 40....
    for (int y = 8; y < height; y += 16) {
        for (int x = 8; x < width; x += 16) {
            UInt8 *checkBit = buffer + y * bytesPerRow + x * bytesPerPixel;
            // copy this color to (x-6, y-6, 12, 12)
            for (int j = y - 6; j < y + 6; j++) {
                for (int i = x - 6; i < x + 6; i++) {
                    memcpy(buffer + j * bytesPerRow + i * bytesPerPixel, checkBit, bytesPerPixel);
                }
            }
        }
    }
	
    // 効果を与えたデータを作成する
    CFDataRef effectedData = CFDataCreate(NULL, buffer, CFDataGetLength(data));
	
    // 効果を与えたデータプロバイダを作成する
    CGDataProviderRef effectedDataProvider = CGDataProviderCreateWithCFData(effectedData);
	
    // 画像を作成する
    CGImageRef effectedCgImage = CGImageCreate(
                                               width, height, 
                                               bitsPerComponent, bitsPerPixel, bytesPerRow, 
                                               colorSpace, bitmapInfo, effectedDataProvider, 
                                               NULL, shouldInterpolate, intent);

    UIImage* effectedImage = [[[UIImage alloc] initWithCGImage:effectedCgImage] autorelease];
	
    // 作成したデータを解放する
    CGImageRelease(effectedCgImage);
    CFRelease(effectedDataProvider);
    CFRelease(effectedData);
    CFRelease(data);	
	
    return effectedImage;
}

これで普通にLEDっぽい(文字の周辺部分が中心にあった場合に色が薄くなることもありますが、拘りがなければOKでしょう)

実際に動かせるプロジェクトはこちら(ImageTest.zip)に置いておきますので、ダウンロードして動かしたり、ソースを見てみてください。簡単ですよ。

ちなみに、これに通信機能や設定などを付けていったものがConnectable LED-Boardです。無料だし、気が向いたらダウンロードしてね。
#リンク先の動画が古いや・・(^^;