UIWebView の表示内容を UIImage にして、表示する方法です。UIWebView を表示させずに、指定した URL のページ内容をレンダリングして UIImage を生成して、UIImageViw に表示します。スクリーンショットだけを取りたいときに使えます。

UIWebView はインスタンスを生成しただけでは、URL をロードしてもレンダリングされません。レンダリングするには UIWindow 内になければダメです。そのために実際には表示しない UIWindow を作成して、その中に addSubview します。

UIWebView のデリゲートメソッド webViewDidFinishLoad: でロード終了の通知を受けてから、UIWebView のレイヤーの内容を UIImage に書きだします。

- (void)viewDidLoad {
  [super viewDidLoad];

  // 表示する UIImageView を生成
  self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 90, 200, 300)];
  [self.view addSubview:imageView];

  // UIWebView 用の表示しない UIWindow を生成
  self.offscreenWindow = [[UIWindow alloc] initWithFrame:self.view.bounds];

  // UIWebView を表示しない UIWindow に生成
  NSURL* url = [NSURL URLWithString:@"http://www.yahoo.co.jp/"];
  self.webView = [[[UIWebView alloc] initWithFrame:imageView.bounds] autorelease];
  webView.delegate = self;
  webView.scalesPageToFit = YES;
  [offscreenWindow addSubview:webView];
  [webView loadRequest:[NSURLRequest requestWithURL:url]];
  isRendering = YES;
}

- (void) webViewDidFinishLoad:(UIWebView *)webView {
  if (isRendering) {
    isRendering = NO;
    // UIWebView の描画は別スレッドで行われ、
    // 描画完了前にこのメソッドが呼ばれるので
    // UIImage への描画処理は遅らせて実行する
    [self performSelector:@selector(renderWebContent) withObject:nil afterDelay:1.0];
  }
}

- (void) renderWebContent {
  UIGraphicsBeginImageContext(imageView.bounds.size);
  [webView.layer renderInContext:UIGraphicsGetCurrentContext()];
  imageView.image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  [webView removeFromSuperview];
  webView.delegate = nil;
}

実行結果は以下のようになります。
スクリーンショット(2010-05-20 5-20木 13.24.26)

注意点は UIWebView のレンダリング処理は別スレッドで非同期に行われるため、webViewDidFinishLoad: の通知の時にすぐに UIImage への書き出し処理を実行すると不完全なページになってしまいます。上記コードの 27行目を下記のように変更してすぐに書き出し処理すると不完全なページになってしまいます。

[self renderWebContent];

スクリーンショット(2010-05-20 5-20木 13.28.42)

関連する投稿