diff --git a/COP/COP.csproj b/COP/COP.csproj
index 060aa1c..be0e99b 100644
--- a/COP/COP.csproj
+++ b/COP/COP.csproj
@@ -7,4 +7,10 @@
enable
+
+
+
+
+
+
diff --git a/COP/Enums/LegendPosition.cs b/COP/Enums/LegendPosition.cs
new file mode 100644
index 0000000..085d71e
--- /dev/null
+++ b/COP/Enums/LegendPosition.cs
@@ -0,0 +1,10 @@
+namespace COP.Enums
+{
+ public enum LegendPosition
+ {
+ Top,
+ Bottom,
+ Left,
+ Right
+ }
+}
diff --git a/COP/ExcelComponent.Designer.cs b/COP/ExcelComponent.Designer.cs
new file mode 100644
index 0000000..899d032
--- /dev/null
+++ b/COP/ExcelComponent.Designer.cs
@@ -0,0 +1,36 @@
+namespace COP
+{
+ partial class ExcelComponent
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Освободить все используемые ресурсы.
+ ///
+ /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Код, автоматически созданный конструктором компонентов
+
+ ///
+ /// Требуемый метод для поддержки конструктора — не изменяйте
+ /// содержимое этого метода с помощью редактора кода.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
diff --git a/COP/ExcelComponent.cs b/COP/ExcelComponent.cs
new file mode 100644
index 0000000..d0bbd40
--- /dev/null
+++ b/COP/ExcelComponent.cs
@@ -0,0 +1,73 @@
+using COP.Info;
+using NPOI.SS.UserModel;
+using NPOI.XSSF.UserModel;
+using System.ComponentModel;
+
+namespace COP
+{
+ public partial class ExcelComponent : Component
+ {
+ public ExcelComponent()
+ {
+ InitializeComponent();
+ }
+
+ public ExcelComponent(IContainer container)
+ {
+ container.Add(this);
+ InitializeComponent();
+ }
+
+ public void GenerateExcelWithImages(ExcelImageInfo info)
+ {
+ if (string.IsNullOrEmpty(info.fileName))
+ {
+ throw new ArgumentNullException(nameof(info.fileName), "File name cannot be null or empty.");
+ }
+ if (info.images == null || info.images.Count == 0)
+ {
+ throw new ArgumentException("At least one image must be provided.", nameof(info.images));
+ }
+
+ if (string.IsNullOrEmpty(info.documentTitle))
+ {
+ throw new ArgumentNullException(nameof(info.documentTitle), "Document title cannot be null or empty.");
+ }
+
+ var workbook = new XSSFWorkbook();
+ var sheet = workbook.CreateSheet("Sheet1");
+ sheet.CreateRow(0).CreateCell(0).SetCellValue(info.documentTitle);
+
+ int startRowIndex = 2;
+ var rowOffset = 1;
+
+ foreach (var imageInfo in info.images)
+ {
+ using var fs = new FileStream(imageInfo.FilePath, FileMode.Open, FileAccess.Read);
+ var imageBytes = new byte[fs.Length];
+ fs.Read(imageBytes, 0, imageBytes.Length);
+
+ var pictureIdx = workbook.AddPicture(imageBytes, PictureType.JPEG);
+ var drawing = sheet.CreateDrawingPatriarch();
+ var anchor = new XSSFClientAnchor(0, 0, 0, 0, 0, startRowIndex, 1, startRowIndex + 1);
+ var picture = drawing.CreatePicture(anchor, pictureIdx);
+
+ picture.Resize();
+
+ var pictureHeight = picture.GetImageDimension().Height / 20;
+
+ startRowIndex += pictureHeight + rowOffset;
+ }
+
+ using (var fs = new FileStream(info.fileName, FileMode.Create, FileAccess.Write))
+ {
+ workbook.Write(fs);
+ }
+ }
+
+ public class ImageInfo
+ {
+ public string? FilePath { get; set; }
+ }
+ }
+}
diff --git a/COP/ExcelTable.Designer.cs b/COP/ExcelTable.Designer.cs
new file mode 100644
index 0000000..2bfd261
--- /dev/null
+++ b/COP/ExcelTable.Designer.cs
@@ -0,0 +1,36 @@
+namespace COP
+{
+ partial class ExcelTable
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Освободить все используемые ресурсы.
+ ///
+ /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Код, автоматически созданный конструктором компонентов
+
+ ///
+ /// Требуемый метод для поддержки конструктора — не изменяйте
+ /// содержимое этого метода с помощью редактора кода.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
diff --git a/COP/ExcelTable.cs b/COP/ExcelTable.cs
new file mode 100644
index 0000000..decc08c
--- /dev/null
+++ b/COP/ExcelTable.cs
@@ -0,0 +1,215 @@
+using COP.Info;
+using NPOI.HSSF.Util;
+using NPOI.SS.UserModel;
+using NPOI.XSSF.UserModel;
+using System.ComponentModel;
+using BorderStyle = NPOI.SS.UserModel.BorderStyle;
+
+namespace COP
+{
+ public partial class ExcelTable : Component
+ {
+ public ExcelTable()
+ {
+ InitializeComponent();
+ }
+
+ public ExcelTable(IContainer container)
+ {
+ container.Add(this);
+
+ InitializeComponent();
+ }
+
+ public void GenerateDocument(ExcelTableInfo info)
+ {
+ if (string.IsNullOrEmpty(info.FilePath))
+ {
+ throw new ArgumentException("File path is null or empty.");
+ }
+ if (string.IsNullOrEmpty(info.DocumentTitle))
+ {
+ throw new ArgumentException("Document title is null or empty.");
+ }
+ if (info.Data == null || info.Data.Count == 0)
+ {
+ throw new ArgumentException("Data is null or empty.");
+ }
+
+ // Создание документа и листа
+ var workbook = new XSSFWorkbook();
+ var sheet = workbook.CreateSheet("Sheet1");
+
+ // Установка заголовка документа в первой строке листа
+ sheet.CreateRow(0).CreateCell(0).SetCellValue(info.DocumentTitle);
+
+ int posString = 2;
+ int posColumn = 1;
+ List properties = new();
+
+ foreach (var property in info.Properties)
+ {
+ if (property.Value.Item1.Count == 1)
+ {
+ var cell1 = sheet.GetRow(posString).CreateCell(posColumn);
+ cell1.SetCellValue(property.Key);
+ cell1.CellStyle.FillPattern = FillPattern.SolidForeground;
+ cell1.CellStyle.FillForegroundColor = HSSFColor.LightGreen.Index;
+ properties.Add(property.Key);
+ posString++;
+ continue;
+ }
+
+ var cell = sheet.GetRow(posString).CreateCell(posColumn);
+ cell.SetCellValue(property.Key);
+ cell.CellStyle.Rotation = 180;
+ cell.CellStyle.FillPattern = FillPattern.SolidForeground;
+ cell.CellStyle.FillForegroundColor = HSSFColor.Aqua.Index;
+ sheet.SetColumnWidth(posColumn, sheet.DefaultColumnWidth);
+
+ posColumn++;
+
+ foreach (var field in property.Value.Item1)
+ {
+ int id = property.Value.Item1.IndexOf(field);
+ var cellValue = sheet.GetRow(posString).CreateCell(posColumn);
+ cellValue.SetCellValue(field);
+ cellValue.CellStyle.FillPattern = FillPattern.SolidForeground;
+ cellValue.CellStyle.FillForegroundColor = HSSFColor.Aqua.Index;
+ sheet.GetRow(posString).Height = (short)property.Value.Item2[id];
+ properties.Add(field);
+ posString++;
+ }
+ posColumn--;
+ }
+
+ posColumn = 3;
+
+ foreach (var data in info.Data)
+ {
+ posString = 2;
+
+ var type = data.GetType();
+
+ foreach (var property in properties)
+ {
+ var cellValue = sheet.GetRow(posString).CreateCell(posColumn);
+ cellValue.SetCellValue((string)(type.GetField(property) == null ? type.GetProperty(property).GetValue(data) : type.GetField(property).GetValue(data)));
+ posString++;
+ }
+ posColumn++;
+ }
+
+ /*var dataCellStyle = GetDataCellStyle(workbook);
+
+ for (int row = 0; row < info.HeaderTitles.Count; row++)
+ {
+ // Создание заголовков для шапки таблицы
+ var headerRow = sheet.CreateRow(row + 1);
+ var headerCellStyle = GetHeaderCellStyle(workbook);
+ var cell = headerRow.CreateCell(0);
+ cell.SetCellValue(info.HeaderTitles[row]);
+ cell.CellStyle = headerCellStyle;
+ // Заполнение таблицы
+ for (int col = 0; col < info.Data.Count; col++)
+ {
+ var dataCell = headerRow.CreateCell(col + 2);
+ var value = GetPropertyValue(info.Data[col], row);
+ dataCell.SetCellValue(value.ToString());
+ dataCell.CellStyle = dataCellStyle;
+ }
+ }*/
+
+ // Объединение ячеек в шапке таблицы
+ /*for (int i = 0; i < info.MergeInfo.Count; i++)
+ {
+ var cellMergeInfo = info.MergeInfo[i];
+ var mergeStartCellRef = CellReference.ConvertNumToColString(cellMergeInfo.StartCol) + (cellMergeInfo.StartRow + 1);
+ var mergeEndCellRef = CellReference.ConvertNumToColString(cellMergeInfo.EndCol) + (cellMergeInfo.EndRow + 1);
+
+ sheet.AddMergedRegion(new CellRangeAddress(cellMergeInfo.StartRow, cellMergeInfo.EndRow, cellMergeInfo.StartCol, cellMergeInfo.EndCol));
+
+ var mergeCell = sheet.GetRow(cellMergeInfo.StartRow).CreateCell(cellMergeInfo.StartCol);
+ mergeCell.SetCellValue(cellMergeInfo.Value);
+ }*/
+
+ /*for (int row = 0; row < info.HeaderTitles.Count; row++)
+ {
+ sheet.AddMergedRegion(new CellRangeAddress(row, row, 0, 1));
+ foreach (var merge in info.MergeInfo)
+ if (merge.Value != "")
+ {
+ sheet.RemoveMergedRegion(row)
+ }
+ foreach (var mergedRegion in mergedRegions)
+ {
+ sheet.RemoveMergedRegion(mergedRegion);
+ }
+ }*/
+
+ /*foreach (var merge in info.MergeInfo)
+ {
+ for (int row = 0; row < info.HeaderTitles.Count; row++)
+ {
+ if (merge.Value != "")
+ {
+ var valueCell = sheet.GetRow(row + 1).GetCell(0);
+ valueCell.SetCellValue(merge.Value);
+ sheet.AddMergedRegion(new CellRangeAddress(merge.StartRow, merge.EndRow, merge.StartCol, merge.EndCol));
+ }
+ else
+ {
+ sheet.AddMergedRegion(new CellRangeAddress(merge.StartRow, merge.EndRow, 0, 1));
+ }
+ }
+ }*/
+
+ /*// Задание высоты строк
+ for (int i = 0; i < info.MergeInfo.Count; i++)
+ {
+ var row = sheet.GetRow(i);
+ if (row != null)
+ {
+ row.Height = (short)(info.MergeInfo[i].RowHeight * 20);
+ }
+ }*/
+
+ using var fs = new FileStream(info.FilePath, FileMode.Create, FileAccess.Write);
+ workbook.Write(fs);
+ }
+
+ private static object GetPropertyValue(object obj, int columnIndex)
+ {
+ var properties = obj.GetType().GetProperties();
+ var field = properties[columnIndex];
+
+ return field.GetValue(obj);
+ }
+
+ private static ICellStyle GetHeaderCellStyle(IWorkbook workbook)
+ {
+ var style = workbook.CreateCellStyle();
+ style.BorderBottom = BorderStyle.Thin;
+ style.BorderLeft = BorderStyle.Thin;
+ style.BorderRight = BorderStyle.Thin;
+ style.BorderTop = BorderStyle.Thin;
+
+ var font = workbook.CreateFont();
+ font.Boldweight = (short)FontBoldWeight.Bold;
+ style.SetFont(font);
+
+ return style;
+ }
+
+ private static ICellStyle GetDataCellStyle(IWorkbook workbook)
+ {
+ var style = workbook.CreateCellStyle();
+ style.BorderBottom = BorderStyle.Thin;
+ style.BorderLeft = BorderStyle.Thin;
+ style.BorderRight = BorderStyle.Thin;
+ style.BorderTop = BorderStyle.Thin;
+
+ return style;
+ }
+ }
+}
diff --git a/COP/Info/DataItem.cs b/COP/Info/DataItem.cs
new file mode 100644
index 0000000..1255d06
--- /dev/null
+++ b/COP/Info/DataItem.cs
@@ -0,0 +1,8 @@
+namespace COP.Info
+{
+ public class DataItem
+ {
+ public string Name { get; set; } = string.Empty;
+ public double Value { get; set; }
+ }
+}
diff --git a/COP/Info/ExcelChartInfo.cs b/COP/Info/ExcelChartInfo.cs
new file mode 100644
index 0000000..998f582
--- /dev/null
+++ b/COP/Info/ExcelChartInfo.cs
@@ -0,0 +1,22 @@
+using COP.Enums;
+
+namespace COP.Info
+{
+ public class ExcelChartInfo
+ {
+ public string? filePath { get; set; } = string.Empty;
+ public string? documentTitle { get; set; } = string.Empty;
+ public string? chartTitle { get; set; } = string.Empty;
+ public LegendPosition legendPosition { get; set; }
+ public List? data { get; set; }
+
+ public ExcelChartInfo(string? filePath, string? documentTitle, string? chartTitle, LegendPosition legendPosition, List? data)
+ {
+ this.filePath = filePath;
+ this.documentTitle = documentTitle;
+ this.chartTitle = chartTitle;
+ this.legendPosition = legendPosition;
+ this.data = data;
+ }
+ }
+}
diff --git a/COP/Info/ExcelImageInfo.cs b/COP/Info/ExcelImageInfo.cs
new file mode 100644
index 0000000..a43e1e2
--- /dev/null
+++ b/COP/Info/ExcelImageInfo.cs
@@ -0,0 +1,18 @@
+using static COP.ExcelComponent;
+
+namespace COP.Info
+{
+ public class ExcelImageInfo
+ {
+ public string? fileName { get; set; } = string.Empty;
+ public string? documentTitle { get; set; } = string.Empty;
+ public List? images { get; set; }
+
+ public ExcelImageInfo (string? fileName, string? documentTitle, List? images)
+ {
+ this.fileName = fileName;
+ this.documentTitle = documentTitle;
+ this.images = images;
+ }
+ }
+}
diff --git a/COP/Info/ExcelTableInfo.cs b/COP/Info/ExcelTableInfo.cs
new file mode 100644
index 0000000..4596ca8
--- /dev/null
+++ b/COP/Info/ExcelTableInfo.cs
@@ -0,0 +1,77 @@
+namespace COP.Info
+{
+ public class ExcelTableInfo
+ {
+ public string? FilePath { get; set; } = string.Empty;
+ public string? DocumentTitle { get; set; } = string.Empty;
+ public List