读取图片文件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,遍 ...
随机推荐
- Maven笔记---超详细
显眼位置标注来源:此文章为B站课程黑马程序员Maven全套教程笔记,由本人整理. Maven简介 Maven的本质是一个项目管理工具,将项目开发和管理过程抽象成一个项目对象模型(POM) POM (P ...
- EnvironmentLocationNotFound: Not a conda environment: C:\Program Files\Anaconda3
可参考:https://blog.csdn.net/dscn15848078969/article/details/114743744
- ShardingSphere 异构迁移最佳实践:将3.5亿量级的顾客系统 RTO 减少60倍
Apache ShardingSphere 助力当当 3.5 亿用户量级顾客系统重构,由 PHP+SQL Server 技术栈无缝转型为 Java+ShardingSphere+MySQL,性能.可用 ...
- ESXI系列问题整理以及记录——使用Windows PowerShell中的SSH功能连接ESXI控制台
首先进入ESXI管理页面,开启ESXI的SSH功能 接下来到位于同一局域网的Win主机上开启Powershell,如果ESXI主机的IP地址为192.168.1.77,则在Powershell中输入: ...
- LVGL库入门教程04-样式
LVGL样式 LVGL样式概述 创建样式 在 LVGL 中,样式都是以对象的方式存在,一个对象可以描述一种样式.每个控件都可以独立添加样式,创建的样式之间互不影响. 可以使用 lv_style_t 类 ...
- C语言学习之我见-strncmp()字符串比较函数(控制范围)
strncmp()函数,用于范围内,两个字符串的比较,n表示最大比较范围. (1)函数原型 int strncmp(const char *_Str1,const char *_Str2,size_t ...
- C#金额数字转换中文繁体
/// <summary> /// 数字转换中文繁体金钱 /// </summary> /// <param name="Digital">&l ...
- 5-19 SpringAop | 切面编程
Aop面向切面编程 什么是Aop 面向切面的程序设计(Aspect Oriented Programming)又译作剖面导向程序设计 和OOP(Object Oriented Programming) ...
- ApiDay002_01 正则表达式
正则表达式 用于检测.测试字符串规则的表达式. 经常用于检测字符串是否符合特定的规则,在网站上经常用于检测用户输入数据是否符合规范: 检测 用户名 是否为 8~10 数字 英文(大小写) 检测 电话号 ...
- break和continue语句的使用
break break关键字的用法有常见的两种: 1.可以用在switch语句当中,一旦执行整个switch语句like结束. 2.还可以用在循环语句当中,一旦执行,整个循环语句立刻结束,打断循环 关 ...