2011-12-09 31 views
11

Tôi muốn ứng dụng WPF của tôi là mục tiêu thả và tôi muốn có thể kéo hình ảnh từ bất kỳ trang web nào.Nhận một hình ảnh được kéo từ trang Web đến cửa sổ WPF

Khi một hình ảnh được kéo từ một trang web, có vẻ như nó ở định dạng "DragImageBits", có thể được deserialized để nhập ShDragImage. (Xem phần dưới cùng của câu hỏi về cách tôi đã xác định nó)

Làm cách nào để chuyển đổi hình ảnh này thành hình ảnh WPF?

Đây là nỗ lực hiện tại của tôi. (Nếu ai biết cách chính xác để làm desirialization, tôi là tất cả tai)

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

Tại thời điểm này tôi nhận được một ngoại lệ kiểu System.Runtime.InteropServices.ExternalException, với thông điệp đơn giản là .

Có ai biết tôi nên làm gì không?


Và đây là định nghĩa lớp hỗ trợ. Tôi đã sao chép chúng từ 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; 
    } 

Trả lời

15

Đây là những gì tôi đã học được:

"DragImageBits" được cung cấp bởi các cửa sổ shell, và có nghĩa là chỉ dành cho con trỏ kéo, không cho dữ liệu cuối cùng. Trình bao biến đổi hình ảnh thành con trỏ kéo thích hợp thông qua thay đổi kích thước và độ trong suốt.

Ví dụ, nếu bạn kéo hình ảnh này:

Fully Opaque Image

Các SHDRAGIMAGE sẽ làm như thế này:

enter image description here

Nếu bạn thực sự muốn trích xuất hình ảnh từ SHDRAGIMAGE, đây là mã. (Một phần nâng lên từ 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); 

Nếu bạn muốn sử dụng các DragImageBits cho nó dành mục đích (như là một hình ảnh kéo), xem this blog cho một đơn giản, ví dụ tải về.


Vì vậy, "DragImageBits" bị phân tâm khá nhiều so với vấn đề thực tế, đó là chấp nhận một hình ảnh được kéo từ một trang web.

Kéo hình ảnh từ trang web trở nên phức tạp, vì Firefox, Chrome và IE9 đều cung cấp cho bạn một bộ định dạng khác. Ngoài ra, bạn muốn xử lý cả hình ảnh và siêu liên kết hình ảnh, và chúng được xử lý khác một lần nữa.

Google và Firefox cung cấp định dạng "văn bản/html", cung cấp cho bạn một phần tử HTML đơn lẻ làm hình ảnh. Google cung cấp cho bạn dưới dạng chuỗi ASCII và Firefox cung cấp cho bạn dưới dạng chuỗi unicode. Vì vậy, đây là mã tôi đã viết để xử lý nó:

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

Trong trường hợp này, biểu thức chính quy sẽ xử lý cả hình ảnh thẳng và siêu liên kết hình ảnh.

SetImageFromUri chức năng của tôi:

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

Đối với IE9 bạn có thể xử lý các định dạng "FileDrop". Điều này hoạt động tốt trong IE9. Chrome không hỗ trợ nó. Firefox không hỗ trợ nó, nhưng chuyển đổi hình ảnh thành bitmap và chuyển đổi các pixel trong suốt sang màu đen. Vì lý do này, bạn chỉ nên xử lý định dạng "FileDrop" nếu định dạng "text.html" không khả dụng.

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

Định dạng "FileDrop" không được cung cấp nếu bạn kéo liên kết hình ảnh từ IE9. Tôi đã không tìm ra cách để kéo một hình ảnh từ một siêu liên kết hình ảnh trong IE9 vào điều khiển hình ảnh của tôi.


tắm Info

Nếu bạn đang sử dụng ví dụ này, nhưng vẫn cần phải chuyển đổi dữ liệu nhị phân này thành một hình ảnh, đây là một đoạn mã hữu ích:

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

Tôi đang gặp cùng một vấn đề - Tôi đã tìm thấy rằng cả Firefox và IE9 cũng cung cấp một định dạng bitmap (DIB) thiết bị độc lập. Trong trường hợp điều này có sẵn, không cần phải sử dụng WebClient để tải xuống tệp, vì chúng tôi có quyền truy cập vào tệp ở định dạng quen thuộc (bitmap). Firefox cũng cho thấy định dạng 'FileDrop', nhưng trong trường hợp phân tích cú pháp html và sử dụng định dạng đệ trình, có thể tải xuống các đối tượng có thể không nhất thiết là hình ảnh – funseiki

+3

Điều này giúp tôi rất nhiều. Cảm ơn vì đăng. Regex không khớp với nhiều liên kết hình ảnh hợp lệ. Tôi đã tìm thấy @ "] + src =" "([^" "] *)" "" hoạt động tốt hơn một chút. –

+0

Bạn là một phao cứu sinh thực sự. Nếu những người khác như tôi muốn kéo hình ảnh trực tiếp từ hình ảnh của google, hãy kiểm tra trên UriString nếu nó bắt đầu bằng dữ liệu '", những chuỗi đó chứa dữ liệu đã và không nên tải xuống (từ [câu hỏi này] (http : //stackoverflow.com/q/25748858/3410196)) –

Các vấn đề liên quan