トップ回答者
CreateDIBSectionなどで大きな画像を作りたい

質問
-
CreateDIBSectionで大きな画像を作りたい
VS2010 MFC を使っています。同じようなタイトルのResあったのですが解決策が無かったので上げました。
初めCreateCompatibleBitmapでBitmapを作っていたのですが、Windows10では少しでも大きな画像だと
エラーになったので、CreateDIBSectionを使っていました。今回CreateDIBSectionでもかなり大きな画像だとやはりエラーになる事が判りました。
メモリが少ない環境でも大きなBitmapを作成できる方法がありましたらご教授お願いします。(ファイルに落とすような方法でも結構です)
なぜ大きな画像が必要かと言うと、小説のような文書を横長に描画した画像を作り、スクロールで見せるような事をする為です。
実際に CreateDIBSectionを使っている部分のソースを添付します。
画像サイズは現在テストしている画像の最大サイズです。BITMAPINFO bmpinfo; ZeroMemory(&bmpinfo, sizeof(bmpinfo)); bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.bmiHeader.biWidth = 500000; // サイズ bmpinfo.bmiHeader.biHeight = 3000; // bmpinfo.bmiHeader.biPlanes = 1; // bmpinfo.bmiHeader.biBitCount = 32; // 32ビットカラー bmpinfo.bmiHeader.biBitCount = 8; bmpinfo.bmiHeader.biCompression = BI_RGB; _hBmp = CreateDIBSection( NULL, &bmpinfo, DIB_RGB_COLORS, NULL, NULL, NULL);
よろしくお願いいたします。
回答
-
1.>メモリが少ない環境でも大きなBitmapを作成できる方法がありましたらご教授お願いします。
2.>小説のような文書を横長に描画した画像を作り、スクロールで見せるような事をする為です。他の方の発言にあるとおり、1.実現する方法は「ありません」。
さて、実現したいのが2.であれば、3.画像を複数に分割して、必要なな場所に連結して表示する方法
が適切と言えます。
ありがとうございました。
今のところ3に近い方法を検討しています。
こんな感じで試してみようと思っています。
横が固定値ではなく、縦は1500px程度の固定の縦書き文書ですので、とりあえず横は表示ウィンドウサイズ、縦は1500pxの画像を作り、その中に現在のページを描画、縦スクロールは縦位置を変えてBitBlt画面、 横スクロールは、BitBltで1行分ずらして画像描画し、新たに表示される1行分をTextOutで描画する。
(表示される行に制限はないですが、利用目的からは多くて5000行程度と言われています)
- 回答としてマーク Freeプログラマー 2017年7月26日 12:38
すべての返信
-
そのまま実現する方法はありません。
何枚かに分割して必要になったらファイルから読み出してメモリに上げるといったことを自分で実装することになります。- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月25日 0:15
-
最近の Visual Studio は GDI ではなく、DirectWrite で描画しているはずです。
ただし、実装の詳細は明らかにされていません。なお、「スムーズなスクロール」は主観が入るので、伝わりません。
普通に実装するとどういうコードになり、どういう現象が発生するのか具体的な話にならないと、フォーラムで解決できる問題だったとしても解決しません。- 編集済み AzuleanMVP, Moderator 2017年7月24日 22:02
-
1.>メモリが少ない環境でも大きなBitmapを作成できる方法がありましたらご教授お願いします。
2.>小説のような文書を横長に描画した画像を作り、スクロールで見せるような事をする為です。他の方の発言にあるとおり、1.実現する方法は「ありません」。
さて、実現したいのが2.であれば、3.画像を複数に分割して、必要なな場所に連結して表示する方法
が適切と言えます。
これは、3.の方法は出力するサイズが一定なら、描画量が常に一定と見積もれるため、
一般に、全体画像のサイズが大きいほど1.の方法より有利になります。>VisualStudioのエディタなどは数千行でもスムーズにスクロールしているので、 どうゆう作りになっているのでしょう?
私が作成したエディタもキーワード色分けして描画しています。
単にGDIのTextOut()を使っているだけですが、VSのエディタと速度的に大差ありません。
描画関数はユーザーに見えない部分は描画しませんので、せいぜい数十行しか描画しないわけです。
この程度の行数では速度的な差は出ないわけですね。
また、スクロールで即座に表示しなければならないため、表示範囲の前後だけはメモリーにバッファしますが、
ファイルの全ては読み込みません。必要になったらファイルからロードしてます。
HDD、システム、およびCPUなどのキャッシュが効きますのでこれでも遅いという感じはしません。
プログラマにとっては、とっても楽チンな世界になったと感じてます。- 編集済み 仲澤@失業者 2017年7月25日 1:44
-
1.>メモリが少ない環境でも大きなBitmapを作成できる方法がありましたらご教授お願いします。
2.>小説のような文書を横長に描画した画像を作り、スクロールで見せるような事をする為です。他の方の発言にあるとおり、1.実現する方法は「ありません」。
さて、実現したいのが2.であれば、3.画像を複数に分割して、必要なな場所に連結して表示する方法
が適切と言えます。
ありがとうございました。
今のところ3に近い方法を検討しています。
こんな感じで試してみようと思っています。
横が固定値ではなく、縦は1500px程度の固定の縦書き文書ですので、とりあえず横は表示ウィンドウサイズ、縦は1500pxの画像を作り、その中に現在のページを描画、縦スクロールは縦位置を変えてBitBlt画面、 横スクロールは、BitBltで1行分ずらして画像描画し、新たに表示される1行分をTextOutで描画する。
(表示される行に制限はないですが、利用目的からは多くて5000行程度と言われています)
- 回答としてマーク Freeプログラマー 2017年7月26日 12:38
-
ビットマップをロードして描画するのではなく、重いフォントや手順が複雑な
TextOut()が主たる描画であるならば、いわゆる「ダブルバッファ」や「裏バッファ」、
「メモリーDC」と呼ばれる方法を選択すべきかもしれません。
これは、1.描画更新が必要なユーザーアクションが発生。
2.描画位置の算定。
3.「裏バッファ」に描画。
4.更新対象のHWNDに対してInvalidateRect(全て)、必要ならUpdateWindow()を発行。
5.OnPaint()または、OnDraw()コールバックにて、PaintDCに、裏バッファをBitBlt()という手順です。
裏バッファは、CDC又はHDCで、下記の手順であらかじめ静的に構築しておきます。1.HWNDに対してGetDC()又はCWindowDCを取得(オーナーのDCとする)
2.上記に対してコンパチブルなDCを、CreateCompatibleDC()で作成する。
3.オーナーのDCに対してコンパチブルなBMPを、
クライアント矩形(又はデスクトップ)サイズで作成(コンパチブルBMPとする)。
4.上記コンパチブルBMPをコンパチブルなDCにSelectObject()。この方法は、WM_PAINT発生時にはBitBlt()が1回発生するだけなのでちらつきが少ないわけです。
本方法を使う場合、WM_ERASEBKGNDで背景塗りつぶしをスルーするのを忘れずにやりましょう。
OnSizeで、裏バッファのサイズを変更しなければなりませんので、この時は遅いですね。
可能であればCS_SIZEREDRAWやCS_CLIPCHILDREN等の無駄なクラススタイルもとってしまう方が描画が早いです。
CViewのOnDraw()がもっさりしてしまう原因のひとつがこれですね。- 編集済み 仲澤@失業者 2017年7月25日 4:47
-
ビットマップをロードして描画するのではなく、重いフォントや手順が複雑な
TextOut()が主たる描画であるならば、いわゆる「ダブルバッファ」や「裏バッファ」、
「メモリーDC」と呼ばれる方法を選択すべきかもしれません。
ご回答ありがとうございます。
もともとメモリ描画のためにBitmapを作成して それにTextOutし、BitBltで画面表示してました。
今回Bitmapあまりにも大きくなりすぎたのでいろいろ検討してました。
とりあえず画面と同じ幅のBitmapを2枚作成して、画面転送用と、横スクロールでズラしその上に文字を描画する用に使用し、2枚を上手く使い回すよう進めています。 上手く行きましたらまた上げます。