2026-01-26 14:51:28 +09:00

147 lines
5.3 KiB
C#

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<List<string>> ParametersSets { get; set; } = new List<List<string>>();
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);
}
}
}