気楽なソフト工房

プログラミングについていろいろな記事を書いています。



mykonos2008

Author:mykonos2008
システムエンジニアとして働いている30代の会社員です。
仕事や趣味でプログラムを書いている方の役に立つ記事を書いていきたいと思っています。
ご意見、ご感想はこちらまで
If you are an english speaker,Please visit my english blog.

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
前回のWPF Tipsで「URLの画像を表示する」方法を紹介しました。

「前回のコード」
   Image image = new Image();
   BitmapImage imageSource =  new BitmapImage(new Uri(画像のURL));
   image.Source = imageSource;

この方法で簡単にURLで指定された画像を画面に表示することが可能になりますが、
一点問題があります。この方法を用いた場合、画像のダウンロードがUIスレッドによって
行われるため、画面にたくさんの画像を表示したい場合などは、全部画像が表示されるまで
かなりの時間がかかってしまいます。

以下は現在私が開発中のYoutubeの動画を閲覧するソフトの画面ショットですが、
前回の方法では、ダウンロードが遅すぎてユーザが待てない感じになってしまいました。



そこで前回のコードを以下のように変更してみました。

   Image image = new Image();

   //スレッドプールのスレッドを利用する
   ThreadPool.QueueUserWorkItem(new WaitCallback((Object parameter) =>
       {
           try
           {
               Uri uri = new Uri(imageUrl);

               using (WebClient web = new WebClient())
               {
                   using (BufferedStream imgData = new BufferedStream(web.OpenRead(uri)))
                   {
                       using (MemoryStream memory = new MemoryStream())
                       {
                           //1バイトずつ読み取り、メモリに書いていく
                           int data = -1;
                           while ((data = imgData.ReadByte()) != -1)
                           {
                               memory.WriteByte((byte)data);
                           }

                           //最初に戻る
                           memory.Seek(0, SeekOrigin.Begin);

                           //メモリストリームからBitmapを作成する
                           BitmapImage bi = new BitmapImage();
                           bi.BeginInit();
                           bi.StreamSource = memory;
                           bi.EndInit();

                           //変更付加にする
                           bi.Freeze();

                           //UIスレッドをコールし、ImageにBitmapを設定する
                           Dispatcher.BeginInvoke(new Action(() =>
                           {
                               try
                               {
                                   image.Source = bi;
                                   image.Width = bi.PixelWidth;
                                   image.Height = bi.PixelHeight;
                               }
                               catch { }

                           }), DispatcherPriority.Normal);
                       }
                   }
               }
           }
           catch (Exception e) { Console.WriteLine(e); }

       }), null);

スレッドプールのスレッドを利用して、バックグラウンドで画像をダウンロードするように
変更しました。

WebClientでURLに接続し、ダウンロードしたデータをMemoryStreamを利用して、一旦メモリに
保存し、そのデータからBitmapImageを生成しています。

これにより格段にダウンロード処理が早くなりました!!

余談ですが、WaitCallbackデリゲートやActionデリゲートに渡す匿名メソッドの中で
それぞれ、try~catchをするようにしています。これはそれぞれが別の処理単位として
スレッドに渡されるので、その中で例外が発生し、スレッドがとんでしまうの防止するためです。

コメント

よいアプローチだと思いますが、画像によってはうまく表示されないものがあるようです。
http://www.google.co.jp/intl/ja_jp/images/logo.gif
などはDLはできるんですが、表示されません。何か別に設定が必要なのでしょうか?

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://csfun.blog49.fc2.com/tb.php/76-70e3f6f7

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。