blob: 1ed100538d95785660697926eef3b748db004507 [file] [log] [blame]
/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* All rights reserved.
*
* EPPlus is an Open Source project provided under the
* GNU General Public License (GPL) as published by the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* EPPlus provides server-side generation of Excel 2007 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
*
*
* The GNU General Public License can be viewed at http://www.opensource.org/licenses/gpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* The code for this project may be used and redistributed by any means PROVIDING it is
* not sold for profit without the author's written consent, and providing that this notice
* and the author's name and all copyright notices remain intact.
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*
*
* Code change notes:
*
* Author Change Date
*******************************************************************************
* Jan Källman Added 25-JAN-2010
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing;
using OfficeOpenXml;
using OfficeOpenXml.Drawing;
using OfficeOpenXml.Drawing.Chart;
using System.Drawing.Imaging;
using OfficeOpenXml.Style;
using OfficeOpenXml.Style.XmlAccess;
using OfficeOpenXml.Table;
namespace EPPlusSamples
{
/// <summary>
/// Sample 6 - Reads the filesystem and makes a report.
/// </summary>
class Sample6
{
#region "Icon API function"
[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public IntPtr iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
public const uint SHGFI_ICON = 0x100;
public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
public const uint SHGFI_SMALLICON = 0x1; // 'Small icon
[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbSizeFileInfo,
uint uFlags);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
#endregion
public class StatItem : IComparable<StatItem>
{
public string Name { get; set; }
public int Count { get; set; }
public long Size { get; set; }
#region IComparable<StatItem> Members
//Default compare Size
public int CompareTo(StatItem other)
{
return Size < other.Size ? -1 :
(Size > other.Size ? 1 : 0);
}
#endregion
}
static int _maxLevels;
static Dictionary<string, StatItem> _extStat = new Dictionary<string, StatItem>();
static List<StatItem> _fileSize = new List<StatItem>();
/// <summary>
/// Sample 6 - Reads the filesystem and makes a report.
/// </summary>
/// <param name="outputDir">Output directory</param>
/// <param name="dir">Directory to scan</param>
/// <param name="depth">How many levels?</param>
/// <param name="skipIcons">Skip the icons in column A. A lot faster</param>
public static string RunSample6(DirectoryInfo outputDir, DirectoryInfo dir, int depth, bool skipIcons)
{
_maxLevels = depth;
FileInfo newFile = new FileInfo(outputDir.FullName + @"\sample6.xlsx");
if (newFile.Exists)
{
newFile.Delete(); // ensures we create a new workbook
newFile = new FileInfo(outputDir.FullName + @"\sample6.xlsx");
}
//Create the workbook
ExcelPackage pck = new ExcelPackage(newFile);
//Add the Content sheet
var ws = pck.Workbook.Worksheets.Add("Content");
ws.View.ShowGridLines = false;
ws.Column(1).Width = 2.5;
ws.Column(2).Width = 60;
ws.Column(3).Width = 16;
ws.Column(4).Width = 20;
ws.Column(5).Width =20;
//This set the outline for column 4 and 5 and hide them
ws.Column(4).OutlineLevel = 1;
ws.Column(4).Collapsed = true;
ws.Column(5).OutlineLevel = 1;
ws.Column(5).Collapsed = true;
ws.OutLineSummaryRight = true;
//Headers
ws.Cells["B1"].Value = "Name";
ws.Cells["C1"].Value = "Size";
ws.Cells["D1"].Value = "Created";
ws.Cells["E1"].Value = "Last modified";
ws.Cells["B1:E1"].Style.Font.Bold = true;
ws.View.FreezePanes(2,1);
ws.Select("A2");
//height is 20 pixels
double height = 20 * 0.75;
//Start at row 2;
int row = 2;
//Load the directory content to sheet 1
row = AddDirectory(ws, dir, row, height, 0, skipIcons);
ws.OutLineSummaryBelow = false;
//Format columns
ws.Cells[1, 3, row - 1, 3].Style.Numberformat.Format = "#,##0";
ws.Cells[1, 4, row - 1, 4].Style.Numberformat.Format = "yyyy-MM-dd hh:mm";
ws.Cells[1, 5, row - 1, 5].Style.Numberformat.Format = "yyyy-MM-dd hh:mm";
//Add the textbox
var shape = ws.Drawings.AddShape("txtDesc", eShapeStyle.Rect);
shape.SetPosition(1, 5, 6, 5);
shape.SetSize(400, 200);
shape.Text = "This example demonstrates how to create various drawing objects like pictures, shapes and charts.\n\r\n\rThe first sheet contains all subdirectories and files with an icon, name, size and dates.\n\r\n\rThe second sheet contains statistics about extensions and the top-10 largest files.";
shape.Fill.Style = eFillStyle.SolidFill;
shape.Fill.Color = Color.DarkSlateGray;
shape.Fill.Transparancy = 20;
shape.Border.Fill.Style = eFillStyle.SolidFill;
shape.Border.LineStyle = eLineStyle.LongDash;
shape.Border.Width = 1;
shape.Border.Fill.Color = Color.Black;
shape.Border.LineCap = eLineCap.Round;
shape.TextAnchoring = eTextAnchoringType.Top;
shape.TextVertical = eTextVerticalType.Horizontal;
shape.TextAnchoringControl=false;
ws.Calculate();
ws.Cells[1,2,row,5].AutoFitColumns();
//Add the graph sheet
AddGraphs(pck, row, dir.FullName);
//Add a HyperLink to the statistics sheet.
var namedStyle = pck.Workbook.Styles.CreateNamedStyle("HyperLink"); //This one is language dependent
namedStyle.Style.Font.UnderLine = true;
namedStyle.Style.Font.Color.SetColor(Color.Blue);
ws.Cells["K13"].Hyperlink = new ExcelHyperLink("Statistics!A1", "Statistics");
ws.Cells["K13"].StyleName = "HyperLink";
//Printer settings
ws.PrinterSettings.FitToPage = true;
ws.PrinterSettings.FitToWidth = 1;
ws.PrinterSettings.FitToHeight = 0;
ws.PrinterSettings.RepeatRows = new ExcelAddress("1:1"); //Print titles
ws.PrinterSettings.PrintArea = ws.Cells[1, 1, row - 1, 5];
pck.Workbook.Calculate();
//Done! save the sheet
pck.Save();
return newFile.FullName;
}
/// <summary>
/// This method adds the comment to the header row
/// </summary>
/// <param name="ws"></param>
private static void AddComments(ExcelWorksheet ws)
{
//Add Comments using the range class
var comment = ws.Cells["A3"].AddComment("Jan Källman:\r\n", "JK");
comment.Font.Bold = true;
var rt = comment.RichText.Add("This column contains the extensions.");
rt.Bold = false;
comment.AutoFit = true;
//Add a comment using the Comment collection
comment = ws.Comments.Add(ws.Cells["B3"],"This column contains the size of the files.", "JK");
//This sets the size and position. (The position is only when the comment is visible)
comment.From.Column = 7;
comment.From.Row = 3;
comment.To.Column = 16;
comment.To.Row = 8;
comment.BackgroundColor = Color.White;
comment.RichText.Add("\r\nTo format the numbers use the Numberformat-property like:\r\n");
ws.Cells["B3:B42"].Style.Numberformat.Format = "#,##0";
//Format the code using the RichText Collection
var rc = comment.RichText.Add("//Format the Size and Count column\r\n");
rc.FontName = "Courier New";
rc.Color = Color.FromArgb(0, 128, 0);
rc = comment.RichText.Add("ws.Cells[");
rc.Color = Color.Black;
rc = comment.RichText.Add("\"B3:B42\"");
rc.Color = Color.FromArgb(123, 21, 21);
rc = comment.RichText.Add("].Style.Numberformat.Format = ");
rc.Color = Color.Black;
rc = comment.RichText.Add("\"#,##0\"");
rc.Color = Color.FromArgb(123, 21, 21);
rc = comment.RichText.Add(";");
rc.Color = Color.Black;
}
/// <summary>
/// Add the second sheet containg the graphs
/// </summary>
/// <param name="pck">Package</param>
/// <param name="rows"></param>
/// <param name="header"></param>
private static void AddGraphs(ExcelPackage pck, int rows, string dir)
{
var ws = pck.Workbook.Worksheets.Add("Statistics");
ws.View.ShowGridLines = false;
//Set first the header and format it
ws.Cells["A1"].Value = "Statistics for ";
using (ExcelRange r = ws.Cells["A1:O1"])
{
r.Merge = true;
r.Style.Font.SetFromFont(new Font("Arial", 22, FontStyle.Regular));
r.Style.Font.Color.SetColor(Color.White);
r.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.CenterContinuous;
r.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
r.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(23, 55, 93));
}
//Use the RichText property to change the font for the directory part of the cell
var rtDir = ws.Cells["A1"].RichText.Add(dir);
rtDir.FontName = "Consolas";
rtDir.Size=18;
//Start with the Extention Size
List<StatItem> lst = new List<StatItem>(_extStat.Values);
lst.Sort();
//Add rows
int row=AddStatRows(ws, lst, 2, "Extensions", "Size");
//Add commets to the Extensions header
AddComments(ws);
//Add the piechart
var pieChart = ws.Drawings.AddChart("crtExtensionsSize", eChartType.PieExploded3D) as ExcelPieChart;
//Set top left corner to row 1 column 2
pieChart.SetPosition(1, 0, 2, 0);
pieChart.SetSize(400, 400);
pieChart.Series.Add(ExcelRange.GetAddress(3, 2, row-1, 2), ExcelRange.GetAddress(3, 1, row-1, 1));
pieChart.Title.Text = "Extension Size";
//Set datalabels and remove the legend
pieChart.DataLabel.ShowCategory = true;
pieChart.DataLabel.ShowPercent = true;
pieChart.DataLabel.ShowLeaderLines = true;
pieChart.Legend.Remove();
//Resort on Count and add the rows
lst.Sort((first,second) => first.Count < second.Count ? -1 : first.Count > second.Count ? 1 : 0);
row=AddStatRows(ws, lst, 16, "", "Count");
//Add the Doughnut chart
var doughtnutChart = ws.Drawings.AddChart("crtExtensionCount", eChartType.DoughnutExploded) as ExcelDoughnutChart;
//Set position to row 1 column 7 and 16 pixels offset
doughtnutChart.SetPosition(1, 0, 8, 16);
doughtnutChart.SetSize(400, 400);
doughtnutChart.Series.Add(ExcelRange.GetAddress(16, 2, row - 1, 2), ExcelRange.GetAddress(16, 1, row - 1, 1));
doughtnutChart.Title.Text = "Extension Count";
doughtnutChart.DataLabel.ShowPercent = true;
doughtnutChart.DataLabel.ShowLeaderLines = true;
doughtnutChart.Style = eChartStyle.Style26; //3D look
//Top-10 filesize
_fileSize.Sort();
row=AddStatRows(ws, _fileSize, 29, "Files", "Size");
var barChart = ws.Drawings.AddChart("crtFiles", eChartType.BarClustered3D) as ExcelBarChart;
//3d Settings
barChart.View3D.RotX = 0;
barChart.View3D.Perspective = 0;
barChart.SetPosition(22, 0, 2, 0);
barChart.SetSize(800, 398);
barChart.Series.Add(ExcelRange.GetAddress(30, 2, row - 1, 2), ExcelRange.GetAddress(30, 1, row - 1, 1));
//barChart.Series[0].Header = "Size";
barChart.Title.Text = "Top File size";
//Format the Size and Count column
ws.Cells["B3:B42"].Style.Numberformat.Format = "#,##0";
//Set a border around
ws.Cells["A1:A43"].Style.Border.Left.Style = ExcelBorderStyle.Thin;
ws.Cells["A1:O1"].Style.Border.Top.Style = ExcelBorderStyle.Thin;
ws.Cells["O1:O43"].Style.Border.Right.Style = ExcelBorderStyle.Thin;
ws.Cells["A43:O43"].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
ws.Cells[1, 1, row, 2].AutoFitColumns(1);
//And last the printersettings
ws.PrinterSettings.Orientation = eOrientation.Landscape;
ws.PrinterSettings.FitToPage = true;
ws.PrinterSettings.Scale = 67;
}
/// <summary>
/// Add statistic-rows to the statistics sheet.
/// </summary>
/// <param name="ws">Worksheet</param>
/// <param name="lst">List with statistics</param>
/// <param name="startRow"></param>
/// <param name="header">Header text</param>
/// <param name="propertyName">Size or Count</param>
/// <returns></returns>
private static int AddStatRows(ExcelWorksheet ws, List<StatItem> lst, int startRow, string header, string propertyName)
{
//Add Headers
int row = startRow;
if (header != "")
{
ws.Cells[row, 1].Value = header;
using (ExcelRange r = ws.Cells[row, 1, row, 2])
{
r.Merge = true;
r.Style.Font.SetFromFont(new Font("Arial", 16, FontStyle.Italic));
r.Style.Font.Color.SetColor(Color.White);
r.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.CenterContinuous;
r.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
r.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79 , 129, 189));
}
row++;
}
int tblStart=row;
//Header 2
ws.Cells[row, 1].Value = "Name";
ws.Cells[row, 2].Value = propertyName;
using (ExcelRange r = ws.Cells[row, 1, row, 2])
{
r.Style.Font.SetFromFont(new Font("Arial", 12, FontStyle.Bold));
}
row++;
//Add top 10 rows
for (int i = 0; i < 10; i++)
{
if (lst.Count - i > 0)
{
ws.Cells[row, 1].Value = lst[lst.Count - i - 1].Name;
if (propertyName == "Size")
{
ws.Cells[row, 2].Value = lst[lst.Count - i - 1].Size;
}
else
{
ws.Cells[row, 2].Value = lst[lst.Count - i - 1].Count;
}
row++;
}
}
//If we have more than 10 items, sum...
long rest = 0;
for (int i = 0; i < lst.Count - 10; i++)
{
if (propertyName == "Size")
{
rest += lst[i].Size;
}
else
{
rest += lst[i].Count;
}
}
//... and add anothers row
if (rest > 0)
{
ws.Cells[row, 1].Value = "Others";
ws.Cells[row, 2].Value = rest;
ws.Cells[row, 1, row, 2].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells[row, 1, row, 2].Style.Fill.BackgroundColor.SetColor(Color.LightGray);
row++;
}
var tbl = ws.Tables.Add(ws.Cells[tblStart, 1, row - 1, 2], null);
tbl.TableStyle = TableStyles.Medium16;
tbl.ShowTotal = true;
tbl.Columns[1].TotalsRowFunction = RowFunctions.Sum;
return row;
}
/// <summary>
/// Just alters the colors in the list
/// </summary>
/// <param name="ws">The worksheet</param>
/// <param name="row">Startrow</param>
private static void AlterColor(ExcelWorksheet ws, int row)
{
using (ExcelRange rowRange = ws.Cells[row, 1, row, 2])
{
rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
if(row % 2==1)
{
rowRange.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
}
else
{
rowRange.Style.Fill.BackgroundColor.SetColor(Color.LightYellow);
}
}
}
private static int AddDirectory(ExcelWorksheet ws, DirectoryInfo dir, int row, double height, int level, bool skipIcons)
{
//Get the icon as a bitmap
Console.WriteLine("Directory " + dir.Name);
if (!skipIcons)
{
Bitmap icon = GetIcon(dir.FullName);
ws.Row(row).Height = height;
//Add the icon as a picture
if (icon != null)
{
ExcelPicture pic = ws.Drawings.AddPicture("pic" + (row).ToString(), icon);
pic.SetPosition((int)20 * (row - 1) + 2, 0);
}
}
ws.Cells[row, 2].Value = dir.Name;
ws.Cells[row, 4].Value = dir.CreationTime;
ws.Cells[row, 5].Value = dir.LastAccessTime;
ws.Cells[row, 2, row, 5].Style.Font.Bold = true;
//Sets the outline depth
ws.Row(row).OutlineLevel = level;
int prevRow = row;
row++;
//Add subdirectories
foreach (DirectoryInfo subDir in dir.GetDirectories())
{
if (level < _maxLevels)
{
row = AddDirectory(ws, subDir, row, height, level + 1, skipIcons);
}
}
//Add files in the directory
foreach (FileInfo file in dir.GetFiles())
{
if (!skipIcons)
{
Bitmap fileIcon = GetIcon(file.FullName);
ws.Row(row).Height = height;
if (fileIcon != null)
{
ExcelPicture pic = ws.Drawings.AddPicture("pic" + (row).ToString(), fileIcon);
pic.SetPosition((int)20 * (row - 1) + 2, 0);
}
}
ws.Cells[row, 2].Value = file.Name;
ws.Cells[row, 3].Value = file.Length;
ws.Cells[row, 4].Value = file.CreationTime;
ws.Cells[row, 5].Value = file.LastAccessTime;
ws.Row(row).OutlineLevel = level+1;
AddStatistics(file);
row++;
}
//Add a subtotal for the directory
if (row -1 > prevRow)
{
ws.Cells[prevRow, 3].Formula = string.Format("SUBTOTAL(9, {0})", ExcelCellBase.GetAddress(prevRow + 1, 3, row - 1, 3));
}
else
{
ws.Cells[prevRow, 3].Value = 0;
}
return row;
}
/// <summary>
/// Add statistics to the collections
/// </summary>
/// <param name="file"></param>
private static void AddStatistics(FileInfo file)
{
//Extension
if (_extStat.ContainsKey(file.Extension))
{
_extStat[file.Extension].Count++;
_extStat[file.Extension].Size+=file.Length;
}
else
{
string ext = file.Extension.Length > 0 ? file.Extension.Remove(0, 1) : "";
_extStat.Add(file.Extension, new StatItem() { Name = ext, Count = 1, Size = file.Length });
}
//File top 10;
if (_fileSize.Count < 10)
{
_fileSize.Add(new StatItem { Name = file.Name, Size = file.Length });
if (_fileSize.Count == 10)
{
_fileSize.Sort();
}
}
else if(_fileSize[0].Size < file.Length)
{
_fileSize.RemoveAt(0);
_fileSize.Add(new StatItem { Name = file.Name, Size = file.Length });
_fileSize.Sort();
}
}
/// <summary>
/// Gets the icon for a file or directory
/// </summary>
/// <param name="FileName"></param>
/// <returns></returns>
private static Bitmap GetIcon(string FileName)
{
try
{
SHFILEINFO shinfo = new SHFILEINFO();
var ret = SHGetFileInfo(FileName,
0,
ref shinfo,
(uint)Marshal.SizeOf(shinfo),
SHGFI_ICON | SHGFI_SMALLICON);
if (shinfo.hIcon == IntPtr.Zero) return null;
Bitmap bmp = Icon.FromHandle(shinfo.hIcon).ToBitmap();
DestroyIcon(shinfo.hIcon);
//Fix transparant color
Color InvalidColor = Color.FromArgb(0, 0, 0, 0);
for (int w = 0; w < bmp.PhysicalDimension.Width; w++)
{
for (int h = 0; h < bmp.PhysicalDimension.Height; h++)
{
if (bmp.GetPixel(w, h) == InvalidColor)
{
bmp.SetPixel(w, h, Color.Transparent);
}
}
}
return bmp;
}
catch
{
return null;
}
}
}
}