为了账号安全,请及时绑定邮箱和手机立即绑定

如何从Clipboard类获取图像格式?

如何从Clipboard类获取图像格式?

C#
眼眸繁星 2023-07-22 18:32:38
我正在用 C# 制作一个图像查看器。该功能是使用 C# 上的 Clipboard 类进行复制和粘贴功能。我成功获取了BitmapSource的图像。但它无法检查图像格式(jpeg、png、bmp)。这是 C# 支持的源 BitmapSource source = Clipboard.GetImage();这些是我想要使用的。 byte[] image = Clipboard.GetImage("image/png") byte[] image = Clipboard.GetImage("image/bmp")我会说,如何从 BitmapSource 或剪贴板检查图像格式?
查看完整描述

1 回答

?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

简而言之,你不能。

图像作为原始位图保存在剪贴板上。有些应用程序也将其以 png 格式显示,但这并不是为了保留原始格式,而只是为了更好地支持 alpha-transparency。

但是,一般来说,剪贴板根本不包含该图像的来源或最初的格式的任何指示。您还必须意识到剪贴板上的图像可能根本就不是文件。这就像假设任何复制的文本都必须是一个带有文件名的完整文本文件。该图像可能是直接从某个编辑器复制的,甚至可能是直接的 [PrintScreen] 按钮屏幕截图。

然而...

注意到,当我从 Chrome 复制图像并将其粘贴到 Discord 中时,Discord 会以某种方式知道它在 Chrome 中的文件名。这是因为您可以同时将多种格式的数据放入剪贴板。

该系统通常旨在确保每个应用程序都可以读取最适合它的内容。例如,对于从网页复制的内容,记事本将首选纯文本版本,而 Microsoft Word 将采用 HTML(如果可用)。同样,正如我所提到的,应用程序通常以位图和 png 格式复制图像,以确保支持透明度的接收应用程序可以采用支持透明度的 PNG 版本,而不了解使用 PNG 的新趋势的应用程序可以采用经典位图。

但许多应用程序也使用它来将元数据添加到复制的内容中。当我在 Chrome 中复制您头像的 32x32 缩略图时,剪贴板中的内容之一是此文本片段标识为HTML Format

Version:0.9

StartHTML:0000000105

EndHTML:0000000238

StartFragment:0000000141

EndFragment:0000000202

<html>

<body>

<!--StartFragment--><img src="https://i.stack.imgur.com/Eql2x.jpg?s=32&amp;g=1"/><!--EndFragment-->

</body>

</html>

(我相信指定 HTML 片段信息的标头可能是标准格式。但从未研究过这一点。)

如您所见,这包含文件名,并且您通常会获得一个扩展名,可用于确定文件的原始格式。

但该文件不再是那种格式。因为,它只是剪贴板上的数据,而不是实际的文件。复制图像后 Chrome 剪贴板的完整转储包含以下格式:

  • System.Drawing.Bitmap(.Net Bitmap 对象。这可能在 WPF 上以不同的方式公开)

  • Bitmap(和System.Drawing.Bitmap我想的一样)

  • HTML Format(上面显示的片段)

  • DeviceIndependentBitmap(包含 DIB v1 图像字节的字节流;在剪贴板上传输图像的最常见方式;经常被滥用为具有 alpha 功能,因为它是 32 位 RGB)

  • Format17(包含 DIB v5 图像字节的字节流;比 v1 稍微高级,并且正式支持 alpha。“17”指的是旧 Windows 版本中使用的旧数字剪贴板格式)

如您所见,其中没有 jpeg 文件。因为当您处于剪贴板级别时,永远不会假定保留原始文件格式。即使是能够读取并保留文件名的 Discord,也会将粘贴的文件另存为 png,并根据需要调整文件扩展名。

在这种特定情况下,您当然可以实际从该 url 下载图像,而不是使用剪贴板版本。但从技术上讲,这永远不能保证是相同的图像。

请注意,Chrome 就是这样做的。无法保证来自其他应用程序甚至其他浏览器的剪贴板副本将发送元数据,并且如果发送元数据,则其格式是否略有可比。


我用来分析剪贴板数据的代码:

(注意,这是 Windows 窗体代码。我不知道它的 WPF 等效项)

DataObject retrievedData = (DataObject)Clipboard.GetDataObject();

if (retrievedData == null)

    return;

String[] formats = retrievedData.GetFormats();

foreach (String format in formats)

{

    Object contents = retrievedData.GetData(format);

    MemoryStream ms = contents as MemoryStream;

    Byte[] bContents = ms == null ? null : ms.ToArray();

    String sContents = contents as String;


    // Check if bContents and sContents are null here, and analyse their contents


    // ...

}


查看完整回答
反对 回复 2023-07-22
  • 1 回答
  • 0 关注
  • 147 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信