以编程方式(C#)将Excel转换为图像

我想通过编程(c#)将Excel文件转换为图像(每种格式都可以)。 目前,我正在使用Microsoft Interop Libraries&Office 2007,但默认情况下不支持保存图像。

所以我目前的解决方法如下:

  • 使用Microsoft Interop打开Excel文件;
  • 找出最大范围(包含数据);
  • 使用该范围的CopyPicture(),将复制数据到剪贴板。

现在棘手的部分(和我的问题):

问题1:

使用.NET剪贴板类,我不能从剪贴板中得到正确的复制数据:数据是相同的,但不知何故格式化是扭曲的(整个文件的字体似乎变得粗体和一点点当他们不是可读的时候); 如果我使用mspaint.exe从剪贴板粘贴,粘贴的图像是正确的(就像我想要的那样)。

我反汇编mspaint.exe,并发现它正在使用(OleGetClipboard)从剪贴板中获取数据的函数,但我似乎无法得到它在C#/ .NET中的工作。

我尝试的其他事情是剪贴板WINAPI(OpenClipboard,GetClipboardData,CF_ENHMETAFILE),但结果与使用.NET版本相同。

问题2:

使用范围和CopyPicture,如果Excel表格中有任何图像,这些图像不会与周围的数据一起复制到剪贴板。

一些源代码

Excel.Application app = new Excel.Application(); app.Visible = app.ScreenUpdating = app.DisplayAlerts = false; app.CopyObjectsWithCells = true; app.CutCopyMode = Excel.XlCutCopyMode.xlCopy; app.DisplayClipboardWindow = false; try { Excel.Workbooks workbooks = null; Excel.Workbook book = null; Excel.Sheets sheets = null; try { workbooks = app.Workbooks; book = workbooks.Open(inputFile, false, false, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); sheets = book.Worksheets; } catch { Cleanup(workbooks, book, sheets); //Cleanup function calls Marshal.ReleaseComObject for all passed objects throw; } for (int i = 0; i < sheets.Count; i++) { Excel.Worksheet sheet = (Excel.Worksheet)sheets.get_Item(i + 1); Excel.Range myrange = sheet.UsedRange; Excel.Range rowRange = myrange.Rows; Excel.Range colRange = myrange.Columns; int rows = rowRange.Count; int cols = colRange.Count; //Following is used to find range with data string startRange = "A1"; string endRange = ExcelColumnFromNumber(cols) + rows.ToString(); //Skip "empty" excel sheets if (startRange == endRange) { Excel.Range firstRange = sheet.get_Range(startRange, endRange); Excel.Range cellRange = firstRange.Cells; object text = cellRange.Text; string strText = text.ToString(); string trimmed = strText.Trim(); if (trimmed == "") { Cleanup(trimmed, strText, text, cellRange, firstRange, myrange, rowRange, colRange, sheet); continue; } Cleanup(trimmed, strText, text, cellRange, firstRange); } Excel.Range range = sheet.get_Range(startRange, endRange); try { range.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture); //Problem here <------------- //Every attempt to get data from Clipboard fails } finally { Cleanup(range); Cleanup(myrange, rowRange, colRange, sheet); } } //end for loop book.Close(false, Type.Missing, Type.Missing); workbooks.Close(); Cleanup(book, sheets, workbooks); } finally { app.Quit(); Cleanup(app); GC.Collect(); } 

使用WINAPI从剪贴板获取数据成功,但质量差。 资源:

 protected virtual void ClipboardToPNG(string filename) { if (OpenClipboard(IntPtr.Zero)) { if (IsClipboardFormatAvailable((int)CLIPFORMAT.CF_ENHMETAFILE)) { int hEmfClp = GetClipboardDataA((int)CLIPFORMAT.CF_ENHMETAFILE); if (hEmfClp != 0) { int hEmfCopy = CopyEnhMetaFileA(hEmfClp, null); if (hEmfCopy != 0) { Metafile metafile = new Metafile(new IntPtr(hEmfCopy), true); metafile.Save(filename, ImageFormat.Png); } } } CloseClipboard(); } } 

任何人都有解决办法? (我使用.NET 2.0 btw)

SpreadsheetGear for .NET将做到这一点。

您可以在这里看到我们的ASP.NET(C#和VB)“ Excel图表和范围图像样本 ”样本,如果您想试用,请在此下载免费试用版。

SpreadsheetGear还可以与Windows窗体,控制台应用程序等一起使用(您没有指定要创build的应用程序的types)。 还有一个Windows窗体控件来显示您的应用程序中的工作簿,如果这是你真的以后。

免责声明:我自己的SpreadsheetGear LLC

从我的理解你的问题我不能重现这个问题。

我在Excel中手动select一个范围,select复制为图片屏幕上显示的选项和位图select,然后我使用下面的代码保存剪贴板数据:

 using System; using System.IO; using System.Windows; using System.Windows.Media.Imaging; using System.Drawing.Imaging; using Excel = Microsoft.Office.Interop.Excel; public class Program { [STAThread] static void Main(string[] args) { Excel.Application excel = new Excel.Application(); Excel.Workbook wkb = excel.Workbooks.Add(Type.Missing); Excel.Worksheet sheet = wkb.Worksheets[1] as Excel.Worksheet; Excel.Range range = sheet.Cells[1, 1] as Excel.Range; range.Formula = "Hello World"; // copy as seen when printed range.CopyPicture(Excel.XlPictureAppearance.xlPrinter, Excel.XlCopyPictureFormat.xlPicture); // uncomment to copy as seen on screen //range.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlBitmap); Console.WriteLine("Please enter a full file name to save the image from the Clipboard:"); string fileName = Console.ReadLine(); using (FileStream fileStream = new FileStream(fileName, FileMode.Create)) { if (Clipboard.ContainsData(System.Windows.DataFormats.EnhancedMetafile)) { Metafile metafile = Clipboard.GetData(System.Windows.DataFormats.EnhancedMetafile) as Metafile; metafile.Save(fileName); } else if (Clipboard.ContainsData(System.Windows.DataFormats.Bitmap)) { BitmapSource bitmapSource = Clipboard.GetData(System.Windows.DataFormats.Bitmap) as BitmapSource; JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); encoder.QualityLevel = 100; encoder.Save(fileStream); } } object objFalse = false; wkb.Close(objFalse, Type.Missing, Type.Missing); excel.Quit(); } } 

关于你的第二个问题:据我所知在Excel中不可能同时select一个单元格范围和一个图像。 如果您想同时获取图像,则可能需要将Excel工作表打印到图像/ PDF / XPS文件。

在将元文件转换为位图格式时,这是GDI +的一个错误。
对于许多EMF来说,它会显示带有文本的图表。 要重新创build,只需要在Excel中创build一个显示其X轴和Y轴数据的图表。 复制图表作为图片并粘贴在单词中作为图元文件。 打开docx,您将在媒体文件夹中看到一个EMF。 如果您现在在任何基于Windows的绘图程序中将EMF打开,将其转换为位图,您将看到扭曲,尤其是文本和线条变得更大和扭曲。 不幸的是,这是微软不太可能承认或做任何事情的其中一个问题。 希望谷歌和苹果能很快接pipe办公室/文字处理世界。

由于asp.net线程没有合适的ApartmentState来访问剪贴板类,所以您必须编写代码才能在新线程中访问剪贴板。 例如:

 private void AccessClipboardThread() { // access clipboard here normaly } 

在主线程中:

 .... Excel.Range range = sheet.get_Range(startRange, endRange); //Save range image to clipboard Thread thread = new Thread(new ThreadStart(AccessClipboardThread)); thread.ApartmentState = ApartmentState.STA; thread.Start(); thread.Join(); //main thread will wait until AccessClipboardThread finish. .... 

有趣的是,我一直在一个STA的隔间里做了一段时间的成功。 我编写了一个每周运行的应用程序,并发布了项目状态报告,包括一些使用Excel编程生成的图表。

昨天晚上这个失败的图表全部返回null。 我今天正在debugging,没有find解释只是方法Clipboard.GetImage()突然返回null,它没有。 通过在此调用中设置断点,我可以有效地演示(通过在MS-Word中按CTRL + V)图像确实在剪贴板中。 唉继续Clipboard.GetImage()返回null(不pipe我是否这样snooping)。

我的代码作为控制台应用程序运行,Main方法具有[STAThread]属性。 我debugging它作为一个Windows窗体应用程序(我所有的代码是在一个库中,我只是有两个前端)。

两者今天都返回null。

出于兴趣,我将图表获取器分解为一个线程(并注意thread.ApartmentState已被弃用),它运行得很好,但是仍然返回空值。

那么,我放弃了,做任何IT怪胎会做,重新启动。

瞧,一切都很好。 去图…这就是为什么我们都讨厌电脑,微软Windows和微软Office? 嗯…有什么东西,完全是短暂的,可以发生在你的电脑,使Clipboard.GetImage()失败!

如果您不介意Linux(风格),您可以使用OpenOffice(或LibreOffice)将xls首先转换为pdf,然后使用ImageMagic将PDF转换为图像。 基本指南可以在http://www.novell.com/communities/node/5744/c-linux-thumbnail-generation-pdfdocpptxlsimagesfind&#x3002;

另外,上面提到的两个程序似乎都有.Net API。 请参阅: http : //www.opendocument4all.com/download/OpenOffice.net.pdf和http://imagemagick.net/script/api.php#dotnet