前言

前段时间群里有个小伙在工作中遇到一个问题,透明的图片存入剪切板在粘贴到adobe PDF中出现不透明问题但是粘贴到Excel可以,还有就是从excel复制再粘贴到PDF也是可以。小伙在群里发了两天都没有解决,当时看到这个问题感觉很有趣我就去尝试了一下,当时我用的WPS,我试了一下可以粘贴到WPS 打开的PDF中,当时我感觉是PDF编辑器的问题,建议小伙换个,小伙说不能换客户要求必须是这个,好的嘛那就开始搞

号脉

我打开两个神级IDE VS 分别获取一下从excel复制之后和通过小伙程序复制之后存到剪切板中的数据,我对比了一下剪切板中的确有很多的不同,那就开始尝试是因啥不同导致的,我用程序把从Excel中复制获取的数据按照参数对象一个一个从新清空剪切板在重新放入剪切板,尝试是哪个参数对象导致的PDF无法呈现预想的结果。最后确定是因为剪切板中没有存储MetafilePict数据导致的

开药

下面获取图片文件的MetaFile数据

public Metafile GetGeometryMetafile(Bitmap bitmap)
{ Metafile metafile;
using (MemoryStream stream = new MemoryStream())
using (Graphics rtfBoxGraphics = Graphics.FromImage(bitmap))
{
IntPtr pDeviceContext = rtfBoxGraphics.GetHdc(); metafile = new Metafile(stream, pDeviceContext);
using (Graphics imageGraphics = Graphics.FromImage(metafile))
{
//imageGraphics.DrawImage(bitmap, new Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
imageGraphics.DrawImageUnscaled(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
rtfBoxGraphics.ReleaseHdc(pDeviceContext);
}
return metafile; }

吃药

下面把获取的文件MetaFile放入剪切板

因为特殊原因,需要调用系统dll进行剪切板操作

internal static class ClipboardMetafileHelper
{ [DllImport("user32.dll")]
static extern bool OpenClipboard(IntPtr hWndNewOwner); [DllImport("user32.dll")]
static extern bool EmptyClipboard(); [DllImport("user32.dll")]
static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem); [DllImport("user32.dll")]
static extern bool CloseClipboard(); [DllImport("gdi32.dll")]
static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, string fileName); [DllImport("gdi32.dll")]
static extern bool DeleteEnhMetaFile(IntPtr hemf); /// <summary>
/// Copies the given <see cref="T:System.Drawing.Imaging.MetaFile" /> to the clipboard.
/// The given <see cref="T:System.Drawing.Imaging.MetaFile" /> is set to an invalid state inside this function.
/// </summary>
static public bool PutEnhMetafileOnClipboard(IntPtr hWnd, Metafile metafile)
{
return PutEnhMetafileOnClipboard(hWnd, metafile, true);
} /// <summary>
/// Copies the given <see cref="T:System.Drawing.Imaging.MetaFile" /> to the clipboard.
/// The given <see cref="T:System.Drawing.Imaging.MetaFile" /> is set to an invalid state inside this function.
/// </summary>
static public bool PutEnhMetafileOnClipboard(IntPtr hWnd, Metafile metafile, bool clearClipboard)
{
if (metafile == null) throw new ArgumentNullException("metafile");
bool bResult = false;
IntPtr hEMF, hEMF2;
hEMF = metafile.GetHenhmetafile(); // invalidates mf
if (!hEMF.Equals(IntPtr.Zero))
{
try
{
hEMF2 = CopyEnhMetaFile(hEMF, null);
if (!hEMF2.Equals(IntPtr.Zero))
{
if (OpenClipboard(hWnd))
{
try
{
if (clearClipboard)
{
if (!EmptyClipboard())
return false;
}
IntPtr hRes = SetClipboardData(14 /*CF_ENHMETAFILE*/, hEMF2);
bResult = hRes.Equals(hEMF2);
}
finally
{
CloseClipboard();
}
}
}
}
finally
{
DeleteEnhMetaFile(hEMF);
}
}
return bResult;
} /// <summary>
/// Copies the given <see cref="T:System.Drawing.Imaging.MetaFile" /> to the specified file. If the file does not exist, it will be created.
/// The given <see cref="T:System.Drawing.Imaging.MetaFile" /> is set to an invalid state inside this function.
/// </summary>
static public bool SaveEnhMetaFile(string fileName, Metafile metafile)
{
if (metafile == null) throw new ArgumentNullException("metafile");
bool result = false;
IntPtr hEmf = metafile.GetHenhmetafile();
if (hEmf != IntPtr.Zero)
{
IntPtr resHEnh = CopyEnhMetaFile(hEmf, fileName);
if (resHEnh != IntPtr.Zero)
{
DeleteEnhMetaFile(resHEnh);
result = true;
}
DeleteEnhMetaFile(hEmf);
metafile.Dispose();
}
return result;
}
}
var path = AppDomain.CurrentDomain.BaseDirectory + "1.png";

			Bitmap bm = new Bitmap(path, false);

			var mf = GetGeometryMetafile(bm);
ClipboardMetafileHelper.PutEnhMetafileOnClipboard(IntPtr.Zero, mf);

总结

功能看着挺简单,其实内部有很多的坑(文件MetaFIle数据的获取,MetaFile怎么才能正确放到剪切板中),从网上找的资料也不是很全,没有现成的代码,这里做一下总结汇总,供大家使用。上述代码也有一定的问题(剪切板中的数据放到别的编辑器有的失效是因为剪切板中数据缺少对应编辑器所需的参数,可根据Clipboard.GetDataObject()获取缓存数据对象判断编辑器需要的对象然后利用下面方法进行后续代码优化。

public static void SetClipboardImage(Bitmap image, Bitmap imageNoTr, DataObject data)
{
Clipboard.Clear();
if (data == null)
data = new DataObject();
if (imageNoTr == null)
imageNoTr = image;
using (MemoryStream pngMemStream = new MemoryStream())
using (MemoryStream dibMemStream = new MemoryStream())
{
// As standard bitmap, without transparency support
data.SetData(DataFormats.Bitmap, imageNoTr);
// As PNG. Gimp will prefer this over the other two.
image.Save(pngMemStream, ImageFormat.Png);
data.SetData("PNG", pngMemStream);
// As DIB. This is (wrongly) accepted as ARGB by many applications.
Byte[] dibData = ConvertToDib(image);
dibMemStream.Write(dibData, 0, dibData.Length);
data.SetData(DataFormats.Dib, dibMemStream);
// The 'copy=true' argument means the MemoryStreams can be safely disposed after the operation.
Clipboard.SetDataObject(data, true);
}
}

读取图片文件MetaFile放入Windows剪切板的更多相关文章

  1. 监视 Windows 剪切板

    一.先看代码 import win32con,win32gui import win32clipboard as cb class MyWindow(): def __init__(self): #注 ...

  2. Python实现图片转文字并翻译至剪切板

    一.环境搭建: 1.PySimpleGUI: pip3 install pysimplegui 2.pytesseract需要有tesseract环境才行: 1. 先搭建tesseract: brew ...

  3. windows剪切板暂存

    其实最初是因为在项目中使用了html网页编辑器,通过ie的com组件和javascript通讯完成一些事情,其中有一个功能是插入表格,我们原本使用的range.pasteHTML(HTMLstr);根 ...

  4. winform学习之----打开文件对话框并将文件内容放入文本框

    OpenFileDialog ofg = new OpenFileDialog(); ofg.Title = "ddd";//设置对话框标题 ofg.Multiselect = t ...

  5. c# 读取图片文件

    /// <summary> /// 通过FileStream 来打开文件,这样就可以实现不锁定Image文件,到时可以让多用户同时访问Image文件 /// </summary> ...

  6. 【DOS】取某目录下某类型文件信息放入文本

    C:\Users\horn1\Desktop\新建文件夹>dir *.jar >1.txt 这样,所有扩展名为jar的文件信息就送到新建的文本文件1.txt中了.虽然简单,但也是个常用功能 ...

  7. Delphi的windows剪切板操作函数

    1. Clipbrd函数 function Clipboard: TClipboard;:若应用程序从未使用过剪贴板,则调用该函数形成新的剪贴板:若之前使用过剪贴板则返回使用过的剪贴板. 属性: As ...

  8. 使用python读写windows剪切板

    import win32clipboard as w import win32con base_addr = 0x8e00000 buffer_len = 0x123 def getText(): w ...

  9. java通过文件路径读取该路径下的所有文件并将其放入list中

    java通过文件路径读取该路径下的所有文件并将其放入list中   java中可以通过递归的方式获取指定路径下的所有文件并将其放入List集合中.假设指定路径为path,目标集合为fileList,遍 ...

随机推荐

  1. 对TCP粘包拆包的理解

    TCP的粘包与拆包 TCP是一种字节流(byte-stream)协议,所谓流,就是没有界限的一串数据. 一个完整的包会被TCP拆为多个包进行发送,也有可能把多个小包封装成一个大的数据包发送,这就是所谓 ...

  2. 苹果宣布 2022 年 Apple 设计大奖得主

    Apple 今日举办了年度 Apple 设计大奖颁奖仪式,表彰 12 款出类拔萃的 app 与游戏佳作.今年的获奖者包括来自全球各地的开发者.他们通过 app 呈现锐意创新.别出心裁的优美设计体验,以 ...

  3. PyTorch保存模型、冻结参数等

    此外可以参考PyTorch模型保存.https://zhuanlan.zhihu.com/p/73893187 查看模型每层输出详情 Keras有一个简洁的API来查看模型的每一层输出尺寸,这在调试网 ...

  4. 无法打开虚拟机“master”(D:\文档\Virtual Machines\master\master.vmx):未找到文件。是否从库中移除“master”?

    今天打开虚拟机的时候,出现了这样的弹窗提示: 无法打开虚拟机"master"(D:\文档\Virtual Machines\master\master.vmx):未找到文件.是否从 ...

  5. Vue 安装 vue的基本使用 vue的初步使用步骤

    1. 资源: https://cn.vuejs.org/v2/guide/#%E8%B5%B7%E6%AD%A5 进入官网学习 2. 点击安装,要把vue下载到本地文件的根目录中,不要选择压缩版的,这 ...

  6. 从Hadder看蛋白质分子中的加氢算法

    技术背景 PDB(Protein Data Bank)是一种最常用于存储蛋白质结构的文件.而我们在研究蛋白质构象时,往往更多的是考虑其骨架,因此在很多pdb文件中直接去掉了氢原子.但是在我们构建蛋白质 ...

  7. # NC20860 兔子的区间密码

    NC20860 兔子的区间密码 题目 题目描述 有一只可爱的兔子被困在了密室了,密室里有两个数字,还有一行字: 只有解开密码,才能够出去. 可爱的兔子摸索了好久,发现密室里的两个数字是表示的是一个区间 ...

  8. RESTAPI 版本控制策略【eolink 翻译】

    微服务,是现阶段开发建设云原生应用程序的流行趋向.API 版本控制有益于在辨别出所需要的调节时加速迭代更新的速度. 根据微服务架构的关键构件其一,是 API 的设计和规范.针对 API,版本控制是不可 ...

  9. 一个豆瓣电影Top250爬虫

    一个爬虫 这是我第一次接触爬虫,写的第一个爬虫实例. https://movie.douban.com/top250 模块 import requests #用于发送请求 import re #使用正 ...

  10. NAT模式 LVS负载均衡群集部署

    NAT模式 LVS负载均衡群集部署的操作步骤 实验环境准备: 负载调度器:内网关 ens33:172.16.10.1,外网关 ens37:12.0.0.1 Web节点服务器1:172.16.10.10 ...