读取图片文件MetaFile放入Windows剪切板
前言
前段时间群里有个小伙在工作中遇到一个问题,透明的图片存入剪切板在粘贴到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剪切板的更多相关文章
- 监视 Windows 剪切板
一.先看代码 import win32con,win32gui import win32clipboard as cb class MyWindow(): def __init__(self): #注 ...
- Python实现图片转文字并翻译至剪切板
一.环境搭建: 1.PySimpleGUI: pip3 install pysimplegui 2.pytesseract需要有tesseract环境才行: 1. 先搭建tesseract: brew ...
- windows剪切板暂存
其实最初是因为在项目中使用了html网页编辑器,通过ie的com组件和javascript通讯完成一些事情,其中有一个功能是插入表格,我们原本使用的range.pasteHTML(HTMLstr);根 ...
- winform学习之----打开文件对话框并将文件内容放入文本框
OpenFileDialog ofg = new OpenFileDialog(); ofg.Title = "ddd";//设置对话框标题 ofg.Multiselect = t ...
- c# 读取图片文件
/// <summary> /// 通过FileStream 来打开文件,这样就可以实现不锁定Image文件,到时可以让多用户同时访问Image文件 /// </summary> ...
- 【DOS】取某目录下某类型文件信息放入文本
C:\Users\horn1\Desktop\新建文件夹>dir *.jar >1.txt 这样,所有扩展名为jar的文件信息就送到新建的文本文件1.txt中了.虽然简单,但也是个常用功能 ...
- Delphi的windows剪切板操作函数
1. Clipbrd函数 function Clipboard: TClipboard;:若应用程序从未使用过剪贴板,则调用该函数形成新的剪贴板:若之前使用过剪贴板则返回使用过的剪贴板. 属性: As ...
- 使用python读写windows剪切板
import win32clipboard as w import win32con base_addr = 0x8e00000 buffer_len = 0x123 def getText(): w ...
- java通过文件路径读取该路径下的所有文件并将其放入list中
java通过文件路径读取该路径下的所有文件并将其放入list中 java中可以通过递归的方式获取指定路径下的所有文件并将其放入List集合中.假设指定路径为path,目标集合为fileList,遍 ...
随机推荐
- C# 类继承中的私有字段都去了哪里?
最近在看 C++ 类继承中的字段内存布局,我就很好奇 C# 中的继承链那些 private 字段都哪里去了? 在内存中是如何布局的,毕竟在子类中是无法访问的. 一:举例说明 为了方便讲述,先上一个例子 ...
- JavaScript Number -> String
六种将Number类型转化为String类型的方法: 方法一:通过+运算符加上一个空字符串: eg:'' + 5 -> '5' 5 + '' -> '5' 方法二:toStrin ...
- 2021.04.24【NOIP提高B组】模拟 总结
2021.04.24[NOIP提高B组]模拟 总结 T1 题意:有一圈数.两两之间有加法或乘法操作, 问你开始断掉那条边使得剩下的序列经过某种操作后的值最大 看上去是个区间 dp .然后直接断环成列, ...
- 简述基于CPU的机器码运行过程
引言:会写日志的人不一定是优秀的人,但优秀的人往往是会写日志的 这里涉及五个部分,胡歌,林拜,贾以枚,罗伊人,冯眷眷-林拜老婆 依次对应CPU里的控制器, CPU里的寄存器,存储器,输入电路,输出电路 ...
- Python程序入口 __name__ == ‘__main__‘ 有重要功能(多线程)而非编程习惯
文章来源于互联网(https://jq.qq.com/?_wv=1027&k=rX9CWKg4) 在Python中,被称为「程序的入口」的 if name =='main': 总是出现在各种示 ...
- NC17059 队列Q
NC17059 队列Q 题目 题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 \(Q_i\) 表示.Q1 表示队头元素,\(Q_N\) 表示队尾元素.队列中 ...
- 机器学习基础:用 Lasso 做特征选择
大家入门机器学习第一个接触的模型应该是简单线性回归,但是在学Lasso时往往一带而过.其实 Lasso 回归也是机器学习模型中的常青树,在工业界应用十分广泛.在很多项目,尤其是特征选择中都会见到他的影 ...
- HTML知识点概括——一篇文章带你完全掌握HTML
HTML知识点概括 前端三件套分别是HTML3,CSS5,JavaScript 稍微介绍一下W3C标准: 结构化标准语言(HTML) 表现标准语言(CSS) 行为标准(DOM,JavaScript) ...
- Learning Latent Graph Representations for Relational VQA
The key mechanism of transformer-based models is cross-attentions, which implicitly form graphs over ...
- k8s配置集ConfigMap详解
ConfigMap介绍 ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷,ConfigMap对象用于为容器中的应用提供配置文件等信息.但是比较敏感的数据,例如密钥.证书 ...