# OfficeCLI Unit and Color Format Conversions: A Complete Technical Guide

> Master OfficeCLI unit and color format conversions. This technical guide covers twips, points, EMUs, cm, inches, and hex color normalization. Improve your document formatting with OfficeCLI.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: deep-dive
- Published: 2026-08-04

---

**OfficeCLI handles document formatting through centralized unit conversion (twips, points, EMUs, centimeters, inches) and canonical hex color normalization, implemented in [`Units.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/Units.cs), [`SpacingConverter.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/SpacingConverter.cs), and [`ParseHelpers.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ParseHelpers.cs) under `src/officecli/Core`.**

OfficeCLI is a cross-platform command-line tool for creating, reading, and editing Office documents (Word, PowerPoint, Excel). Understanding how **OfficeCLI unit and color format conversions** work is essential for scripting precise document layouts and styling. This guide covers the conversion architecture, implementation details from the iOfficeAI/OfficeCLI repository, and practical CLI usage patterns.

## Unit Conversion Architecture

OfficeCLI uses multiple measurement systems internally. The following table maps each concept to its implementation:

| Concept | Internal Representation | Public API | Location |
|---------|------------------------|-----------|----------|
| **Twips** (1/1440 in) | `int`/`uint` | `Units.TwipsToPt`, `Units.ParseTwips` | [`src/officecli/Core/Units.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/Units.cs) |
| **Points** (1/72 in) | `double` | `Units.TwipsToPt`, `Units.HalfPointsToPt` | [`src/officecli/Core/Units.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/Units.cs) |
| **EMUs** (English Metric Units — 1 emu = 1/914400 in) | `long` | `EmuConverter` conversion factor | [`src/officecli/Core/EmuConverter.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/EmuConverter.cs) |
| **Length strings** (`"2cm"`, `"0.5in"`, `"36pt"`) | Parsed to twips | `WordHandler.Set.ParseTwips`, `SpacingConverter.Parse` | [`src/officecli/Handlers/Word/WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Set.cs), [`src/officecli/Core/SpacingConverter.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/SpacingConverter.cs) |
| **Percentages / special values** | Stored as raw string | Same parsers detecting `%`, `"nil"`, `"auto"` | [`src/officecli/Handlers/Word/WordHandler.Add.Table.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Add.Table.cs) |

### Core Conversion Helpers

The `Units` class in [`src/officecli/Core/Units.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/Units.cs) provides static methods for **twips ↔ points** conversion with culture-independent rounding:

```csharp
public static double TwipsToPt(int twips) => twips / 20.0;
public static double EmuToPt(long emu) => Math.Round(emu / EmuConverter.EmuPerPointF, 2);
public static double HalfPointsToPt(int hp) => hp / 2.0;

```

Key supporting components:

- **`EmuConverter`** — Holds `EmuPerPointF = 12700` for PowerPoint geometry conversions
- **`SpacingConverter`** — Parses length strings with unit suffixes (`pt`, `cm`, `in`, `dxa`) and returns **twips**; also handles reverse formatting via `FormatTwipsToCm`
- **`WordHandler.Set.ParseTwips`** — Central entry point that checks for unit suffixes, falls back to raw integer twips, and throws `ArgumentException` for invalid formats

All handlers reuse these helpers, enforcing **CONSISTENCY** across document types as noted in inline comments throughout the codebase.

## Color Formatting Architecture

OfficeCLI stores colors internally as **hex strings prefixed with `#`** (e.g., `#FF00AA`). The conversion pipeline flows through three stages:

1. **Raw OOXML values** — Theme references or plain hex strings from `Color.Val.Value`
2. **`ParseHelpers.FormatHexColor`** — Normalizes any input to canonical `#RRGGBB` form
3. **CLI output** — Consistent hex formatting for all color properties

### Implementation in ParseHelpers.cs

The [`src/officecli/Core/ParseHelpers.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/ParseHelpers.cs) file contains the authoritative color formatter:

```csharp
public static string FormatHexColor(string rawValue)
{
    if (string.IsNullOrWhiteSpace(rawValue)) return "";
    var hex = rawValue.TrimStart('#').PadLeft(6, '0');
    if (!Regex.IsMatch(hex, "^[0-9a-fA-F]{6}$"))
        throw new ArgumentException($"Invalid hex color '{rawValue}'");
    return $"#{hex.ToUpperInvariant()}";
}

```

Key behaviors:

- Empty or null inputs return `""`
- Leading `#` is stripped, string padded to 6 characters, then `#` re-added
- Invalid hex digits trigger `ArgumentException` with clear messaging

This helper appears across all handlers:

- **Word**: `WordHandler.Query`, `WordHandler.Set`, `WordHandler.Add`, `WordHandler.StyleList`
- **PowerPoint**: `PowerPointHandler.Query`, `PowerPointHandler.Theme`
- **Excel**: `ExcelHandler.Query`, `ExcelHandler.Helpers.Drawing`

The **CONSISTENCY(color-format)** rule ensures uniform color handling throughout the repository.

## Practical CLI Usage Examples

### Setting Lengths with Unit Suffixes

The CLI accepts human-readable length strings with automatic conversion:

```bash

# Set column width to 3 centimeters

officecli set doc.docx /tables[0].columns[0] --prop width=3cm

```

Internally, `3cm` → twips via `SpacingConverter.Parse` → OOXML `tblGridCol/@w` attribute.

### Using Raw Twips for Precision

Omit the unit suffix to specify exact twip values:

```bash

# Set top margin to 720 twips (0.5 inches)

officecli set doc.docx /section[1] --prop margin.top=720

```

Raw integers bypass unit parsing and are stored directly as twips.

### Applying Colors

Standard hex colors are normalized automatically:

```bash

# Apply red fill to a shape

officecli set slide.pptx /shapes[2] --prop fill=#FF0000

```

`#FF0000` passes through `ParseHelpers.FormatHexColor` to guarantee canonical `#RRGGBB` output.

### Using the "No Color" Placeholder

Remove color attributes with the `?` token:

```bash

# Remove underline color

officecli set doc.docx /paragraphs[3] --prop underline.color=?

```

`FormatHexColor` interprets `?` as an empty string, eliminating the OOXML attribute.

## Key Source Files Reference

| File | Purpose |
|------|---------|
| [`src/officecli/Core/Units.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/Units.cs) | Twips ↔ points, EMU ↔ points, culture-safe numeric handling |
| [`src/officecli/Core/ParseHelpers.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/ParseHelpers.cs) | Canonical hex color formatting, length parsing utilities |
| [`src/officecli/Core/EmuConverter.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/EmuConverter.cs) | EMU ↔ point conversion constants for PowerPoint |
| [`src/officecli/Core/SpacingConverter.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/SpacingConverter.cs) | Length string parsing (`pt`, `cm`, `in`, `dxa`), twips → cm formatting |
| [`src/officecli/Handlers/Word/WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Set.cs) | Central `ParseTwips` implementation for Word length values |
| [`src/officecli/Handlers/Word/WordHandler.Query.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Query.cs) | Color reading and normalization for Word documents |
| [`src/officecli/Handlers/Pptx/PowerPointHandler.Query.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Pptx/PowerPointHandler.Query.cs) | PowerPoint color handling implementation |
| [`src/officecli/Handlers/Excel/ExcelHandler.Query.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Excel/ExcelHandler.Query.cs) | Excel cell color processing |

## Summary

- **Single source of truth**: All length conversions route through `Units` and `SpacingConverter`; all color strings route through `ParseHelpers.FormatHexColor`
- **Robust error handling**: Invalid units or malformed hex colors raise clear `ArgumentException`s, preventing corrupt OOXML output
- **Explicit consistency**: `// CONSISTENCY(...)` comments document architectural decisions for future contributors
- **Cross-document uniformity**: The same conversion logic powers Word, PowerPoint, and Excel handlers

Mastering these two conversion systems unlocks precise control over OfficeCLI's document formatting capabilities.

## Frequently Asked Questions

### What units does OfficeCLI accept for length values?

OfficeCLI accepts `pt` (points), `cm` (centimeters), `in` (inches), and `dxa` (twips) as explicit suffixes. Raw integers are interpreted as twips. The parser in `SpacingConverter.Parse` and `WordHandler.Set.ParseTwips` handles all conversions to the internal twip representation.

### How does OfficeCLI handle invalid hex color input?

Invalid hex colors trigger an `ArgumentException` from `ParseHelpers.FormatHexColor` with a descriptive message like `"Invalid hex color '{rawValue}'"`. The method validates that the final 6-character string contains only hexadecimal digits `[0-9a-fA-F]`.

### What is the difference between EMUs and twips in OfficeCLI?

**Twips** (1/1440 inch) are the internal default for Word documents, while **EMUs** (English Metric Units, 1/914400 inch) are used for PowerPoint geometry. `EmuConverter.EmuPerPointF = 12700` provides the conversion factor, and `Units.EmuToPt()` rounds to two decimal places for consistent output.

### Can I use percentages for width and height values?

Yes. The parsers in [`WordHandler.Add.Table.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Add.Table.cs) and [`PowerPointHandler.Query.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/PowerPointHandler.Query.cs) detect trailing `%` characters and preserve percentage strings (`"50%"`) as raw values. Special literals like `"nil"` and `"auto"` are also recognized and passed through unchanged.