2011-12-09 55 views
11

我希望我的WPF應用程序成爲放置目標,並且我希望能夠從任何網頁拖動圖像。接收從Web頁面拖動到WPF窗口的圖像

從網頁中拖出圖像時,顯然它處於「DragImageBits」格式,該格式可以反序列化以鍵入ShDragImage。 (請參閱問題的底部瞭解我如何定義它)

如何將其轉換爲WPF圖像?

這是我目前的嘗試。 (如果有人知道正確的方式做desirialization,我所有的耳朵)

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); 

在這一點上,我得到System.Runtime.InteropServices.ExternalException類型的異常,與消息僅僅是。

有誰知道我應該做什麼?


這裏是支持類的定義。我從 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」是由Windows提供的外殼,和被認爲只用於拖動光標,而不是最終的數據。 shell通過調整大小和透明度將圖像轉換爲合適的拖動光標。

例如,如果拖動這個圖片:

Fully Opaque Image

的SHDRAGIMAGE將呈現爲這樣:

enter image description here

如果你真的想從SHDRAGIMAGE提取圖像,這裏是代碼。如果你想利用DragImageBits它的預期目的(作爲拖動圖像),請參閱this blog一種簡單,下載的例子(部分來自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」與實際問題分不開,它接受從網頁拖動的圖像。

從網頁拖動圖像變得複雜,因爲Firefox,Chrome和IE9都爲您提供了一組不同的格式。此外,您想要處理圖像和圖像超鏈接,並且這些處理再次不同。

Google和Firefox提供了一個「text/html」格式,該格式爲您提供了一個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功能:

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可以處理 「FileDrop」 格式。這在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都提供了設備無關位圖(DIB)格式。在可用的情況下,不需要使用WebClient下載文件,因爲我們可以以熟悉的(位圖)格式訪問文件。 Firefox也暴露了'FileDrop'格式,但是在解析html和使用存檔格式的情況下,可能下載的對象可能不一定是圖像 – funseiki

+3

這對我很有幫助。感謝發佈。正則表達式無法匹配許多有效的圖像鏈接。我發現@「] + src =」「([^」「] *)」「」效果稍好一些。 –

+0

你是一個真正的救星。如果像我這樣的其他人想要直接從谷歌圖像拖動圖像,請檢查UriString是否以「data」開頭,這些字符串包含已經存在的數據,不應該下載(來自[此問題](http ://stackoverflow.com/q/25748858/3410196)) –