OfficeIMO.Excel
3.6.0
Prefix Reserved
See the version list below for details.
dotnet add package OfficeIMO.Excel --version 3.6.0
NuGet\Install-Package OfficeIMO.Excel -Version 3.6.0
<PackageReference Include="OfficeIMO.Excel" Version="3.6.0" />
<PackageVersion Include="OfficeIMO.Excel" Version="3.6.0" />
<PackageReference Include="OfficeIMO.Excel" />
paket add OfficeIMO.Excel --version 3.6.0
#r "nuget: OfficeIMO.Excel, 3.6.0"
#:package OfficeIMO.Excel@3.6.0
#addin nuget:?package=OfficeIMO.Excel&version=3.6.0
#tool nuget:?package=OfficeIMO.Excel&version=3.6.0
OfficeIMO.Excel
Create, edit, read and save Excel workbooks (.xlsx, and the supported subsets of .xlsb and Excel 97–2003 .xls) in .NET, without Microsoft Excel or COM. Tables, charts and cell styles follow the workbook's theme; very large exports stream rows with bounded memory.
Returned authoring objects
range.ConditionalFormat() adds rules; each call returns the attached
ExcelConditionalFormattingInfo, the same editable model used by
AddConditionalFormattingRule. Edit the returned model and call
sheet.UpdateConditionalFormattingRule(rule) to apply it, or pass it to
RemoveConditionalFormattingRule to remove that exact rule. Pivot conditional
formats use the pivot's output range: sheet.Range(sheet.GetPivotTableRange(name)).ConditionalFormat().
range.AutoFilter() returns the ExcelAutoFilter on that range. Column(header) or
Column(offset) sets criteria, Clear() removes the filter and Inspect() reads
current criteria and table ownership. Creating the handle preserves deferred
workbook exports. AddTableOfContents returns the sheet it creates, and
AddPivotManualGrouping returns the created ExcelPivotGroupingInfo.
CustomProperties.Add returns the attached ExcelCustomProperty, so edits
to the returned value are saved with the workbook. The collection also implements
IDictionary<string, ExcelCustomProperty> and ICollection<KeyValuePair<string, ExcelCustomProperty>>.
AddManualRowPageBreak and AddManualColumnPageBreak return an attached
ExcelPageBreak with its worksheet, index, orientation and Remove() method.
AddMacro returns the attached ExcelMacroProject, which can read, save or remove
the VBA payload. Removed or replaced handles reject further operations.
AddIgnoredErrorRegion returns the created ExcelIgnoredErrorRegionInfo.
AddBackLinksToToc returns hyperlink metadata keyed by the worksheets receiving
links. Use AddImage to create an image and receive its ExcelImage.
Image dimensions and anchor offsets use OfficeLength: image.Width, image.Height,
image.OffsetX and image.OffsetY retain whole EMUs. Two-cell ending offsets use
ToOffsetX and ToOffsetY. For example, replace widthPixels: 96 with
new ExcelImageOptions { Width = OfficeLength.Pixels(96) }. SetSize, MoveTo, SetTwoCellEndingMarker and
TryGetAbsoluteAnchorBounds use the same length contract. Cell and ending-marker
offsets on existing XML remain inspectable when signed; SetTwoCellEndingMarker
requires non-negative ending offsets; the absolute-position AddImage(x, y, ...) overload requires non-negative
authored positions. HTML round trips preserve signed positions and offsets read
from existing native drawings. Omitted byte-image
sizes remain 96 by 32 pixels at 96 DPI, while file/scaled placement retains its
source-dimension defaults. Remote insertion also uses detected source dimensions
when width, height and scale are omitted; use explicit lengths to request a fixed
96 by 32 pixel image. Raster export applies its pixel rounding and safety
limits when rendering. GetRangeSize returns Width and Height as lengths;
worksheet reports insert images through sheet.Report().AddImage(...).
Use AddImage with a path, stream or native byte array. AddImageAsync reads files
and streams asynchronously or loads an HTTP or HTTPS Uri. Geometry, metadata,
network policy and stream ownership belong to ExcelImageOptions:
ExcelImage logo = sheet.AddImage(2, 3, "logo.png", new ExcelImageOptions {
ScalePercent = 20,
Description = "Company logo",
Title = "Logo"
});
sheet.AddImage("A1:C15", File.ReadAllBytes("header.png"), new ExcelImageOptions {
Placement = ExcelImagePlacement.MoveAndSize
});
await sheet.AddImageAsync(4, 2, new Uri("https://example.org/logo.png"));
A single A1 reference uses a one-cell anchor; a colon-delimited range, including
A1:A1, uses a two-cell anchor. AddImage(x, y, source, options) uses an absolute
anchor. Range anchors determine their own size and reject explicit dimensions or
scale. LockAspectRatio sets Excel's picture lock; it does not calculate an omitted
dimension. Streams stay open by default and retain their seekable position;
LeaveOpen = false closes them on success, failure or cancellation. Image bytes
are embedded without re-encoding. Deduplicate = true shares identical native
payloads within the worksheet drawing while each picture keeps its own metadata;
the default creates separate image parts. sheet.Report() uses the same options
and returns the worksheet's attached image.
Install
dotnet add package OfficeIMO.Excel
dotnet add package OfficeIMO.Excel.Pdf # only for SaveAsPdf
Targets netstandard2.0, net8.0 and net10.0, plus net472 on Windows.
A table and a chart from your data
using OfficeIMO;
using OfficeIMO.Excel;
Order[] orders = [
new("Contoso", "North", 12_400m, 0.21),
new("Fabrikam", "South", 8_900m, 0.17),
new("Northwind", "North", 15_100m, 0.24),
new("Tailspin", "West", 6_300m, 0.12)
];
using var book = ExcelDocument.Create("Orders.xlsx", new ExcelCreateOptions { Theme = OfficeTheme.Modern });
ExcelSheet sheet = book.AddSheet("Orders");
ExcelTable table = sheet.AddTable(orders, new OfficeTableOptions { Name = "Orders" });
sheet.AddChart(OfficeChartType.Column, orders, nameof(Order.Customer),
new ExcelChartOptions { Title = "Revenue by customer", Row = 2, Column = 7 }, nameof(Order.Total));
book.Save();
record Order(string Customer, string Region, decimal Total, double Margin);
AddTable writes a native Excel table: a header row from the property names, typed cells and the theme's table style. It returns the ExcelTable, and AddChart returns the ExcelChart, for further changes. ExcelChartOptions.Row and Column anchor the chart; Width and Height take an OfficeLength.
Cells, formulas and formatting
using OfficeIMO;
using OfficeIMO.Excel;
using var book = ExcelDocument.Create("Budget.xlsx");
ExcelSheet sheet = book.AddSheet("Budget");
sheet.Range("A1:B3").SetValues(new object?[,] {
{ "Item", "Cost" },
{ "Laptops", 18_500m },
{ "Licenses", 7_250m },
});
sheet.Cell("A4").SetValue("Total").SetBold();
sheet.Cell("B4").SetFormula("SUM(B2:B3)");
sheet.Range("A1:B1").SetBold().SetFillColor(OfficeColor.Parse("D9EAF7"));
sheet.Range("B2:B4").SetNumberFormat("#,##0.00");
sheet.Range("B2:B3").ConditionalFormat().DataBar(OfficeColor.Accent1);
sheet.View.Freeze(topRows: 1);
sheet.AutoFitColumns();
book.Save();
Rows and columns are 1-based, as in Excel. sheet.Cell(row, column) and sheet.Cell("B4") return a lightweight
ExcelCell handle (a struct, so a loop over cells allocates nothing); sheet.Range("A1:V1") returns an
ExcelRange. Format a block through its range rather than cell by cell: one range call applies the style under
one lock and saves the stylesheet once. sheet.UsedRange returns the range in use, and
book.GetNamedRange("Total")?.FirstCell writes through a defined name without parsing its address.
Cells created in a formatted row or column start with that row's or column's style, so values written into a template keep its number formats and fonts. A date written into a cell that already has a date format keeps it.
Native roles such as OfficeColor.Accent1 stay linked to the workbook theme.
Success, Warning and Danger use the shared palette selected at creation
or through book.ApplyTheme(theme). Loading a file or replacing raw theme XML
does not infer these status roles, because Excel's native theme has no slots for
them. In that case, pass color.Resolve(theme) as a literal color, or call
book.ApplyTheme(theme) before authoring with status roles.
Read rows back as objects
using OfficeIMO.Excel;
using var book = ExcelDocument.Load("Orders.xlsx");
foreach (Order order in book["Orders"].RowsAs<Order>()) {
Console.WriteLine($"{order.Customer}: {order.Total:N0}");
}
record Order(string Customer, string Region, decimal Total, double Margin);
Columns map to properties or constructor parameters by header name. RowsAs also accepts a factory or an explicit column mapping. For files from outside your organization, load with ExcelLoadOptions.UntrustedDefaults.
For a forward-only read, OpenReader(pathOrStream, options) returns an
ExcelWorkbookDataReader derived from DbDataReader. The shared OfficeIMO.Data
mappings also work on loaded documents:
using OfficeIMO.Data;
using OfficeIMO.Excel;
using ExcelWorkbookDataReader reader = ExcelDocument.OpenReader("Orders.xlsx",
new ExcelReaderOptions { SheetName = "Orders" });
List<Order> streamed = reader.RowsAs<Order>().ToList();
using var book = ExcelDocument.Load("Orders.xlsx");
List<Order> loaded = book.RowsAs<Order>(
options: new ExcelReaderOptions { SheetName = "Orders" }).ToList();
Loaded-document RowsAs overloads support automatic, configured RowMapper<T>
and factory mapping, with ExcelReaderOptions and cancellation. Their
RowsAsParallel counterparts take parallelOptions, format options, then
cancellationToken and preserve source order. OpenReaderAsync returns
Task<ExcelWorkbookDataReader> on .NET 8 and later.
XML Spreadsheet import also limits defined names (10,000 by default). Set ExcelSpreadsheetXmlOptions.MaxNames for a larger trusted workbook.
Large exports
The object model keeps the whole workbook editable until Save(). For hundreds of thousands of rows, the XLSX and XLSB streaming writers write each row as it arrives with bounded row memory:
using OfficeIMO;
using OfficeIMO.Excel;
IEnumerable<LogEvent> events = Enumerable.Range(1, 200_000)
.Select(i => new LogEvent(DateTime.UtcNow.AddSeconds(-i), i % 7 == 0 ? "Warning" : "Info", $"Event {i}"));
using (ExcelWorkbookWriter writer = ExcelDocument.CreateWriter("Events.xlsx", theme: OfficeTheme.Modern)) {
writer.WriteTable("Events", events);
}
record LogEvent(DateTime Time, string Level, string Message);
WriteTable also takes an IAsyncEnumerable<T>, a DataTable or an IDataReader. The file is published when the writer is disposed.
The same writer supports binary formats with an explicit format argument. A typed callback writes scalar values directly to native records:
using (var writer = ExcelDocument.CreateWriter(ExcelFileFormat.Xlsb, "Events.xlsb")) {
writer.WriteTable("Events", events, new[] { "Time", "Level", "Message" },
static (row, item) => row.Write(item.Time).Write(item.Level).Write(item.Message));
}
Use ExcelFileFormat.Xls for BIFF8 output, within its limit of 65,536 rows (including headers) and 256 columns. XLS stages native records and its required shared-string table; RequireStreaming=true rejects that format. Binary row writers create plain worksheets and reject tables, AutoFit, freeze panes and declared styles. Existing CreateWriter(path) and CreateWriter(stream) calls select XLSX. WriteData retains its selector and buffering behavior.
XLS and XLSB numeric cells use IEEE-754 double precision, including when a callback supplies a decimal, long or ulong. Large integers and high-precision decimals may lose digits. Write identifiers or exact decimal text as strings when every digit matters.
Report sheets
sheet.Report() lays out titled sections, KPI rows, paragraphs and tables on a sheet, for workbooks that people read rather than filter:
using OfficeIMO;
using OfficeIMO.Excel;
using var book = ExcelDocument.Create("Summary.xlsx");
book.AddSheet("Summary").Report()
.Title("Service review", "October")
.KpiRow([("Availability", "99.95%"), ("Incidents", 3), ("Changes", 41)])
.Section("Highlights")
.BulletedList(["No priority 1 incidents", "Patch compliance at 98%"]);
book.Save();
Save as PDF
using OfficeIMO;
using OfficeIMO.Excel;
using OfficeIMO.Excel.Pdf;
using var book = ExcelDocument.Load("Orders.xlsx");
OfficeConversionReport report = book.SaveAsPdf("Orders.pdf");
Console.WriteLine($"{report.ItemsWritten} pages, loss: {report.HasLoss}");
More
- Excel guide: styles, validation, conditional formats, pivot tables, slicers, sparklines, templates, formulas and calculation, protection, links, images, printing, legacy
.xlsand image export. - Formula calculation: typed errors and lookup modes, reference-valued
INDEXandXLOOKUP, and named scalar and array expressions. - Compatibility matrix and the generated operation contract: exactly what is supported, preserved or rejected.
- Large-workbook guidance, remote loading and legacy XLS compatibility.
- Examples and the migration guide.
- Adapters: OfficeIMO.Excel.Pdf, Html, Csv, OpenDocument, GoogleSheets and IWork. PDF tables back to Excel live in OfficeIMO.Pdf.Excel.
- PowerShell: PSWriteOffice (
Export-OfficeExcel,New-OfficeExcel).
Dependencies: the Open XML SDK and OfficeIMO.Core. MIT licensed.
Generated capability summary
This table is generated from the package-neutral OfficeIMO operation catalog. The detailed source contracts remain authoritative for feature-level behavior and limitations.
| Operation | Supported | Partial | Preserved | Rejected | Unsupported | Not applicable |
|---|---|---|---|---|---|---|
| Create | 22 | 13 | 0 | 15 | 1 | 2 |
| Read | 34 | 0 | 17 | 0 | 0 | 2 |
| Edit | 11 | 0 | 39 | 2 | 1 | 0 |
| Preserve | 10 | 0 | 39 | 0 | 0 | 0 |
| Inspect | 6 | 0 | 0 | 0 | 0 | 0 |
| Validate | 4 | 0 | 0 | 0 | 0 | 2 |
| Remove | 4 | 0 | 0 | 0 | 1 | 0 |
| Convert | 49 | 41 | 0 | 8 | 0 | 0 |
| Export | 5 | 0 | 0 | 0 | 0 | 0 |
The complete rows for OfficeIMO.Excel are published in the generated operation contract.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.7.2
- DocumentFormat.OpenXml (>= 3.5.1 && < 4.0.0)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.9)
- OfficeIMO.Core (>= 3.6.0)
- System.Text.Encoding.CodePages (>= 10.0.9)
- System.Text.Json (>= 10.0.7 && < 11.0.0)
-
.NETStandard 2.0
- DocumentFormat.OpenXml (>= 3.5.1 && < 4.0.0)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.9)
- OfficeIMO.Core (>= 3.6.0)
- System.Text.Encoding.CodePages (>= 10.0.9)
- System.Text.Json (>= 10.0.7 && < 11.0.0)
-
net10.0
- DocumentFormat.OpenXml (>= 3.5.1 && < 4.0.0)
- OfficeIMO.Core (>= 3.6.0)
-
net8.0
- DocumentFormat.OpenXml (>= 3.5.1 && < 4.0.0)
- OfficeIMO.Core (>= 3.6.0)
NuGet packages (16)
Showing the top 5 NuGet packages that depend on OfficeIMO.Excel:
| Package | Downloads |
|---|---|
|
OfficeIMO.Excel.Pdf
PDF converter for OfficeIMO.Excel - Export Excel workbooks to PDF using the first-party OfficeIMO.Pdf engine. |
|
|
Ank.DocToolkit
Convert HTML to PDF and DOCX in C# without a browser - pure managed, no Chromium, no wkhtmltopdf, no native binaries, no LibreOffice, no Office interop. Also converts Markdown to DOCX and PDF; renders DOCX, XLSX and PPTX to PDF; exports DOCX to HTML/Markdown and XLSX to CSV/HTML; reads legacy Word 97-2003 .doc files; reads text out of a PDF; creates/edits DOCX, XLSX and PPTX; password-protects PDF, DOCX, XLSX and PPTX; and inspects and validates digital signatures in DOCX, XLSX and PPTX. Runs on Linux, Windows, macOS and arm64, and makes no network calls at runtime. |
|
|
OfficeIMO.ChartForgeX
Optional typed bridge from ChartForgeX visual artifacts to OfficeIMO Word, Excel, PowerPoint, PDF, drawing, and editable Visio surfaces. |
|
|
OfficeIMO.Reader
Unified, read-only document extraction facade for OfficeIMO (Word/Excel/PowerPoint/Markdown/PDF) intended for AI ingestion. |
|
|
OfficeIMO.Reader.Excel
Excel workbook adapter for OfficeIMO.Reader.Core. |
GitHub repositories (2)
Showing the top 2 popular GitHub repositories that depend on OfficeIMO.Excel:
| Repository | Stars |
|---|---|
|
EvotecIT/EventViewerX
Windows Event Log tooling for PowerShell and .NET: typed queries, reporting, export, WEC, automation, and the PSEventViewer module.
|
|
|
EvotecIT/PSWriteOffice
Moved to OfficeIMO. Development, releases, issues and pull requests: https://github.com/EvotecIT/OfficeIMO
|
| Version | Downloads | Last Updated |
|---|---|---|
| 3.6.1 | 527 | 11/10/2026 |
| 3.6.0 | 874 | 11/6/2026 |
| 3.5.3 | 2,106 | 10/31/2026 |
| 3.5.2 | 3,342 | 10/24/2026 |
| 3.5.1 | 2,534 | 10/16/2026 |
| 3.4.5 | 2,346 | 10/10/2026 |
| 3.4.4 | 6,384 | 9/27/2026 |
| 3.4.3 | 2,841 | 9/12/2026 |
| 3.4.2 | 861 | 9/9/2026 |
| 3.4.1 | 722 | 9/7/2026 |
| 3.4.0 | 599 | 9/6/2026 |
| 3.3.0 | 713 | 9/2/2026 |
| 3.2.7 | 2,745 | 8/29/2026 |
| 3.2.6 | 4,555 | 8/22/2026 |
| 3.2.5 | 592 | 8/21/2026 |
| 3.2.4 | 2,259 | 8/19/2026 |
| 3.2.3 | 958 | 8/17/2026 |
| 3.2.2 | 3,969 | 8/13/2026 |
| 3.2.1 | 646 | 8/11/2026 |
| 3.2.0 | 4,159 | 8/7/2026 |