いつもお世話になります。先日以下のような質問をさせていただきました者であります。
https://www.petitmonte.com/bbs/answers?question_id=3892
リンクようにキャプチャーを行っているのですがなかなか苦戦しております。そこで以下のような質問があります。
i) 上記の投稿と内容が重なってしまいますが、大きいサイズのbitmapを
高速に表示させる手段はないでしょうか??
ii) 今 タスクメニュー上からメニューを選んでキャプチャーさせているのですが、そのとき「タスクバーを自動的に隠す」を選択していてもタスクバーが表示され Sleep()しないとタスクバーまでキャプチャーされてしまいます。タスクバーを表示させない方法はありますでしょうか??
以上ご教授をよろしくお願いいたします。
>i)
再描画に関してだけは、他にも書きましたが
TCanvas.ClipRectで再描画が必要な部分だけを判断でき
高速化できます。
初回の表示は、大きければ時間がかかってしまうのは
仕方が無いと思います。
3200x1200x24bit とかのサイズなんですよね?
メインスレッドが固まるのを阻止したい とかそういうことであれば
方法はいろいろあります。
>ii)
h ttp://www.wwlnk.com/boheme/delphi/tips/tec0400.htm
全てのWindowsで 'Shell_TrayWnd' なのかは、謎です。
> 大きいサイズのbitmapを高速に表示させる手段はないでしょうか?
TBitmap.LoadFromFile() などを使って表示するぶんには特に無いと思います。
問題は「大きい」というのがどの程度のサイズを想定しているのか、
また、モニタに表示させる場合、実寸表示でスクロールを使用するのか、
それとも縮小表示して画像全体が収まるようにするのかなどにより知恵の使い方も変わってくるでしょう。
例えば実寸表示であれば、モニタに収まる分だけ読み込んで表示するという手もあり得ます。Exloler が、当面の表示に必用なフォルダだけ検索するのと同じ発想ですが。
やりたいことは分かりました。
こんな風にすればキャプチャ自体が不要です。
フォーカスを失ったときclose等もう少し手を加えてやってください。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormDblClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
procedure WMEraseBkGnd(var Msg: TMessage); message WM_ERASEBKGND;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormDblClick(Sender: TObject);
begin
Close;
end;
procedure TForm1.WMEraseBkGnd(var Msg: TMessage);
begin
Msg.Result:=0;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle:=bsNone;
FormStyle :=fsStayOnTop;
WindowState:=wsMaximized;
DoubleBuffered:=False;
end;
end.
fさん。さどやま さん。ママんさん。ありがとうございます。
>3200x1200x24bit とかのサイズなんですよね?
>問題は「大きい」というのがどの程度のサイズを想定しているのか
最大でも2048*768 ですね -> あくまでもデスクトップのキャプチャーですので・・・
>メインスレッドが固まるのを阻止したい とかそういうことであれば
現状は ApplicationのProcessMessage()を利用してますが 他にもよい手段はありますか??
>こんな風にすればキャプチャ自体が不要です。
キャプチャーソフトなどもこのような方法で実装しているのですかね??スピードがものすごく速いものもあるのでどうようにしているのかが 疑問なのですがね・・・
> 大きいサイズのbitmapを高速に表示させる手段はないでしょうか?
> 最大でも2048*768 ですね
私の環境では、TBitmap.LoadFromFile で 13ミリ秒です。
1秒間に4.6枚表示可能で、映画の1秒24コマには及びませんが、使っていただいているお客様からは「他のソフトより速い」という評価をいただいています。
「他のソフト」とは、デジタルカメラについてくるViewerのことですが。
ちなみに私の環境はCPU 2.66GHz, 空きメモリ 920MB, コンパイル Delphi7です。
速い・遅いは主観的な判断ですので、カレーライスさんの環境及び
自分のコードでの時間と「速い」というソフトでの時間とを示してもらわないと
論評は困難です。
後者についてはストップウォッチをお持ちでないと計測困難でしょうが。
速いソフトがフリーソフトであれば名称も知りたいところです。
こちらでも比較テストができますので。
> キャプチャーソフトなどもこのような方法で実装しているのですかね??
カレーライスさんの言って見えることが私には今ひとつ見えません。
まさかとは思いつつも正直、ママんさんが書かれたような意味ではないかとも思ったりしました。
> タスクメニュー上からメニューを選んでキャプチャーさせているのですが
「タスクメニュー」の意味が解りません。
当然「メニューを選んでキャプチャー」も、例えばどういうメニューとどういうメニューがあるのか想像がつきません。
> そのとき「タスクバーを自動的に隠す」を選択していても
コードからタスクバーを hidden にしているのか、PCでそのように設定しておいてからアプリを実行しているのか定かでありません。
Sleep()するとタスクバーをキャプチャーしないのだからコードからでしょうが。
これは単にタイミングの問題で、モデルがポーズを取り終わらないうちにシャッターを押してしまっているわけで、画像処理に関わらず起こりうる問題です。
例えば動的に表示されるウィンドウのサイズや位置を取得する場合でも、SHBrowsForFolderのようにインスタンス作成にもたつくオブジェクトの場合には同様な対処が必用になります。
> Sleep()しないとタスクバーまでキャプチャーされてしまいます
なぜタスクバーまでキャプチャーされると困るのか解りません。
余計なお世話のようですが、実際にはいくら必用なのか教えてもらえずにただ金を借してくれと言われている感じです。
つまり、何をキャプチャしたいのか解らないのです。
例えば、タスクバー以外のデスクトップ領域だけをキャプチャしたいのであればそのような方法がありますが、「ひょっとしたらこうではないか」といろいろ推測しながらダメ元で意見を出すのは疲れます。このサイトはクイズではないのですから。
率直に何を実現したいのか具体的に教えていただいたほうが Res も的確に得られると思います。
> スピードがものすごく速いものもあるのでどうようにしているのかが 疑問なのですがね
キャプチャー自体の所要時間も問題にしてみえるのですね。
私もWMV3映像の連続キャプチャアプリを作ったばかりで大変興味があります。
私の環境と私の能力では1秒間に7から8枚のキャプチャが限界でした。
ぜひソフト名と、フリーなら入手方法を知りたいところです。
実は、あまり作りたいものが見えてこないのですが、
コントロールの描画イメージを取り込みたいだけなのであれば、
デスクトップ全てをキャプチャーしなくても OleDrawなどで
イメージが拾えます(子に対してもやらないといけないものが一部あります)
>メインスレッドが固まるのを阻止したい とかそういうことであれば
> 現状は ApplicationのProcessMessage()を利用してますが
TThreadを使ったマルチスレッドか、
別アプリケーションで共有メモリを使って
マルチプロセスにするとか。
sadoyamaさん。アドバイスありがとうございます。
>当然「メニューを選んでキャプチャー」も、例えばどういうメニューとどういうメニューがあるのか想像がつきません。
「WinShot」というキャプチャーソフトをご存知でしょうか??こちらのソフトはキャプチャーのメニューをすべて タスクトレイ上からポップアップメニューで処理をするようにしています。
>タスクバー以外のデスクトップ領域だけをキャプチャしたいのであれば
まさにそのとおりです。
>率直に何を実現したいのか具体的に教えていただいたほうが Res も的確に得られると思います。
はい。以下のような処理を実現したのですが、それらの処理を高速にしたいと考えています。
前準備としてダミー用のフォームにTImageを準備しています。
i) タスクメニューを選択されたら、タスクバー以外のデスクトップ領域だけをキャプチャを行い、それをダミー用フォームに貼り付けて、デスクトップで表示させる
ii) ダミー用のフォームが表示されたら 任意の矩形領域を選択(ドラッグしながら領域選択)してその部分をファイルに保存するということをしています。
特にi)の処理を速くしたいと思います
>ぜひソフト名と、フリーなら入手方法を知りたいところです。
WinShotというフリーソフトでかなり有名です。このソフトを利用して頂いたら、特に「矩形範囲選択」などのメニューが非常にスムーズだと思っています。
WinShot と同じでは芸がないので、WinShot の不足/扱い方など、
何を改善しようとしているのですか?
>何を改善しようとしているのですか?
特に何かをということはありません。ただ 大きいサイズのイメージを表示させた場合に いろんなキャプチャーソフトのように高速表示できないかと疑問に思ったのです。
(1) WinShot 使ってみました。
1.キャプチャ速度
私が公開している Crop30 と比較し特に速いとは思いませんでした。
スクリーンキャプチャとしては、普通に作成すればこの程度の速度になるものだと思います。
2.タスクバー以外のデスクトップ領域だけをキャプチャしたい
HISTORY v1.53
ポップアップメニューからアクティブウィンドウをキャプチャする際、タスクバーをキャプチャ対象としないようにした。
と WinShot のホームぺージに書かれていますが、意味が解りませんでした。
タスクバー(これもウィンドウの一つですから)以外のウィンドウがアクティブであれば、タスクバーまでキャプチャするはずがないのですが。
いずれにせよデスクトップをキャプチャする場合にはタスクバーも入るようですね。私のもそうなっています。
ヘルプがわかりにくいのでこれ以上触る気はありませんが、これだけの機能を詰め込めば、プロジェクトよりヘルプの作成のほうが大変でしょう。
(2)タスクバー以外のデスクトップ領域だけをキャプチャする
Windows の DC はどのみち全スクリーンを保持しています。
そこからキャプチャしたい範囲をRect指定してTBitmapなどにコピーし、それを画面表示するのがキャプチャソフトの常套手段です。
アクティブウィンドウだけならアクティブウィンドウの座標で切り取ればよく、タスクバー以外のデスクトップ部分を得たければその座標を得ればできます。
procedure GetDeskTopWorkRect(var DeskTopRect: TRect);
begin
SystemParametersInfo(SPI_GETWORKAREA, 0, @DesktopRect, 0);
end;
> 「矩形範囲選択」などのメニューが非常にスムーズ
私の場合、ピクセル単位で簡単に切り取れるものが欲しかったので自作しました。Windowsプログラミングを始めた理由でもあります。
処女作ですので、今から考えればよく作れたと思いますが、見よう見真似で書いたコードの意味がやっと解りかけてきた今日この頃です。
私のPC(ScreenSize 1024*768)での結果例 Top=0, Lef=0, Right=1024, Bottom=740
通常どおり、タスクバーは画面下に配置されている。
> WinShot と同じでは芸がないので
やはり、タスクバーを除いたデスクトップ領域のキャプチャがWinShortではできない、その機能が欲しいということですかね。
> 大きいサイズのイメージを表示させた場合に
> いろんなキャプチャーソフトのように高速表示できないかと疑問に思ったのです。
キャプチャは、元々メモリ上にWindowsが管理している画像データをユーザメモリにコピーして表示するわけですから、ディスクから読み込んで表示する場合では太刀打ちできるわけがありません。新幹線と自転車の違いくらいあるのではないでしょうか。
また、ビットマップの場合、ディスク上のデータは相当数のフォーマットが存在しうるのでそのチェックを済まさないと次に進めません。
更に圧縮データの場合もありその場合事前に解読の時間も必要になります。
特定のフォーマット形式だけをターゲットにする場合なら、Delphi VCL を使わずに、場合によっては Windows API もほとんど使わずに高速化できるでしょうが、ハード部分での読み取り速度だけはソフトからは如何ともしがたいところです。
> 大きいサイズのイメージを表示させた場合に
> いろんなキャプチャーソフトのように高速表示できないかと疑問に思ったのです。
もっと具体的に教えてあげないと意味無いと思います。
まず、WinShot試してみたけど、
うちのデュアルディスプレイでは、それなりに遅かったです。
1600x1200でも、驚くほど早くはありませんでした。
これなら、普通に、bitbltするだけで、この速度は出せますよ。
次に、
Delphiでいう TFormで
BorderStyle=bsNone,FormStyle=fsStayOnTop, WindowState=wsMaxmized
にイメージを描画する時ですが、
マウスドラッグで、枠を描画した時、時間かかります?
これが重いって言うなら、TImageで無駄な描画イベントが
たくさん走っているんだと思います。
こうなると TImageを使うのはかえってめんどくさいです。
ので、TFormのOnPaintで
TForm.Canvas.Handleにbitbltで直接描画したほうが良いと思います。
TFormに描画する場合もWM_ERASEBKGNDで、フォーム自体の背景塗りつぶしを
無効にし、(前述のママんさんが書いた方法でできます)
1番最初の描画は、全体(Screen.Width, Screen.Height)を使って
キャプチャー下画像を、フォーム全体に描画し
2回目以降は、前述したようにTCanvas.ClipRectで位置と幅を求め描画します。
枠自体は、Pen.Mode =pmNot(同じ位置に2回描画すると、元に戻る)
で1サイクルずらして2回ずつ組で描画するか、
枠を描く前に、枠が描かれる位置の画像をTBitmapに入れておいてそれで枠を
描く前に、古い枠を消すか
などが考えられます。
タスクバーはもう消せますよね?
私も消すより、高さを引くべきだと思いますが、
でも、タスクバーは下にあるとは限らず、左にあったり上にあったりも
しますから、消したほうが楽かもしれませんね
sadoyama さどやまさん。fさん。ありがとうございます。
ご丁寧なアドバイスを参考にしてあとは自分で解決していきたいと思います。あとはアドバイスを元に考えていきます。
>マウスドラッグで、枠を描画した時、時間かかります?
いえ これはほとんど時間がかかってないと思います。
>タスクバーはもう消せますよね?
はい。無事消すことができました。
また何かありましたらよろしくお願いします。
ツイート | ![]() |