【问题标题】:How can I convert a CF_DIBV5 to a BitmapSource?如何将 CF_DIBV5 转换为 BitmapSource?
【发布时间】:2018-04-23 16:19:46
【问题描述】:

我希望将剪贴板中的CF_DIBV5 格式转换为BitmapSource 对象。到目前为止,这是我的代码,基于我以前用于将普通 DIB 转换为 BitmapSource 的代码。要转换普通的 DIB,我发现我只需要获取标头,并将其添加到位图的原始字节之前。

不幸的是,当我尝试使代码兼容 DIBV5 时,程序现在抛出以下异常。

找不到适合完成此操作的成像组件。

当我使用BitmapFrameCreate 方法时会发生这种情况。完整代码如下。

var infoHeader =
    ApiHelper.ByteArrayToStructure<BITMAPV5HEADER>(buffer);

var fileHeaderSize = Marshal.SizeOf(typeof(BITMAPV5HEADER));
var infoHeaderSize = infoHeader.bV5Size;
var fileSize = fileHeaderSize + infoHeader.bV5Size + infoHeader.bV5SizeImage;

var fileHeader = new BITMAPV5HEADER();
fileHeader.bV5CSType = BITMAPV5HEADER.LCS_sRGB;
fileHeader.bV5Size = (uint) fileSize;
fileHeader.bV5Reserved = 0;

byte[] fileHeaderBytes =
    ApiHelper.StructureToByteArray(fileHeader);

var bitmapStream = new MemoryStream();
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
bitmapStream.Write(buffer, 0, buffer.Length);
bitmapStream.Seek(0, SeekOrigin.Begin);

BitmapFrame bitmap = BitmapFrame.Create(bitmapStream);

关于我做错了什么,或者我做错了什么的任何想法?我在盲目地摸索,不幸的是,对于像我这样的 C# 程序员来说,文档很少。我懂一点 C++,但不足以从 C++ 转换为 C#。

【问题讨论】:

  • 异常不存在。 v5 格式的本意是对 BMP 格式的改进,但没有人想要它。甚至微软也不行。目前尚不清楚为什么这是一个问题,大多数提供 CF_DIBV5 剪贴板格式的程序如果想要可用,也会暴露 CF_BITMAP 和/或 CF_DIB。
  • 在解释“缺少什么/无法使用上述代码”方面没有帮助,但从长远来看,this SO question 的这些答案中的任何一个都有可能以某种方式或可能被调整根据您的情况填写缺失的部分?
  • 你能试试那个代码吗:pastebin.com/8Q1b7Bmh 我对 alpha 通道(透明度)有疑问,我不明白,但它可能对你来说已经足够了。它应该适用于 Windows 8+

标签: c#


【解决方案1】:

将此image 复制到剪贴板。您还需要将 Image 控件添加到 MainWindow。这需要一段时间才能弄清楚,所以我可能错过了添加所需参考的解释。

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        [DllImport("User32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool IsClipboardFormatAvailable(uint format);

        [DllImport("User32.dll", SetLastError = true)]
        private static extern IntPtr GetClipboardData(uint uFormat);

        [DllImport("User32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool OpenClipboard(IntPtr hWndNewOwner);

        [DllImport("User32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseClipboard();

        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr GlobalLock(IntPtr hMem);

        [DllImport("Kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GlobalUnlock(IntPtr hMem);

        const uint CF_DIBV5 = 17;

        public enum BitmapCompressionMode : uint
        {
            BI_RGB = 0,
            BI_RLE8 = 1,
            BI_RLE4 = 2,
            BI_BITFIELDS = 3,
            BI_JPEG = 4,
            BI_PNG = 5
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct BITMAPV5HEADER
        {
            public uint bV5Size;
            public int bV5Width;
            public int bV5Height;
            public UInt16 bV5Planes;
            public UInt16 bV5BitCount;
            public uint bV5Compression;
            public uint bV5SizeImage;
            public int bV5XPelsPerMeter;
            public int bV5YPelsPerMeter;
            public UInt16 bV5ClrUsed;
            public UInt16 bV5ClrImportant;
            public UInt16 bV5RedMask;
            public UInt16 bV5GreenMask;
            public UInt16 bV5BlueMask;
            public UInt16 bV5AlphaMask;
            public UInt16 bV5CSType;
            public IntPtr bV5Endpoints;
            public UInt16 bV5GammaRed;
            public UInt16 bV5GammaGreen;
            public UInt16 bV5GammaBlue;
            public UInt16 bV5Intent;
            public UInt16 bV5ProfileData;
            public UInt16 bV5ProfileSize;
            public UInt16 bV5Reserved;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct RGBQUAD
        {
            public byte rgbBlue;
            public byte rgbGreen;
            public byte rgbRed;
            public byte rgbReserved;
        }

        public MainWindow()
        {
            InitializeComponent();
            AttemptConversion();
        }

        private void AttemptConversion()
        {
            WindowInteropHelper helper = new WindowInteropHelper(this);

            bool gotIt = OpenClipboard(helper.Handle);
            if (!gotIt) return;

            bool formatAvail = IsClipboardFormatAvailable(CF_DIBV5);
            if (!formatAvail) return;

            IntPtr hBitmap = IntPtr.Zero;
            hBitmap = GetClipboardData(CF_DIBV5);
            IntPtr ptr = GlobalLock(hBitmap);

            BitmapSource bmpSrc = CF_DIBV5ToBitmapSource(hBitmap);

            img.Width = (int)bmpSrc.Width;
            img.Height = (int)bmpSrc.Height;
            img.Source = bmpSrc;

            if (ptr != IntPtr.Zero) GlobalUnlock(hBitmap);
            if (gotIt) CloseClipboard();
        }

        private BitmapSource CF_DIBV5ToBitmapSource(IntPtr hBitmap)
        {
            IntPtr scan0 = IntPtr.Zero;
            var bmi = (BITMAPV5HEADER)Marshal.PtrToStructure(hBitmap, typeof(BITMAPV5HEADER));

            int stride = (int)(bmi.bV5SizeImage / bmi.bV5Height);
            long offset = bmi.bV5Size + bmi.bV5ClrUsed * Marshal.SizeOf<RGBQUAD>();
            if (bmi.bV5Compression == (uint)BitmapCompressionMode.BI_BITFIELDS)
            {
                offset += 12; //bit masks follow the header
            }
            scan0 = new IntPtr(hBitmap.ToInt64() + offset);

            BitmapSource bmpSource = BitmapSource.Create(
                bmi.bV5Width, bmi.bV5Height,
                bmi.bV5XPelsPerMeter, bmi.bV5YPelsPerMeter,
                PixelFormats.Bgra32, null,
                scan0, (int)bmi.bV5SizeImage, stride);

            return bmpSource;
        }
    }
}

【讨论】:

  • 非常感谢!我明天会检查这是否有效,如果有效,我会奖励赏金。干得好!
  • 在这一行scan0 = new IntPtr(hBitmap.ToInt32() + offset); 上,它因算术溢出错误而崩溃。知道为什么会这样吗?
  • 我通过改为ToInt64 摆脱了错误,但现在图像颠倒了。任何想法如何解决这个问题?
  • 你的图片的 bV5Height 是正的还是负的?这似乎是自上而下与自下而上的 DIB 问题 stackoverflow.com/questions/662853/… msdn.microsoft.com/en-us/library/windows/desktop/…
  • 我会尽快看看。您是否有机会帮助修改示例以使其适用于两者?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多