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

Zur*_*urb 10 c# excel clipboard interop image

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

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

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

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

问题1:

使用.NET Clipboard类,我无法从剪贴板中获取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();
}
Run Code Online (Sandbox Code Playgroud)

使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

有人有解决方案吗?(我正在使用.NET 2.0顺便说一句)

Dir*_*mar 5

根据我从你的问题中了解到的情况,我无法重现该问题。

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

关于你的第二个问题:据我所知,在 Excel 中不可能同时选择单元格区域和图像。如果您想同时在图像中获取两者,您可能必须将 Excel 工作表打印为图像/PDF/XPS 文件。


Joe*_*son 4

SpreadsheetGear for .NET可以做到这一点。

您可以在此处查看我们的 ASP.NET(C# 和 VB)“ Excel 图表和范围成像示例”示例如果您想试用,请在此处下载免费试用版。

SpreadsheetGear 还可以与 Windows 窗体、控制台应用程序等配合使用...(您没有指定要创建的应用程序类型)。如果您真正想要的话,还有一个 Windows 窗体控件可以在您的应用程序中显示工作簿。

免责声明:我拥有 SpreadsheetGear LLC