I need to be able to convert all charts in an excel spreadsheet to images programmatically (via c#),
I've tried Aspose.cells and it works perfectly, but i need a free alternative.
EPplus and other non-commercial libraries i know do not have the ability to do this,
and i'm in an web environment so I cannot use Office Interop.
My question is: is there any way I can programmatically read an .xlsx file and swap every chart it contains for an image of said chart, without depending on a paid library ?
Try Spire.Xls
var wb = new Spire.Xls.Workbook();
var sheet=wb.Worksheets[0];
//Replace charts with png
var charts = summarySheet.Charts.Select(x => (Chart)x).ToArray();
if (charts.Any())
{
var imgs = wb.SaveChartAsImage(summarySheet); //same indexes as chart obj arr
for (int i = 0; i <= charts.Length - 1; i++)
{
var chart = charts[i];
var chartImg = imgs[i];
summarySheet.Pictures.Add(chart.TopRow, chart.LeftColumn, chartImg, 100, 100, ImageFormatType.Png);
}
}
Have you tried ClosedXML.Excel in nuget?
XLSX support
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell("A1").Value = "Hello World!";
worksheet.Cell("A2").FormulaA1 = "=MID(A1, 7, 5)";
workbook.SaveAs("HelloWorld.xlsx");
}
source https://github.com/ClosedXML/ClosedXML
Related
I'm using the latest 4.5.3.3 nuget version. .NET 4.6.1.
No issues if I create an excel file from scratch, but if I need to update an existing one, even if passing it to the ExcelPackage ctor and calling a ExcelPackage.Save after updating the data, or create a copy of the original excel file to pass to ExcelPackage ctor I obtain the same result.
FileInfo exc = new FileInfo(destPath);
using (var ep = new ExcelPackage(exc))
{
foreach (var sheet in _resultTranslations.Keys)
{
List<string> sheetTrs = _resultTranslations[sheet];
var ws = ep.Workbook.Worksheets[sheet];
if (ws == null)
continue;
for (int r = 0; r < sheetTrs.Count; r++)
{
ws.Cells[2 + r, 6].Value = sheetTrs[r];
}
}
ep.Save();
}
UPDATE:
If I open the Excel file with Office 2016, and save it without any changes, EEPlus updates it correctly (it's no more blank).
Any suggestion?
Thanks.
I want to use EPPlus to input data and calculate it.
Here is my code:
ExcelWorksheet sheet = ep.Workbook.Worksheets["input"];
sheet.Cells[1, 1].Value = 10;
ep.Workbook.Calculate();
string test = sheet.Cells[1, 5].Text;
ep.Save();
The string test is "#NAME?"
It seems that EPPlus did not load user define function.
When I open the saved file, the calculation will be done automatically.
What should I do to make the user defined function work?
(I'll use this feature later in the ASP.NET to call User define functions in exist excel file.I tried Interop, it can achieve what I want, but a lot slower.)
Thanks!
The formula calc engine in EPPlus cannot execute VBA functions in the workbook. It supports approx. 150 common built in Excel formulas and nothing more than that.
However, you can implement your VBA functions in .NET code. Each function should inherit the EPPlus class ExcelFunction and be registred to EPPlus via the Workbook.FormulaParserManager given the same function name as your VBA functions.
There are samples that illustrates this (create custom functions) in the EPPlus Samples project which can be downloaded from Codeplex.
For version 4.1, you can download the solution "EPPlus with samples" here:
https://epplus.codeplex.com/releases/view/625020
Then goto the "EPPlusSamples" project and check out SampleAddFormulaFunction.cs
You need to create a vba project in Epplus which is where you would define the function. Something like this:
var fileinfo = new FileInfo(#"c:\temp\UserDefinedFunctionTest.xlsm");
if (fileinfo.Exists)
fileinfo.Delete();
var sb = new StringBuilder();
sb.AppendLine("Function test(a)");
sb.AppendLine(" test = a * 3");
sb.AppendLine("End Function");
using (var package = new ExcelPackage(fileinfo))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
workbook.CreateVBAProject();
var mod1 = workbook.VbaProject.Modules.AddModule("Module1");
mod1.Code = sb.ToString();
worksheet.Cells["A1"].Value = 5;
worksheet.Cells["A2"].Formula = "=test(A1)";
package.Save();
}
Which will look like this:
You need to set formula in ExcelWorkSheet
sheet.Cells[5, 5].Formula = "=A1*3";
This is for first row only , if you want to do in Large number of rows then you have to use loop and inside loop use formula.
I got Excel xlsx document with hyperlinks.
Hyperlinks have adresses and subaddresses (that's the way VBA call Html fragments, all after # sign)
Epplus library has Hyperlink property for every cell, but it has only first part of html address, so instead of
stackoverflow.com#footer
I got:
stackoverflow.com
Is there any way to read the html fragment part with this library ?
Code for reading hyperlinks via epplus:
FileInfo xlsxFile = new FileInfo(_filePath);
using (ExcelPackage pck = new ExcelPackage(xlsxFile))
{
var wb = pck.Workbook;
if (wb == null)
return null;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[0,0];
var hyperlink = er.Hyperlink;
It seems to be an issue with the way excel store hyperlinks and the way Epplus reads them. Excel stores the hyperlinks both in the worksheet itself as well as the relationship file for the worksheet which is a file that stores any kind of cross referencing between workbook parts (worksheets, styles, strings, etc). This all has to do with the structure of the an xlsx file which is xml based off of the OpenOffice XML standard: OpenOffice XML Info
So the problem is Epplus is relying on that relationship file which does not contain the fragment while the `hyperlink' node in the worksheet xml does. You can see all of this in its gory detail if you open up the xlsx file as a zip file by renaming it.
So, the short answer is you are forced to use the `.Value' of the cell object. Not as clean but it will work. For example, if I create a cell like this:
with this code:
var fi = new FileInfo(#"c:\temp\Html_Fragment.xlsx");
using (var pck = new ExcelPackage(fi))
{
var wb = pck.Workbook;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[1,1];
var hyperlink = er.Hyperlink;
Console.WriteLine(er.Value);
Console.WriteLine("{{Value: {0}, Hyperlink: {1}}}", er.Value, er.Hyperlink.AbsoluteUri);
}
Gives this:
{
Value: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx#Anchor_3,
Hyperlink: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx
}
I have a C# data processing application which uses EPPlus to write the final results into an excel sheet. The background color of the rows are changed based on what the data on that row signifies. Time was never an issue as I only dealt with files that were below <100MB before. However, as my requirements have changed and the files get larger, I have noticed that.. just coloring makes my application 60% slower. Removing coloring makes the application significantly faster. The snippet below is an example of the code which I use to color the data to make it visually distinguishing. I'm no expert at EPPlus but is there a way, this can be optimized to make my application faster? Or are there any better ways for me to make the rows visually distinct for the people who will end up looking at the data? Any help will be appreciated!
if (data[4] == "3")
{
// color the type 3 messages here
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.LightGray);
}
if (data[4] == "4")
{
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.BlanchedAlmond);
}
EDIT:
This is the code I use to copy the template and write the excel data into the new worksheet. p is an Excel Package which I convert to a byte Array before writing to the excel file.
Byte[] bin = p.GetAsByteArray();
File.Copy("C:\\Users\\mpas\\Desktop\\template.xlsx", "C:\\Users\\mpas\\Desktop\\result.xlsx");
using (FileStream fs = File.OpenWrite("C:\\Users\\mpas\\Desktop\\result.xlsx")) {
fs.Write(bin, 0, bin.Length);
}
Styling is much faster in EPPlus, and most Excel APIs, if you use named styles. Assign and use the style to cell in EPPlus like this ...
internal static string YourStyleName = "MyStyle";
ExcelNamedStyleXml yourStyle = excel.Workbook.Styles.CreateNamedStyle(YourStyleName);
yourStyle.Style.Font.Color.SetColor(Color.DarkRed);
yourStyle.Style.Fill.PatternType = ExcelFillStyle.Solid;
yourStyle.Style.Fill.BackgroundColor.SetColor(Color.LemonChiffon);
// ...
sheet.Cells[sourceRange].StyleName = YourStyleStyleName
Here is code to open an existing file.
FileInfo AddressList = new FileInfo("c:\test\test.xlsx");
// Open and read the XlSX file.
try
{
using (ExcelPackage package = new ExcelPackage(AddressList))
{
// Get the work book in the file
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
// Get the first worksheet
//ExcelWorksheet Worksheet = workBook.Worksheets.First();
var worksheet = package.Workbook.Worksheets[1];
I'm using EPPlus in a web application with C#. I need to read an Excel file and check its format, I tried it doing the same as this article (How do I get partial cell styling in excel using EPpplus?), and actually all format properties were ok (bold, italic, color...), but the one that I really need is to check the strike
text property and it is always set to false.
Here is an answer just so the question doesnt hang out there:
[TestMethod]
public void Strike_Format_Test()
{
//http://stackoverflow.com/questions/30517646/how-to-apply-strike-formatting-using-epplus
var existingFile = new FileInfo(#"c:\temp\StrikeFormat.xlsx");
using (var pck = new ExcelPackage(existingFile))
{
var wb = pck.Workbook;
var ws = wb.Worksheets.First();
var cell = ws.Cells["A1"];
Console.WriteLine(cell.Style.Font.Strike);
}
}