using System; using System.Collections.Generic; using System.IO; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using OpenCvSharp; namespace ExcelImageHelper { public class ExcelEntry { public string Name { get; set; } = ""; public Mat Image { get; set; } public List> ParametersSets { get; set; } = new List>(); public string Content { get; set; } = ""; } public class ExcelImageInserter { private IWorkbook workbook; private string filePath; private int jpgQuality; // 생성자: JPEG 품질 지정 (0~100, 기본 95) public ExcelImageInserter(string excelPath, int jpegQuality = 95) { filePath = excelPath; // Math.Clamp 대신 삼항연산으로 제한 jpgQuality = (jpegQuality < 0) ? 0 : (jpegQuality > 100 ? 100 : jpegQuality); // 폴더 존재 확인 후 없으면 생성 string folderPath = Path.GetDirectoryName(filePath); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } // 파일이 있으면 열고, 없으면 새로 생성 if (File.Exists(filePath)) { using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { workbook = new XSSFWorkbook(fs); } } else { workbook = new XSSFWorkbook(); } } // 단일 Entry 추가 public void AddEntry(ExcelEntry entry, string sheetName, double widthCm, double heightCm) { ISheet sheet = workbook.GetSheet(sheetName) ?? workbook.CreateSheet(sheetName); int startRow = 0; int startCol = 0; // Name 삽입 IRow nameRow = sheet.GetRow(startRow) ?? sheet.CreateRow(startRow); ICell nameCell = nameRow.GetCell(startCol) ?? nameRow.CreateCell(startCol); nameCell.SetCellValue(entry.Name); // 이미지 삽입 int imageRowStart = startRow + 1; // JPEG 인코딩 시 설정한 품질 적용 var jpgParams = new ImageEncodingParam[] { new ImageEncodingParam(ImwriteFlags.JpegQuality, jpgQuality) }; byte[] bytes = entry.Image.ImEncode(".jpg", jpgParams); int pictureIdx = workbook.AddPicture(bytes, PictureType.JPEG); var drawing = sheet.CreateDrawingPatriarch(); var anchor = workbook.GetCreationHelper().CreateClientAnchor(); anchor.Col1 = startCol; anchor.Row1 = imageRowStart; int cols = (int)Math.Ceiling(widthCm / 2.0); int rows = (int)Math.Ceiling(heightCm / 0.7); anchor.Col2 = startCol + cols; anchor.Row2 = imageRowStart + rows; drawing.CreatePicture(anchor, pictureIdx); // Parameters 삽입 (각 set은 column, 각 값은 row) int dataStartCol = startCol + cols + 1; // 이미지 오른쪽 첫 컬럼 int maxParamCount = 0; // ParametersSet의 최대 길이 계산 foreach (var paramSet in entry.ParametersSets) if (paramSet.Count > maxParamCount) maxParamCount = paramSet.Count; // 각 column별 최대 문자열 길이를 저장 int[] maxColWidths = new int[entry.ParametersSets.Count]; // paramValue index 기준으로 row 반복 for (int i = 0; i < maxParamCount; i++) { var rowObj = sheet.GetRow(imageRowStart + i) ?? sheet.CreateRow(imageRowStart + i); for (int j = 0; j < entry.ParametersSets.Count; j++) { var paramSet = entry.ParametersSets[j]; if (i < paramSet.Count) { string value = paramSet[i]; var cell = rowObj.GetCell(dataStartCol + j) ?? rowObj.CreateCell(dataStartCol + j); cell.SetCellValue(value); // 열 최대 너비 계산 int length = value.Length; if (length > maxColWidths[j]) maxColWidths[j] = length; } } } // 열 너비 적용 (문자수 기준 * 256) for (int j = 0; j < entry.ParametersSets.Count; j++) { sheet.SetColumnWidth(dataStartCol + j, (maxColWidths[j] + 2) * 256); // +2 여유 공간 } // Content 삽입 int contentRow = imageRowStart + rows + 1; IRow contentRowObj = sheet.GetRow(contentRow) ?? sheet.CreateRow(contentRow); ICell contentCell = contentRowObj.GetCell(startCol) ?? contentRowObj.CreateCell(startCol); contentCell.SetCellValue(entry.Content); } // 엑셀 저장 public void Save() { using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) workbook.Write(fs); } // JPEG 품질 변경 public void SetJpegQuality(int quality) { jpgQuality = (quality < 0) ? 0 : (quality > 100 ? 100 : quality); } } }