From 0b15822951fa90fa943a55f77bb836ee95b44e75 Mon Sep 17 00:00:00 2001
From: Nikolai Norum Hansen <35102735+Discolai@users.noreply.github.com>
Date: Fri, 22 Nov 2024 15:19:53 +0100
Subject: [PATCH] Write auto column width (#695)
* Add AutoWidth functionality for async write
* Add MiniExcelAutoAdjustWidthTests
* Implement autowidth for sync write
---
.../OpenXml/Constants/WorksheetXml.cs | 14 +-
.../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 105 ++++++++--
.../OpenXml/ExcelOpenXmlSheetWriter.cs | 114 ++++++++--
src/MiniExcel/OpenXml/ExcelWidthCollection.cs | 74 +++++++
.../OpenXml/MiniExcelAsyncStreamWriter.cs | 5 +
.../OpenXml/MiniExcelStreamWriter.cs | 5 +
src/MiniExcel/OpenXml/OpenXmlConfiguration.cs | 9 +
.../MiniExcelAutoAdjustWidthTests.cs | 194 ++++++++++++++++++
.../MiniExcelOpenXmlAsyncTests.cs | 1 -
tests/MiniExcelTests/Utils/Db.cs | 45 ++++
10 files changed, 523 insertions(+), 43 deletions(-)
create mode 100644 src/MiniExcel/OpenXml/ExcelWidthCollection.cs
create mode 100644 tests/MiniExcelTests/MiniExcelAutoAdjustWidthTests.cs
diff --git a/src/MiniExcel/OpenXml/Constants/WorksheetXml.cs b/src/MiniExcel/OpenXml/Constants/WorksheetXml.cs
index c300cbf0..7ec24856 100644
--- a/src/MiniExcel/OpenXml/Constants/WorksheetXml.cs
+++ b/src/MiniExcel/OpenXml/Constants/WorksheetXml.cs
@@ -1,5 +1,6 @@
using System.Globalization;
using MiniExcelLibs.Attributes;
+using System.Linq;
namespace MiniExcelLibs.OpenXml.Constants
{
@@ -46,8 +47,17 @@ internal static string StartRow(int rowIndex)
internal const string EndRow = "";
internal const string StartCols = "";
- internal static string Column(int? colIndex, double? columnWidth)
- => $@"";
+ internal static string Column(int colIndex, double columnWidth)
+ => $@"";
+
+
+ private static readonly int _maxColumnLength = Column(int.MaxValue, double.MaxValue).Length;
+
+ public static int GetColumnPlaceholderLength(int columnCount)
+ {
+ return StartCols.Length + (_maxColumnLength * columnCount) + EndCols.Length;
+ }
+
internal const string EndCols = "";
internal static string EmptyCell(string cellReference, string styleIndex)
diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
index d852a4d7..7df601ec 100644
--- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
+++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
@@ -6,6 +6,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO.Compression;
using System.Linq;
using System.Text;
@@ -104,6 +105,8 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
var yIndex = 1;
int maxColumnIndex;
int maxRowIndex;
+ ExcelWidthCollection widths = null;
+ long columnWidthsPlaceholderPosition = 0;
{
if (_configuration.FastMode)
{
@@ -122,7 +125,15 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
//sheet view
await writer.WriteAsync(GetSheetViews());
- await WriteColumnsWidthsAsync(writer, props);
+ if (_configuration.EnableAutoWidth)
+ {
+ columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props);
+ widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
+ }
+ else
+ {
+ await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props));
+ }
await writer.WriteAsync(WorksheetXml.StartSheetData);
int fieldCount = reader.FieldCount;
@@ -139,7 +150,7 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
for (int i = 0; i < fieldCount; i++)
{
var cellValue = reader.GetValue(i);
- await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i]);
+ await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i], widths);
xIndex++;
}
await writer.WriteAsync(WorksheetXml.EndRow);
@@ -163,6 +174,10 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
{
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
+ if (_configuration.EnableAutoWidth)
+ {
+ await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns);
+ }
}
private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter writer, IEnumerable values)
@@ -248,7 +263,17 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
await writer.WriteAsync(GetSheetViews());
//cols:width
- await WriteColumnsWidthsAsync(writer, props);
+ ExcelWidthCollection widths = null;
+ long columnWidthsPlaceholderPosition = 0;
+ if (_configuration.EnableAutoWidth)
+ {
+ columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props);
+ widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
+ }
+ else
+ {
+ await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props));
+ }
//header
await writer.WriteAsync(WorksheetXml.StartSheetData);
@@ -266,13 +291,13 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
switch (mode)
{
case "IDictionary": //Dapper Row
- maxRowIndex = await GenerateSheetByColumnInfoAsync>(writer, enumerator, props, xIndex, yIndex);
+ maxRowIndex = await GenerateSheetByColumnInfoAsync>(writer, enumerator, props, widths, xIndex, yIndex);
break;
case "IDictionary":
- maxRowIndex = await GenerateSheetByColumnInfoAsync(writer, enumerator, props, xIndex, yIndex);
+ maxRowIndex = await GenerateSheetByColumnInfoAsync(writer, enumerator, props, widths, xIndex, yIndex);
break;
case "Properties":
- maxRowIndex = await GenerateSheetByColumnInfoAsync