2017-05-31 30 views
1

這是一個奇怪的一個: 我最近升級我的工作站從Windows 7到Windows 10,我有一個聊天客戶端,是使用下面的代碼從剪貼板接受圖片:在Windows 10上使用Clipboard.GetImage()後從屏幕截圖擦除文本?

if (Clipboard.ContainsImage()) 
{ 
     BitmapSource source = Clipboard.GetImage(); 
     BitmapFrame frame = BitmapFrame.Create(source); 
     var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder(); 
     encoder.Frames.Add(frame); 
     var stream = new MemoryStream(); 
     encoder.Save(stream); 
     byte[] daten = stream.ToArray(); 
     if (daten != null && daten.Length > 0) 
     { 
      sendFile(DateTime.Now.ToString("yyyyMMddHHmmss_") + "clipboard.png", stream.ToArray()); 
     } 
} 

這裏是區域我截圖應該樣子(例如,如果我把它粘貼到MS-畫圖或直接從截圖工具保存): Actual Screenshot

現在這裏是什麼樣子,我導入使用Clipboard.GetImage();截圖後。 Screenshot after using Glipboard.GetImage()

正如您所看到的,所有文本都會被擦除,如果您仔細觀察,可以看到通常爲白色的背景現在是透明的。

如果我使用JpegBitmapEncoder而不是PngBitmapEncoder,它工作得很好,所以這是properbly編碼的問題,但什麼baffels我是這樣的:

  1. 這從未happend在Windows 7上 - 什麼已經在Windows 10改變 可以使截圖有什麼不同?
  2. 如果我從截屏工具將屏幕截圖保存到文件中,將創建一個PNG(在數據本身中帶有PNG-Header)。那麼,爲什麼PNG不是正確的編碼?
+0

奇怪......據我所知,Windows剪貼板甚至沒有_support_透明度。 – Nyerguds

+0

將它粘貼到Gimp中肯定不起作用...更不用說,您屏幕截圖的窗口在那裏沒有透明度。 – Nyerguds

+0

如果您刪除所有alpha,圖像仍包含所有信息。我想我明白了,但我不是100%肯定的。你使用的是什麼版本的.net框架?因爲3.5版似乎沒有這樣做,但版本4+可能會有不同的反應。 – Nyerguds

回答

2

我一直在研究Windows剪貼板,我想我知道發生了什麼事情。對我來說,這是一個相當長的解釋,並且需要大量的研究才能獲得關於DIB格式的足夠信息,而DIB格式是這個混亂的核心。

默認情況下,由於傳統原因,剪貼板根本不支持透明度;當剪貼板第一次設計時,沒有像alpha通道那樣的東西。但是,正如你可能知道的那樣,可以將多種格式放在剪貼板上,讓程序讀取剪貼板中更多數據的可能性,而且看起來在最近的Windows版本中,圖像顯然也被放到了DIB(設備無關位圖)格式的剪貼板。現在,.Net框架v3.5通常採用剪貼板中的標準非透明「圖像」格式版本,所以它從不提供透明度,但似乎4.5實際上可能獲得此DIB。

DIB,因爲它存在於剪貼板上,技術上是每像素32位RGB圖像。請注意,RGB,不是 ARGB。這意味着每個像素有四個字節,但紅色,綠色和藍色字節正常填充時,第四個字節實際上是未定義的,不應該指望實際意思是「alpha」。它只是爲了讓數據很好地對齊到四個字節的倍數。

此DIB的內部格式設置爲32位「BITFIELDS」,它不同於標準的32位「RGB」類型,因爲它在標題中專門定義了要使用的每個32位像素的哪些位爲每種顏色。但它只定義了三個這樣的位域;紅色,綠色和藍色。沒有第四個領域;它不應該有阿爾法。考慮一下,如果這個圖像是由一個真正把它當作沒有alpha的RGB處理的系統創建的,並且事先沒有清除它的內存(因爲許多C/C++系統不這樣做),而且實際上只寫這些R,G和B字節,那麼第四個字節可能只是以前操作留下的隨機垃圾。你甚至不能確定它被清除爲0或設置爲標準的不透明值255。

還有問題...因爲很多應用程序,包括顯然Windows 10和.Net框架4.5,這樣對待它。當我在由不同高度的2個屏幕組成的Windows 10桌面上按下Print Screen時,所得到的圖像實際上被Windows本身放在剪貼板中,作爲具有透明度的混蛋-BITFIELDS-DIB格式;當我用我的功能轉儲圖像以將該DIB保存爲ARGB圖像時,圖像上落在實際顯示器之外的區域確實是透明,而不僅僅是黑色;它是'alpha'字節設置爲0的圖像中唯一的一部分。所以這似乎表明Windows 10本身也考慮了alpha-capable格式。

所以我們這裏有什麼似乎是微軟本身沒有正確使用自己的規格問題。 (如果你想知道,是的,他們作出了DIB規格。)他們可以完美地切換到更新的DIB格式與一個更大的頭,其中確實支持真正的阿爾法,而是他們使用一個混蛋老RGB格式,顯然每個人(我從Google Chrome複製圖像時發現它)只需假定包含alpha。

這反過來,似乎會導致像你有什麼奇怪的行爲。我懷疑資源管理器窗口的繪圖機制中的某些東西填充了這些字節,甚至可能是它自己的繪圖層中的一個的alpha,並且在將最終圖像放在剪貼板上時它永遠不會被清除。然後,正如您注意到的,.Net框架4.5顯然假定這些額外的字節確實是您獲得圖像的Alpha通道。

解決方法是將這些字節清除爲255,或讓系統將結果解釋爲RGB而不是ARGB。第二個實際上我可以幫助你:我詳細說明了如何從GetImageData函數in this answer中獲取圖像數據中的字節,而this one有我的BuildImage方法來將字節寫回新圖像。因此,如果您只是使用它來獲取32位ARGB數據,然後將其寫回新的32位RGB圖像,則可以使框架將圖像數據視爲不透明,而無需修改單個字節。

+0

請注意,不是_everyone_假定它包含alpha。我在Gimp問題跟蹤器上發現了一個特定的票據,該票據拒絕格式爲不可靠性原因的alpha-capable。 GIMP將始終將此DIB視爲不透明。 – Nyerguds

+0

很高興我能幫上忙 - 我想出瞭解決剪貼板上可靠地獲取透明圖像的類似問題。 – Nyerguds

+0

如果您對我的完整剪貼板複製代碼感興趣,我在此處發佈它:https://stackoverflow.com/a/46424800/395685 – Nyerguds