Qt最新事情-QtでWebKitを使ってみよう

第5回 Qt WebKit~ブラウザ機能の基本

この記事を読むのに必要な時間:およそ 11 分

Webページのレンダリング結果を画像で保存する

GUI機能を用いずQt WebKitの機能のみでWebベースのユーティリティプログラムを作成してみましょう。表3に挙げたQt WebKit関連のクラスの中で,ウィジェットを継承するクラスはQWebViewのみとなっています。Webページを構成するWebフレームのQFrame::load(const QUrl&)でURLを読み込めるようになっていて,QFrame::render()は引数にQPainterを取るようになっていることに注目しましょう。つまり,ウィジェットがなくともWebアクセスをしてHTMLをレンダリングできるのです。

QWebPageのリファレンスマニュアル に,URLを指定してレンダリングをし,その結果を画像ファイルとして保存するコードが載っています。このコードを元にして次のようにして使うコマンドを作りましょう。

$ render url [スケール]

このコマンドを実行すると指定したURLのWebページをレンダリングし,その結果が画像ファイルとしてthumbnail.pngに保存されます。デフォルトのスケールは1.0で,0.5ならば1/2に縮小され,2.0ならば倍に拡大されます。

リスト6が実装コードです。行を追って説明します。

リスト6 render.cpp

01: #include <QtGui>
02: #include <QtWebKit>
03: 
04: class Thumbnailer : public QObject

Webページへのアクセスは,ネットワークを含めてQtのイベントループの中で行われ,シグナルによって処理状況が通知されるので,QObjectを継承したクラスを用いています。

05: {
06:     Q_OBJECT
07: 
08: public:
09:     Thumbnailer( const QUrl& url, double scale = 1.0 );
10: 
11: signals:
12:     void finished();

新たに追加したシグナルでWebページをロードし,画像ファイルとして保存が完了したときに送信されます。

13: 
14: private slots:
15:     void render();

QWebPageでのロードが完了したときに呼び出す処理スロットです。

16: 
17: private:
18:     QWebPage page;
19:     double scale;
20: };
21: 
22: Thumbnailer::Thumbnailer( const QUrl& url, double scale )
23:     : scale( scale )
24: {
25:     page.mainFrame()->load( url );
26:     connect( &page, SIGNAL( loadFinished( bool ) ), this, SLOT( render() ) );

Webページpageのメインフレームに指定されたURLを渡してロードしています。レンダリング終了はQWebPageのシグナルloadFinished(bool) でわかるので,このシグナルをスロットrender()に接続してすれば,ロードしたWebページを扱えます。

27: }
28: 
29: void Thumbnailer::render()
30: {
31:     page.setViewportSize( page.mainFrame()->contentsSize() );

QWebPageのビューポート(表示領域)のサイズを,QWebPageのメインフレーム(最外部のフレーム)のサイズと同じにします。

32: 
33:     QImage image( page.viewportSize(), QImage::Format_ARGB32 );

ラスターイメージデータQImageをQWebPageのビューポートと同じサイズで用意します。

34: 
35:     QPainter painter( &image );
36:     page.mainFrame()->render( &painter );
37:     painter.end();

Qtの2D描画機能を使うには,描画対象オブジェクトに対してQPainterのインスタンスを作成して,その描画機能を呼び出して使います。ここでは,そのインスタンスをQWebFrame::render() に渡して,QWebFrame内で描画をさせています。

38: 
39:     QImage thumbnail;
40:     if ( scale == 1.0 ) {
41:         thumbnail = image;
42:     } else {
43:         QSize size = page.viewportSize() * scale;
44:         thumbnail = image.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
45:     }
46: 
47:     thumbnail.save( "thumbnail.png" );
48: 
49:     emit finished();

スケーリングした画像を格納するためにQImageのデータthumbnailを用いています。スケールが1.0のときにthumbnailにimageを代入していますが,QImageは暗黙の共有クラスですから画像データ全体がコピーされず,imageと画像データが共有されます。スケールが1.0でないときには,QImage::scaled()を用い,Qt::SmoothTransformationを指定してスケーリング結果が滑らかになるようにしています。そして,QImage::save()で画像ファイルを保存し,処理が完了したことをシグナルfinished()で送信します。

50: }
51: 
52: int main( int argc, char** argv )
53: {
54:     QApplication app( argc, argv );
55: 
56:     QUrl url = QUrl( "http://trolltech.com" );
57:     double scale = 1.0;
58: 
59:     switch ( argc ) {
60:     case 2:
61:         url = argv[1];
62:         break;
63:     case 3:
64:         url = argv[1];
65:         scale = QString( argv[2] ).toDouble();
66:         break;
67:     }
68: 
69:     Thumbnailer thumbnailer( url, scale );
70: 
71:     QObject::connect( &thumbnailer, SIGNAL( finished() ), &app, SLOT( quit() ) );

コマンドラインで指定したURLのレンダリングが完了したならば,イベントループから抜けてプログラムを終了させるために,Thumbnailerのシグナルfinished()をQApplicationのスロットquit()に接続しています。

72: 
73:     return app.exec();
74: }
75: 
76: #include "render.moc"

著者プロフィール

杉田研治(すぎたけんじ)

1955年生まれ。東京都出身。株式会社SRAに勤務。プログラマ。

仕事のほとんどをMac OS XとKubuntu KDE 4でQtと供に過ごす。