using Microsoft.Office.Interop.Word;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Word = Microsoft.Office.Interop.Word;
namespace MoXiaoZhu.Features.ExportAsPNG
{
//将表格转换为PNG
public class TableConverter
{
private Word.Application _wordApp;
//构造函数
public TableConverter(Word.Application wordApp)
{
_wordApp = wordApp ?? throw new ArgumentNullException(nameof(wordApp));
}
public void ConvertAllTablesToPNG(Document doc)
{
//空值校验
if (doc == null)
{
throw new ArgumentNullException(nameof(doc), "转换目标文档不能为空,请先打开Word文档");
}
MessageBox.Show($"当前文档表格数量:{doc.Tables.Count}", "调试信息");
//创建表格转换临时目录
//string tempDir = ConverterHelper.CreateTempDirectory("WordTableConverter");
string tempDir = Path.Combine(Path.GetTempPath(), "WordTableConverter");
Directory.CreateDirectory(tempDir);
//倒序遍历表格集合
for (int i = doc.Tables.Count; i >= 1; i--)
{
//获取当前要转换的表格
Table table = doc.Tables[i];
//转换单个为PNG
ConvertSingleTableToPNG(table, tempDir, doc, i);
}
}
//转换单个表格为PNG图片
private void ConvertSingleTableToPNG(Table table, string tempDir, Document doc, int tableIndex)
{
//调试
MessageBox.Show($"进入表格{tableIndex}的转换逻辑,开始执行CopyAsPicture()", "调试-步骤1");
//
//空值校验
if (table == null)
{
throw new ArgumentNullException(nameof(table), "要转换的表格不能为空");
}
//获取表格的完整范围
Range tableRange = table.Range;
//生成唯一的临时PNG文件名
string tempPngPath = Path.Combine(tempDir, $"table_{Guid.NewGuid()}.png");
try
{
//提前保存号有效Range
Range originalTableRange = table.Range.Duplicate;
int tableStartPos = originalTableRange.Start;
//检查位置有效性
if (tableStartPos < 0 || tableStartPos > doc.Content.End)
tableStartPos = doc.Content.End - 1;
//将表格以图片格式复制到剪贴板
//tableRange.Select();
//tableRange.CopyAsPicture();
table.Range.Select();
System.Threading.Thread.Sleep(300);
table.Range.Copy();
//计算安全安全的Shape尺寸
float pageWidth = doc.PageSetup.PageWidth;
float pageHeight = doc.PageSetup.PageHeight;
float leftMargin = Math.Max(doc.PageSetup.LeftMargin, 0);
float topMargin = Math.Max(doc.PageSetup.TopMargin, 0);
float shapeWidth = Math.Min(pageWidth - leftMargin - doc.PageSetup.RightMargin, pageWidth);
float shapeHeight = Math.Max(pageHeight - topMargin - doc.PageSetup.BottomMargin, pageHeight);
/*
foreach (Row row in table.Rows)
{
tableHeight += row.Height;
}
*/
Shape tempShape = doc.Shapes.AddShape(
Type: 1,
Left: leftMargin,
Top: topMargin,
Width: Math.Max(shapeWidth, 100),
Height: Math.Max(shapeHeight, 50));
/*
//粘贴为图片
tempShape.TextFrame.TextRange.PasteSpecial(
DataType: 3, //粘贴为增强型图元文件
Placement: 0
);
*/
//粘贴为图片并处理
tempShape.TextFrame.TextRange.PasteSpecial(DataType: 3);
tempShape.TextFrame.TextRange.Copy();
//导出为PNG
//tempShape.TextFrame.TextRange.Copy();
if (TryGetEnhancedMetafileFromClipboard(out Image tableImage))
{
using (tableImage)
{
tableImage.Save(tempPngPath, ImageFormat.Png);
}
}
else
{
throw new InvalidOperationException("无法从剪贴板提取表格图片");
}
//清理并替换表格
tempShape.Delete();
//保存表格的起始位置
//int tableStartPos = table.Range.Start;
//删除原表格
table.Delete();
//doc.InlineShapes.AddPicture(tempPngPath, false, true, doc.Range(tableStartPos,tableStartPos));
Range insertRange = doc.Range(tableStartPos, tableStartPos);
doc.InlineShapes.AddPicture(tempPngPath, false, true, insertRange);
MessageBox.Show($"表格{tableIndex}转换成功!", "成功");
/*
//从剪贴板提取图片为PNG
if (ConverterHelper.TryGetImageFromClipboard(out Image tableImage))
{
using (tableImage)
{
//保存为PNG格式
tableImage.Save(tempPngPath, ImageFormat.Png);
}
//删除原表格
ReplaceTableWithImage(table, tableRange, tempPngPath, doc);
}
else
{
//剪贴板提取失败
throw new InvalidOperationException($"无法从剪贴板提取表格图片(表格索引:{tableIndex})");
}
*/
}
catch (Exception ex)
{
MessageBox.Show(
$"表格{tableIndex}转换失败:\n{ex.Message}\n\n内部异常:{ex.InnerException?.Message}\n堆栈:{ex.StackTrace}",
"错误详情"
);
}
}
//从剪贴板提取EMF转为Bitmap
private bool TryGetEnhancedMetafileFromClipboard(out Image image)
{
image = null;
IDataObject data = Clipboard.GetDataObject();
//直接读取Word
if (data.GetDataPresent(DataFormats.EnhancedMetafile))
{
try
{
//先获取原始数据(句柄或流)
object emfData = data.GetData(DataFormats.EnhancedMetafile);
//数据是IntPtr
if (emfData is IntPtr emfHandle && emfHandle != IntPtr.Zero)
{
//接管句柄所有权
using (var tempMetafile = new Metafile(emfHandle, true))
using (var ms = new MemoryStream())
{
tempMetafile.Save(ms, ImageFormat.Emf);
ms.Position = 0;
using (var clonedMetafile = new Metafile(ms))
{
image = new Bitmap(clonedMetafile.Width, clonedMetafile.Height);
using (var g = Graphics.FromImage(image))
{
g.Clear(Color.White);
g.DrawImage(clonedMetafile, 0, 0);
}
}
}
}
else if (emfData is Stream stream)
{
stream.Position = 0;
using (var clonedMetafile = new Metafile(stream))
{
//var emf = data.GetData(DataFormats.EnhancedMetafile) as Metafile;
//if (emf == null) return false;
//将EMF渲染成白底Bitmap
image = new Bitmap(clonedMetafile.Width, clonedMetafile.Height);
using (var g = Graphics.FromImage(image))
{
g.Clear(Color.White);
g.DrawImage(clonedMetafile, 0, 0);
}
return true;
}
}
else
{
//无法识别的数据类型,降级为Bitmap
return TryGetBitmapFromClipboard(out image);
}
return image != null;
}
catch (Exception ex)
{
Debug.WriteLine($"EMF处理崩溃:{ex.Message}");
image?.Dispose();
image = null;
return TryGetBitmapFromClipboard(out image);
}
}
//直接获取Bitmap
return TryGetBitmapFromClipboard(out image);
}
//备选方案:直接获取Bitmap
private bool TryGetBitmapFromClipboard(out Image image)
{
image = null;
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
image = data.GetData(DataFormats.Bitmap) as Image;
return image != null;
}
return false;
}
//删除原表格并在原位置插入PNG
private void ReplaceTableWithImage(Table table, Range insertRange, string pngFilePath, Document doc)
{
//删除原表格
table.Delete();
//在原表格位置插入内联PNG图片
doc.InlineShapes.AddPicture(
FileName: pngFilePath,
LinkToFile: false,
SaveWithDocument: true,
Range: insertRange
);
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace MoXiaoZhu.Features.ExportAsPNG
{
public static class ConverterHelper
{
//创建插件临时目录
public static string CreateTempDirectory(string subDirName)
{
//参数校验:避免创建空名称目录
if (string.IsNullOrWhiteSpace(subDirName))
{
throw new ArgumentException("临时子目录名称不能为空或空白", nameof(subDirName));
}
//获取系统临时目录 C:\Users\[用户名]\AppData\Local\Temp
string systemTempRoot = Path.GetTempPath();
//拼接系统临时目录和自定义子目录
string customTempDir = Path.Combine(systemTempRoot, subDirName);
//确保目录存在
if (!Directory.Exists(customTempDir))
{
Directory.CreateDirectory(customTempDir);
}
return customTempDir;
}
//从系统剪贴板中安全提取图片
public static bool TryGetImageFromClipboard(out Image image)
{
//初始化输出参数为null
image = null;
try
{
//先检查剪贴板是否包含图片数据
if (Clipboard.ContainsImage())
{
//从剪贴板获取图片副本
image = Clipboard.GetImage();
//验证图片是否有效
return image != null;
}
//剪贴板无图片数据,返回false
return false;
}
catch (ExternalException ex)
{
//处理剪贴板访问异常
MessageBox.Show(
text: $"剪贴板访问失败:{ex.Message}\n请关闭占用剪贴板的程序后重试",
caption: "操作失败",
buttons: MessageBoxButtons.OK,
icon: MessageBoxIcon.Error);
return false;
}
catch (Exception ex)
{
//捕获其它异常
MessageBox.Show(
text: $"提取剪贴板图片时发生错误:{ex.Message}",
caption: "未知错误",
buttons: MessageBoxButtons.OK,
icon: MessageBoxIcon.Error);
return false;
}
}
}
}
private void btnConvertToPNG_Click(object sender, RibbonControlEventArgs e)
{
try
{
Word.Application wordApp = Globals.ThisAddIn.Application;
/*
//获取Word应用实例
if (_wordApp == null)
{
throw new InvalidOperationException("无法获取Word应用程序实例");
}
*/
//获取活动文档
Document activeDoc = _wordApp.ActiveDocument;
if (activeDoc == null)
{
throw new InvalidOperationException("请先打开一个Word文档再执行转换");
}
//实例化TableConverter
var tableConverter = new TableConverter(wordApp);
//执行表格转PNG
tableConverter.ConvertAllTablesToPNG(activeDoc);
//执行转换
//imageConverter.ConvertNonPNGImagesToPNG(activeDoc);
//tableConverter.ConvertAllTablesToPNG(activeDoc);
//_wordApp.StatusBar = "转换完成!所有非PNG图片和表格已成功转换为PNG格式";
MessageBox.Show("所有表格已成功转换为PNG图片!", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
//异常处理
MessageBox.Show(
text: $"转换过程中发生错误:{ex.Message}\n\n建议:\n1. 关闭占用剪贴板的程序\n2. 确保文档未被只读保护\n3. 重启Word后重试",
caption: "转换失败",
buttons: MessageBoxButtons.OK,
icon: MessageBoxIcon.Error
);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Core;
namespace MoXiaoZhu.Features.ExportAsPNG
{
//将非PNG格式转换为PNG格式
public class ImageConverter
{
public void ConvertNonPNGImagesToPNG(Document doc)
{
if (doc == null)
throw new ArgumentNullException(nameof(doc), "文档对象不能为空");
//创建临时目录
string tempDir = ConverterHelper.CreateTempDirectory("WordImageConverter");
//倒序遍历
ProcessInlineImages(doc, tempDir);
ProcessFloatingImages(doc, tempDir);
}
//处理嵌入式图片
private void ProcessInlineImages(Document doc, string tempDir)
{
//从后往前遍历
for (int i = doc.InlineShapes.Count; i >= 1; i--)
{
InlineShape inlineShape = doc.InlineShapes[i];
//仅处理嵌入型图片
if (inlineShape.Type == WdInlineShapeType.wdInlineShapePicture)
{
ConvertSingleImage(inlineShape, tempDir, doc);
}
}
}
//处理浮动图片
private void ProcessFloatingImages(Document doc, string tempDir)
{
//从后往前遍历浮动图片
for (int i = doc.Shapes.Count; i >= 1; i--)
{
Microsoft.Office.Interop.Word.Shape shape = doc.Shapes[i];
//仅处理图片类型的浮动形状
if (shape.Type == MsoShapeType.msoPicture)
{
ConvertSingleImage(shape, tempDir, doc);
}
}
}
//转换单个图片为PNG
private void ConvertSingleImage(object shape, string tempDir, Document doc)
{
//获取图片对应的文档范围
Range imageRange = GetImageRange(shape);
//检查是否已为PNG格式
if (!IsPNGImage(shape))
{
string tempPngPath = Path.Combine(tempDir, $"img_{Guid.NewGuid()}.png");
try
{
//将图片复制为图片格式到剪贴板
imageRange.CopyAsPicture();
//从剪贴板获取并保存为PNG
if (ConverterHelper.TryGetImageFromClipboard(out var pngImage))
{
using (pngImage)
{
pngImage.Save(tempPngPath, System.Drawing.Imaging.ImageFormat.Png);
}
//删除原图,插入新图
ReplaceOriginalImage(shape, imageRange, tempPngPath, doc);
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"转换图片失败:{ex.Message}", ex);
}
}
}
//获取图片对应的文档范围
private Range GetImageRange(object shape)
{
switch (shape)
{
case InlineShape inlineShape:
return inlineShape.Range;
case Microsoft.Office.Interop.Word.Shape floatingShape:
return floatingShape.Anchor;
default:
throw new ArgumentException($"不支持的图片类型:{shape.GetType().FullName}", nameof(shape));
}
}
//检查是否已经为PNG格式
private bool IsPNGImage(object shape)
{
try
{
if (shape is InlineShape inlineShape)
{
//获取图片的链接路径
string sourcePath = inlineShape.LinkFormat?.SourcePath ?? string.Empty;
return !string.IsNullOrEmpty(sourcePath) &&
Path.GetExtension(sourcePath).Equals(".png", StringComparison.OrdinalIgnoreCase);
}
return false;
}
catch
{
return false;
}
}
//替换原来图片为新图PNG
private void ReplaceOriginalImage(object originalShape, Range targetRange, string pngFilePath, Document doc)
{
//删除原图片
targetRange.Delete();
//根据图片类型插入新的PNG图片
if (originalShape is InlineShape)
{
//插入嵌入式
doc.InlineShapes.AddPicture(
FileName: pngFilePath,
LinkToFile: false,
SaveWithDocument: true,
Range: targetRange
);
}
else if (originalShape is Microsoft.Office.Interop.Word.Shape)
{
//插入浮动型
doc.Shapes.AddPicture(
FileName: pngFilePath,
LinkToFile: false,
SaveWithDocument: true,
Anchor: targetRange
);
}
}
}
}
这是上述报错项目的全部代码,请分析一下应该如何解决这个报错问题,之前shape直接导出emf数据的方法因版本问题,部分枚举不存在不可行
最新发布