自前で描画した内容がUIImageで ぼやける時の処置

このブログのアクセス解析で、検索されたワードを見ていると、「objective-c ぼやける」という組み合わせで当ブログにアクセスしている方がいた。おそらく、Objective-Cで描画した内容がぼやけている問題を解決したくて検索したのだろうな、と勝手に解釈して、その解決方法を書いておく。本稿の内容は、CGContextRefを指定したりして描画した内容をUIImage化した際にぼやける場合の解決方法である。

描画の例

例えば、グラフィックコンテキストをつくって描画した内容をUIImageにする場合、以下のようなコードになる。

// ビットマップ画像のコンテキストを作成
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();

// 文字列を描画
NSString *text = @"これはテストです。";
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
[text drawInRect:self.view.bounds withFont:[UIFont systemFontOfSize:18]];

// 現在のコンテキストのビットマップをUIImageとして取得
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// コンテキストを閉じる
UIGraphicsEndImageContext();

// UIImageViewをつくって、画像を画面上に表示する
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:self.view.bounds] autorelease];
[imageView setImage:image];
[self.view addSubview:imageView];

上記のようなコードを書いた場合、以下のようにパッと見は綺麗だが、

このように、iOSシミュレーターで最大まで拡大すると粗が見える。

解決策

このような場合は、以下のようにコードを書き換えればよい。

// ビットマップ画像のコンテキストを作成
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();

// 文字列を描画
NSString *text = @"これはテストです。";
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
[text drawInRect:self.view.bounds withFont:[UIFont systemFontOfSize:18]];

// 現在のコンテキストのビットマップをUIImageとして取得
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// コンテキストを閉じる
UIGraphicsEndImageContext();

// UIImageViewをつくって、画像を画面上に表示する
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:self.view.bounds] autorelease];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[imageView setImage:image];
[self.view addSubview:imageView];

上記のように書き換えると、画面は拡大に耐えられるぐらいに綺麗になる。

要点は以下のとおり。

  • iOS4.0からUIGraphicsBeginImageContextWithOptionsという関数が利用できる
  • UIGraphicsBeginImageContextWithOptionsはCGSize size, BOOL opaque, CGFloat scaleという3つの引数を持つ
  • scaleに指定した数字がビットマップの倍率になる。例えばsizeに(320.0, 240.0)scaleに2.0を指定すると、実際には(640.0, 480)のビットマップを生成する
  • scaleに0.0を指定すると、デバイスのメインスクリーンと同じ倍率になる。
  • 上記詳しくはUIKit Function ReferenceのUIGraphicsBeginImageContextWithOptionsを参照。

つまり、Retinaディスプレイでも対応できるよう「〜@2x.png」というファイル名の画像を作る時と同じことを、コーディング中にやっている。例えば、UIGraphicsBeginImageContextWithOptions(CGSizeMake(320.0, 240.0), NO, 0.0);というコードをRetina環境で実行すると、サイズが640×480の、背景が透過してる画像が生成される。

追記

2013/01/04 1:08
ハードコーディングしていたところを修正しました。
ありがとうございます >@sgssさん

関連書籍

Pocket
LINEで送る
LinkedIn にシェア