I'm triying to generate an image from an excel worksheet. After a lot of research, I'm using the following code, but at some point I get an exception:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
namespace ConsoleApplication1
{
class Prueba
{
[STAThread]
static void Main(string[] args)
{
var a = new Microsoft.Office.Interop.Excel.Application();
try
{
Workbook w = a.Workbooks.Open(@"C:\SCRATCH\Libro2.xlsx");
Worksheet ws = w.Sheets["Report"];
ws.Protect(Contents: false);
Range r = ws.Range["B2:H20"];
r.CopyPicture(XlPictureAppearance.xlScreen, XlCopyPictureFormat.xlBitmap);
a.DisplayAlerts = false;
// System.Runtime.InteropServices.COMException Excepción de HRESULT: 0x80010105 (RPC_E_SERVERFAULT)
ChartObject chartObj = ws.ChartObjects().Add(r.Left, r.Top, r.Width, r.Height);
chartObj.Activate();
Chart chart = chartObj.Chart;
chart.Paste();
chart.Export(@"C:\SCRATCH\image.JPG", "JPG");
chartObj.Delete();
w.Close(SaveChanges: false);
}
finally
{
a.Quit();
}
}
}
}
I'm using Office 2013, 64 bits, Windows 7 64 and .Net 4.5.
This worked for me in a WinForms project:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using ios = System.Runtime.InteropServices;
namespace ClipBoardTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void ExportRangeAsJpg()
{
Excel.Application xl;
xl = (Excel.Application)ios.Marshal.GetActiveObject("Excel.Application");
if (xl == null)
{
MessageBox.Show("No Excel !!");
return;
}
Excel.Workbook wb = xl.ActiveWorkbook;
Excel.Range r = wb.ActiveSheet.Range["A1:E10"];
r.CopyPicture(Excel.XlPictureAppearance.xlScreen,
Excel.XlCopyPictureFormat.xlBitmap);
if (Clipboard.GetDataObject() != null)
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
Image image = (Image)data.GetData(DataFormats.Bitmap, true);
this.pict1.Image = image;
image.Save(@"C:\_Stuff\test\sample.jpg",
System.Drawing.Imaging.ImageFormat.Jpeg);
}
else
{
MessageBox.Show("No image in Clipboard !!");
}
}
else
{
MessageBox.Show("Clipboard Empty !!");
}
}
private void button1_Click(object sender, EventArgs e)
{
ExportRangeAsJpg();
}
}
}
For a console app you need to see also: http://blog.another-d-mention.ro/programming/c/use-clipboard-copypaste-in-c-console-application/
No need to create a Chart
object. Calling CopyPicture()
on the Range
puts the image on the system clipboard. You can finish it off in as little as two steps, if you want:
Workbook w = a.Workbooks.Open(@"C:\SCRATCH\Libro2.xlsx");
Worksheet ws = w.Sheets["Report"];
ws.Protect(Contents: false);
Range r = ws.Range["B2:H20"];
r.CopyPicture(XlPictureAppearance.xlScreen, XlCopyPictureFormat.xlBitmap);
Bitmap image = new Bitmap(Clipboard.GetImage());
image.Save(@"C:\SCRATCH\image.png");
// charting code, replaced with the above
/* ChartObject chartObj = ws.ChartObjects().Add(r.Left, r.Top, r.Width, r.Height);
chartObj.Activate();
Chart chart = chartObj.Chart;
chart.Paste();
chart.Export(@"C:\SCRATCH\image.JPG", "JPG");
chartObj.Delete(); */
EDIT: Leaving all the error checking and flow control to you, but it would be wise of course to (at least) use the ContainsImage()
method of the Clipboard
class before trying to access it's content.
Might be easier in VBA :
Sub PictureSaver()
Dim ch As Chart
Charts.Add
Set ch = ActiveChart
Sheets("Sheet4").Select
Range("A1:D4").Select
Selection.CopyPicture Appearance:=xlScreen, Format:=xlPicture
ch.Select
ch.Paste
ch.Export Filename:="sample.jpg"
Application.DisplayAlerts = False
ch.Delete
Application.DisplayAlerts = True
End Sub
User contributions licensed under CC BY-SA 3.0