2011-12-09 4 views
11

WPFアプリケーションをドロップターゲットにして、任意のWebページからイメージをドラッグできるようにします。WebページからWPFウィンドウにドラッグされたイメージを受け取る

イメージがWebページからドラッグされると、明らかに「DragImageBits」形式になります。この形式は、デシリアライズしてShDragImageと入力できます。 (私が定義した方法についての質問の最後を参照してください)

これをWPFイメージに変換するにはどうすればよいですか?

これは私の現在の試みです。メッセージは、単にであると、私はタイプSystem.Runtime.InteropServices.ExternalExceptionの例外を取得します。この時点で

private void UserControl_Drop(object sender, System.Windows.DragEventArgs e) 
    { 

      string[] formats = data.GetFormats(); 

      // DragImageBits 
      if (formats.Contains("DragImageBits")) 
      { 
      MemoryStream imageStream = data.GetData("DragImageBits") as MemoryStream; 

      // Now I'm deserializing this, the only way I know how 
      imageStream.Seek(0, SeekOrigin.Begin); 
      BinaryReader br = new BinaryReader(imageStream); 

      ShDragImage shDragImage; 
      shDragImage.sizeDragImage.cx = br.ReadInt32(); 
      shDragImage.sizeDragImage.cy = br.ReadInt32(); 
      shDragImage.ptOffset.x = br.ReadInt32(); 
      shDragImage.ptOffset.y = br.ReadInt32(); 
      shDragImage.hbmpDragImage = new IntPtr(br.ReadInt32()); 
      shDragImage.crColorKey = br.ReadInt32(); 


      var systemDrawingBitmap = System.Drawing.Bitmap.FromHbitmap(shDragImage.hbmpDragImage); 

(誰でもdesirializationを行うための正しい方法を知っている場合、私はすべての耳です)。

私は何をすべきか知っていますか?


次に、サポートするクラスの定義を示します。 this blog entryからコピーしました。

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    public struct Win32Point 
    { 
     public int x; 
     public int y; 
    } 

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    public struct Win32Size 
    { 
     public int cx; 
     public int cy; 
    } 

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    public struct ShDragImage 
    { 
     public Win32Size sizeDragImage; 
     public Win32Point ptOffset; 
     public IntPtr hbmpDragImage; 
     public int crColorKey; 
    } 

答えて

15

は、ここで私が学んだことです:

「DragImageBitsは、」シェルウィンドウによって提供され、そして唯一のドラッグカーソルのためではなく、最終的なデータのためのものです。シェルは、サイズ変更と透明度を使用してイメージを適切なドラッグカーソルに変換します。例えば

、あなたはこのイメージドラッグした場合:あなたは本当にSHDRAGIMAGEから画像を抽出したい場合は、

enter image description here

Fully Opaque Image

をSHDRAGIMAGEは、このようにレンダリングされますここにコードがあります。 (一部this answerから持ち上げ)

 MemoryStream imageStream = data.GetData("DragImageBits") as MemoryStream; 
     imageStream.Seek(0, SeekOrigin.Begin); 
     BinaryReader br = new BinaryReader(imageStream); 
     ShDragImage shDragImage; 
     shDragImage.sizeDragImage.cx = br.ReadInt32(); 
     shDragImage.sizeDragImage.cy = br.ReadInt32(); 
     shDragImage.ptOffset.x = br.ReadInt32(); 
     shDragImage.ptOffset.y = br.ReadInt32(); 
     shDragImage.hbmpDragImage = new IntPtr(br.ReadInt32()); // I do not know what this is for! 
     shDragImage.crColorKey = br.ReadInt32(); 
     int stride = shDragImage.sizeDragImage.cx * 4; 
     var imageData = new byte[stride * shDragImage.sizeDragImage.cy]; 
     // We must read the image data as a loop, so it's in a flipped format 
     for (int i = (shDragImage.sizeDragImage.cy - 1) * stride; i >= 0; i -= stride) 
     { 
      br.Read(imageData, i, stride); 
     } 
     var bitmapSource = BitmapSource.Create(shDragImage.sizeDragImage.cx, shDragImage.sizeDragImage.cy, 
                96, 96, 
                PixelFormats.Bgra32, 
                null, 
                imageData, 
                stride); 

あなたはそれが(ドラッグイメージとして)目的を意図していますためDragImageBitsを利用したい場合は、簡単な、ダウンロード可能な例えばthis blogを参照してください。


"DragImageBits"は、ウェブページからドラッグされた画像を受け入れるという、実際の問題からかなり離れていました。

Firefox、Chrome、IE9はすべて異なるフォーマットを提供するため、Webページから画像をドラッグすると複雑になります。また、画像と画像のハイパーリンクの両方を処理したい場合は、これらの処理を別の方法で再度行います。

GoogleとFirefoxは「text/html」形式を提供しています。この形式では、画像として1つのHTML要素が得られます。 GoogleはあなたにASCII文字列としてそれを渡し、FirefoxはUnicode文字列としてあなたにそれを与えます。だからここに私はそれを処理するために書いたコードです:

 System.Windows.IDataObject data = e.Data; 
     string[] formats = data.GetFormats(); 


     if (formats.Contains("text/html")) 
     { 

      var obj = data.GetData("text/html"); 
      string html = string.Empty; 
      if (obj is string) 
      { 
       html = (string)obj; 
      } 
      else if (obj is MemoryStream) 
      { 
       MemoryStream ms = (MemoryStream)obj; 
       byte[] buffer = new byte[ms.Length]; 
       ms.Read(buffer, 0, (int)ms.Length); 
       if (buffer[1] == (byte)0) // Detecting unicode 
       { 
        html = System.Text.Encoding.Unicode.GetString(buffer); 
       } 
       else 
       { 
        html = System.Text.Encoding.ASCII.GetString(buffer); 
       } 
      } 
      // Using a regex to parse HTML, but JUST FOR THIS EXAMPLE :-) 
      var match = new Regex(@"<img[^/]src=""([^""]*)""").Match(html); 
      if (match.Success) 
      { 
       Uri uri = new Uri(match.Groups[1].Value); 
       SetImageFromUri(uri); 
      } 
     } 

この場合は、正規表現はストレート画像とハイパーリンクの両方を処理します。

そして、私のSetImageFromUri機能:あなたは "FileDrop" フォーマットを扱うことができるIE9について

private void SetImageFromUri(Uri uri) 
    { 
     string fileName = System.IO.Path.GetTempFileName(); 
     using (WebClient webClient = new WebClient()) 
     { 
      webClient.DownloadFile(uri, fileName); 
     } 
     using (FileStream fs = File.OpenRead(fileName)) 
     { 
      byte[] imageData = new byte[fs.Length]; 
      fs.Read(imageData, 0, (int)fs.Length); 
      this.ImageBinary = imageData; 
     } 
     File.Delete(fileName); 
    } 

。これはIE9でうまくいきます。 Chromeはそれをサポートしていません。 Firefoxはそれをサポートしていますが、イメージをビットマップに変換し、透明ピクセルを黒に変換します。このため、「text.html」形式が利用できない場合は、「FileDrop」形式のみを処理する必要があります。

else if (formats.Contains("FileDrop")) 
    { 
     var filePaths = (string[])data.GetData("FileDrop"); 
     using (var fileStream = File.OpenRead(filePaths[0])) 
     { 
      var buffer = new byte[fileStream.Length]; 
      fileStream.Read(buffer, 0, (int)fileStream.Length); 
      this.ImageBinary = buffer; 
     } 
    } 

IE9から画像ハイパーリンクをドラッグすると、「FileDrop」形式は提供されません。 IE9のイメージハイパーリンクからイメージコントロールにイメージをドラッグする方法はわかりません。


追加情報

この例を使用しますが、静止画には、このバイナリデータを変換する必要がある場合は、ここで便利なコードスニペットです:

   BitmapImage sourceImage = new BitmapImage(); 
       using (MemoryStream ms = new MemoryStream(imageBinary)) 
       { 
        sourceImage.BeginInit(); 
        sourceImage.CacheOption = BitmapCacheOption.OnLoad; 
        sourceImage.StreamSource = ms; 
        sourceImage.EndInit(); 
       } 
+0

私がいます同じ問題 - 私は、FirefoxとIE9の両方でDevice Independent Bitmap(DIB)フォーマットも提供することを発見しました。これが利用可能な場合、WebClientを使用してファイルをダウンロードする必要はありません。これは、わかりやすい(ビットマップ)形式でファイルにアクセスできるためです。 Firefoxでも 'FileDrop'形式が公開されていますが、htmlを解析してfiledrop形式を使用すると、必ずしも画像ではないオブジェクトをダウンロードすることができます – funseiki

+3

これは私を大きく助けます。投稿していただきありがとうございます。正規表現は多くの有効な画像リンクと一致しません。私は@ "] + src =" "([^" "] *)" ""が少し良く機能することを発見しました。 –

+0

あなたは本当の命を救う人です。私のような他の人がGoogle画像から直接画像をドラッグしたい場合は、「データ」で始まる場合はUriStringをチェックします。これらの文字列には既にデータが含まれているので、[この質問](http ://stackoverflow.com/q/25748858/3410196)) –

関連する問題