gpt4 book ai didi

winforms - 需要帮助将具有透明背景的图像设置到剪贴板

转载 作者:行者123 更新时间:2023-12-02 22:14:41 24 4
gpt4 key购买 nike

我需要帮助将透明图像设置到剪贴板。我不断收到“句柄无效”。基本上,我需要“第二双眼睛”来查看以下代码。 (完整的工作项目位于ftp://missico.net/ImageVisualizer.zip。)

这是一个图像调试可视化器类库,但我将包含的项目作为可执行文件运行以进行测试。 (请注意,该窗口是一个工具箱窗口,并且在任务栏中显示设置为 false。)我厌倦了必须在工具箱窗口上执行屏幕捕获,使用图像编辑器打开屏幕捕获,然后删除添加的背景,因为它是一个屏幕截图。所以我想我应该快速将透明图像放到剪贴板上。嗯,问题是...Clipboard.SetImage 不支持透明度。谷歌来救援......不完全是。

这就是我到目前为止所拥有的。我从多个来源获取。主要引用代码请参见代码。我的问题是使用 CF_DIBV5 时的“无效句柄”。我需要使用 BITMAPV5HEADER 和 CreateDIBitmap 吗?

如果您能得到 GDI/GDI+ 向导的任何帮助,我们将不胜感激。

    public static void SetClipboardData(Bitmap bitmap, IntPtr hDC) {

const uint SRCCOPY = 0x00CC0020;
const int CF_DIBV5 = 17;
const int CF_BITMAP = 2;

//'reference
//'http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/816a35f6-9530-442b-9647-e856602cc0e2

IntPtr memDC = CreateCompatibleDC(hDC);
IntPtr memBM = CreateCompatibleBitmap(hDC, bitmap.Width, bitmap.Height);

SelectObject(memDC, memBM);

using (Graphics g = Graphics.FromImage(bitmap)) {

IntPtr hBitmapDC = g.GetHdc();
IntPtr hBitmap = bitmap.GetHbitmap();

SelectObject(hBitmapDC, hBitmap);

BitBlt(memDC, 0, 0, bitmap.Width, bitmap.Height, hBitmapDC, 0, 0, SRCCOPY);

if (!OpenClipboard(IntPtr.Zero)) {
throw new System.Runtime.InteropServices.ExternalException("Could not open Clipboard", new Win32Exception());
}

if (!EmptyClipboard()) {
throw new System.Runtime.InteropServices.ExternalException("Unable to empty Clipboard", new Win32Exception());
}

//IntPtr hClipboard = SetClipboardData(CF_BITMAP, memBM); //works but image is not transparent

//all my attempts result in SetClipboardData returning hClipboard = IntPtr.Zero
IntPtr hClipboard = SetClipboardData(CF_DIBV5, memBM);


//because
if (hClipboard == IntPtr.Zero) {

// InnerException: System.ComponentModel.Win32Exception
// Message="The handle is invalid"
// ErrorCode=-2147467259
// NativeErrorCode=6
// InnerException:

throw new System.Runtime.InteropServices.ExternalException("Could not put data on Clipboard", new Win32Exception());
}

if (!CloseClipboard()) {
throw new System.Runtime.InteropServices.ExternalException("Could not close Clipboard", new Win32Exception());
}

g.ReleaseHdc(hBitmapDC);

}

}

private void __copyMenuItem_Click(object sender, EventArgs e) {

using (Graphics g = __pictureBox.CreateGraphics()) {

IntPtr hDC = g.GetHdc();

MemoryStream ms = new MemoryStream();

__pictureBox.Image.Save(ms, ImageFormat.Png);

ms.Seek(0, SeekOrigin.Begin);

Image imag = Image.FromStream(ms);

// Derive BitMap object using Image instance, so that you can avoid the issue
//"a graphics object cannot be created from an image that has an indexed pixel format"

Bitmap img = new Bitmap(new Bitmap(imag));

SetClipboardData(img, hDC);

g.ReleaseHdc();

}

}

最佳答案

您可以采取一些措施来稍微收紧代码库,我在 CF_DIBV5 上做了一些功课,您可能会发现它们很有帮助。

首先,在 __copyMenuItem_Click() 中,我们有图像的四个完整副本,这远远超出了必要的范围。

  1. __pictureBox.Image
  2. 图像 imag = Image.FromStream(ms);
  3. 新位图(imag)
  4. Bitmap img = new Bitmap(new Bitmap(imag));(外部位图)

此外,您的 MemoryStreamimagnew Bitmap(imag)img 不会被释放,这可能会导致问题。

在不改变代码意图(并且可能不解决句柄问题)的情况下,您可以像这样重写该方法:

private void __copyMenuItem_Click(object sender, EventArgs e)
{
var image = __pictureBox.Image;
using (var g = __pictureBox.CreateGraphics())
using (var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
using (var bmpg = Graphics.FromImage(bmp))
{
IntPtr hDC = g.GetHdc();
bmpg.DrawImage(image, 0, 0, image.Width, image.Height);
SetClipboardData(bmp, hDC);
g.ReleaseHdc();
}
}

接下来看起来需要注意的是这行:

IntPtr hClipboard = SetClipboardData(CF_DIBV5, memBM);

我相当确定,在使用 CF_DIBV5 时,您必须编码 BITMAPV5HEADER 结构才能将位传递到剪贴板。我之前就错了,但我会验证 memBM 实际上包含 header 。一个很好的指标是第一个 DWORD (UInt32) 的值是否为 124( header 的大小,以字节为单位)。

我的最后一句话更多的是建议,而不是第二双眼睛。我发现 GIMP、Paint.NET、Fireworks 和 PhotoScape 等照片应用程序似乎对 CF_DIBV5 (Format17) 粘贴的支持很差或不支持。您可以考虑将 PNG 格式复制到剪贴板,并使用不透明位图作为备份,以防目标应用程序不支持 PNG。我使用扩展方法来促进这一点:

public static void CopyMultiFormatBitmapToClipboard(this Image image)
{
using (var opaque = image.CreateOpaqueBitmap(Color.White))
using (var stream = new MemoryStream())
{
image.Save(stream, ImageFormat.Png);

Clipboard.Clear();
var data = new DataObject();
data.SetData(DataFormats.Bitmap, true, opaque);
data.SetData("PNG", true, stream);
Clipboard.SetDataObject(data, true);
}
}

有了扩展方法,您的 __copyMenuItem_Click() 方法可以简化为以下内容,并且 SetClipboardData() 方法可以完全删除:

private void __copyMenuItem_Click(object sender, EventArgs e)
{
__pictureBox.Image.CopyMultiFormatBitmapToClipboard();
}

现在,正如我们已经在另一个线程中讨论的那样,PNG 支持可能不适合您。我已经在一些应用程序上测试了这种方法;但是,这将由您决定这是否足以满足您的要求的透明度支持。

  • GIMP:支持透明度
  • Fireworks (3.0):支持透明度
  • PhotoScape:白色背景
  • Paint.NET:白色背景
  • MS PowerPoint 2007:支持透明度
  • MS Word 2007:白色背景
  • MS Paint (Win7):白色背景

对于 Stack Overflow 来说,我所研究的所有内容的讨论都太长了。我的博客上提供了其他示例代码和讨论:http://www.notesoncode.com/articles/2010/08/16/HandlingTransparentImagesOnTheClipboardIsForSomeReasonHard.aspx

祝你好运!

关于winforms - 需要帮助将具有透明背景的图像设置到剪贴板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2799442/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com