我想转换一个excel文件到图像(每种格式都可以)编程(c#)。目前我正在使用Microsoft Interop Libraries & Office 2007,但默认情况下它不支持保存到图像。
所以我目前的工作方法如下:
- 使用Microsoft Interop打开Excel文件;
- 找出最大范围(包含数据);
- 对该范围使用CopyPicture(),它将数据复制到剪贴板。
现在是棘手的部分(和我的问题):
问题一:
使用.NET Clipboard类,我无法从剪贴板中获取精确的复制数据:数据是相同的,但不知何故格式被扭曲(整个文档的字体似乎变得粗体,有点更不可读,而他们没有);如果我使用mspaint.exe从剪贴板粘贴,则粘贴的图像是正确的(正如我所希望的那样)。
我反汇编了mspaint.exe,发现它正在使用一个函数(OleGetClipboard)从剪贴板中获取数据,但我似乎无法在C# /. NET中使用它。
我尝试的其他东西是剪贴板WINAPI的(OpenClipboard,GetClipboardData,CF_ENHMETAFILE),但结果与使用.NET版本相同。
问题二:
使用范围和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)
7条答案
按热度按时间lvmkulzt1#
根据我对你的问题的理解,我无法重现这个问题。
我在Excel中手动选择了一个范围,选择 * 复制为图片 *,并选择了选项 * 如屏幕所示 * 和 * 位图 *,然后我使用以下代码保存剪贴板数据:
关于你的第二个问题:据我所知,在Excel中不可能同时选择单元格区域和图像。如果您想同时在图像中获得这两个,则可能必须将Excel工作表打印到图像/PDF/XPS文件。
uhry853o2#
SpreadsheetGear for .NET可以。
您可以查看我们的ASP.NET(C#和VB)“
Excel Chart and Range Imaging Samples
”示例here,如果您想试用,请下载免费试用版here。SpreadsheetGear还可以与Windows窗体、控制台应用程序等一起工作。(您没有指定要创建的应用程序类型)。还有一个Windows窗体控件,用于在应用程序中显示工作簿(如果这是您真正需要的)。
免责声明:我拥有SpreadsheetGear LLC
dm7nw8vv3#
这是GDI+在将图元文件转换为位图格式时的一个错误。
它发生在许多显示带有文本的图表的EMF中。要重新创建,您只需在Excel中创建一个图表,显示其X轴和Y轴的数据。将图表复制为图片,然后将其粘贴为图元文件。打开docx,您将在介质文件夹中看到EMF。如果你现在在任何基于窗口的绘画程序中打开EMF,将其转换为位图,你会看到扭曲,特别是文本和线条变得更大和扭曲。不幸的是,这是微软不太可能承认或采取任何行动的问题之一。让我们希望谷歌和苹果也能很快接管办公/文字处理世界。
t9eec4r04#
因为asp.net线程没有访问Clipboard Class的正确的ApartmentState,所以必须编写代码才能在新线程中访问Clipboard。例如:
在主线程中:
dsekswqp5#
有趣的是,我已经在STA车厢里成功地做了一段时间。我写了一个应用程序,每周运行一次,并发送项目状态报告,包括一些我用Excel编程生成的图表。
昨晚这失败了,所有的图都返回null。我今天在调试,没有找到任何解释,只是方法Clipboard.GetImage()突然返回null,而它没有。通过在这个调用中设置一个断点,我可以有效地证明(通过在MS-Word中按CTRL+V)图像确实在剪贴板中。唉,在剪贴板上继续。GetImage()返回null(无论我是否这样窥探)。
我的代码作为控制台应用程序运行,Main方法具有[STAThread]属性。我把它作为一个windows窗体应用程序进行调试(我所有的代码都在一个库中,我只有两个前端)。
今天两者都返回null。
出于兴趣,我将图表提取器分离到一个线程中(注意thread.ApartmentState已被弃用),它运行正常,但仍然返回null。
好吧,我放弃了,做了任何IT极客都会做的事,重新启动。
瞧...一切都很好。想想看...这就是为什么我们都讨厌电脑,微软的Windows和微软的Office?嗯……有一些事情,一些完全暂时的事情可能会发生在你的电脑上,使Clipboard.GetImage()失败!
mzillmmw6#
如果你不介意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
0kjbasz67#
虽然问题已经回答了,但我想说明的是DevExpress can solve it too .