我想以编程方式将excel文件转换为图像(每种格式都可以)(c#)。目前我正在使用Microsoft Interop Libraries& Office 2007,但默认情况下不支持保存到图像。
所以我目前的解决方案如下:
现在棘手的部分(和我的问题):
问题1:
使用.NET剪贴板类,我无法从剪贴板中获取EXACT复制数据:数据是相同的,但不知何故格式化失真(整个文档的字体似乎变得粗体和在他们不是的时候更难以理解;如果我使用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顺便说一句)
答案 0 :(得分:4)
根据我对你的问题的理解,我无法重现这个问题。
我在Excel中手动选择了一个范围,选择了复制为图片,选项如屏幕上所示和 Bitmap 选中,然后我使用了以下代码保存剪贴板数据:
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中无法同时选择单元格区域和图像。如果要同时获取图像,则可能需要将Excel工作表打印到图像/ PDF / XPS文件。
答案 1 :(得分:3)
你可以看到我们的ASP.NET(C#和VB)“ Excel图表和范围成像样本”样本here并下载免费试用here如果你想尝试一下。
SpreadsheetGear也适用于Windows窗体,控制台应用程序等...(您没有指定要创建的应用程序类型)。还有一个Windows窗体控件可以在您的应用程序中显示工作簿,如果这是您真正想要的工作簿。
免责声明:我拥有SpreadsheetGear LLC
答案 2 :(得分:1)
因为asp.net线程没有正确的ApartmentState来访问Clipboard类,所以你必须编写代码来访问新线程中的Clipboard。例如:
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.
....
答案 3 :(得分:1)
在将元文件转换为位图格式时,这是GDI +的一个错误 它发生在许多显示带有文本的图表的EMF上。要重新创建,您只需在Excel中创建一个显示其X轴和Y轴数据的图表。将图表复制为图片并将文字粘贴为图元文件。打开docx,您将在媒体文件夹中看到EMF。如果您现在在任何基于窗口的绘制程序中打开该EMF将其转换为位图,您将看到扭曲,特别是文本和线条变得更大和扭曲。不幸的是,这是微软不太可能承认或做任何事情的问题之一。让我们希望谷歌和苹果很快就能接管办公室/文字处理领域。
答案 4 :(得分:0)
有趣的是,我已经在STA隔间中做了一段时间并且成功了。我编写了一个每周运行的应用程序,并邮寄出项目状态报告,包括我使用Excel以编程方式生成的一些图表。
昨晚,这些图表都失败了。我今天正在调试,并没有找到解释只是方法Clipboard.GetImage()突然返回null,但它没有。通过在此调用中设置断点,我可以有效地演示(通过在MS-Word中按CTRL + V)图像确实在剪贴板中。 Alas继续在Clipboard.GetImage()上返回null(无论我是否在这样窥探)。
我的代码作为控制台应用程序运行,Main方法具有[STAThread]属性。我将它调试为一个Windows窗体应用程序(我的所有代码都在一个库中,我只有两个前端)。
今天都返回null。
出于兴趣,我将图表提取器分离成一个概述的线程(并注意不推荐使用thread.ApartmentState),它运行得很好,但仍然会返回空值。
好吧,我放弃并做了任何IT极客会做的事情,重新启动。
瞧瞧...一切都很好。去图...这就是为什么我们都厌恶计算机,Microsoft Windows和Microsoft Office?嗯...有一些东西,一些完全短暂的东西可能发生在PC上,使得Clipboard.GetImage()失败!答案 5 :(得分:0)
如果您不介意Linux(样式),可以使用OpenOffice(或LibreOffice)将xls首先转换为pdf,然后使用ImageMagic将pdf转换为图像。可以在http://www.novell.com/communities/node/5744/c-linux-thumbnail-generation-pdfdocpptxlsimages找到基本指南。
此外,似乎有两个上述程序的.Net API。看到: http://www.opendocument4all.com/download/OpenOffice.net.pdf 和 http://imagemagick.net/script/api.php#dot-net