import { ValueType } from "../enums.js"; /** * Text measurement engine for auto-fit column width and row height calculation. * * ## Algorithm Summary * * **Width calculation** follows a 3-tier approach: * * 1. **Calibri 11pt**: Use pre-computed bitmap pixel widths (exact match with Excel) * 2. **Known fonts at any size**: Use FUnit advance widths with the formula: * `pixelWidth = ROUND(advanceFU / unitsPerEm * ROUND(fontSize / 72 * 96))` * 3. **Unknown fonts**: Fall back to excelize-style category-average factors * * **Height calculation** uses the ClosedXML-verified formula: * `lineHeight = (unitsPerEm + usWinDescent) / unitsPerEm * fontSizePx` * * **Unit conversions** follow the ECMA-376 spec as verified by ClosedXML: * - Column width in XLSX = `TRUNC(pixelWidth / MDW * 256) / 256` * - MDW = max digit width in pixels (Calibri 11pt: 7) * - Pixel Padding (PP) = `2 * CEIL(MDW / 4) + 1` * * ## Key References * - ClosedXML wiki Cell Dimensions * - ECMA-376 ยง18.3.1.13 (col width) * - rust_xlsxwriter utility.rs (Calibri 11pt pixel table) * - excelize col.go (factor-based calculation) */ import type { Font, Alignment, NumFmt, RichText } from "../types.js"; /** * Measure the pixel width of a text string with a given font. * * Handles: * - Per-character precise measurement (Tier 1 & 2) * - Category-average fallback for unknown fonts (Tier 3) * - Multi-line text (returns width of widest line) * - Bold/italic modifiers * - Superscript/subscript scaling */ export declare function measureTextWidthPx(text: string, font?: Partial): number; /** * Measure the pixel width of rich text (mixed fonts). * Each run may have a different font; width is summed per run. * Line breaks reset the accumulator. */ export declare function measureRichTextWidthPx(richText: RichText[], defaultFont?: Partial): number; /** * Calculate the Max Digit Width (MDW) in pixels for a given font. * * Special case: Calibri 11pt returns 7 (bitmap metrics override). * For other fonts: MDW = ROUND(maxDigitAdvanceFU / unitsPerEm * ppem) */ export declare function getMaxDigitWidth(font?: Partial): number; /** * Calculate Pixel Padding (PP) from MDW. * Formula: PP = 2 * CEIL(MDW / 4) + 1 */ export declare function getPixelPadding(mdw: number): number; /** * Convert pixel width to Excel column character width (stored in XLSX). * * Formula: TRUNC(pixels / MDW * 256) / 256 * This gives the column width in MDW-based character units with 1/256 precision. */ export declare function pixelToCharWidth(pixels: number, mdw: number): number; /** * Convert Excel character width to pixel width. * * The formula differs for widths below 1 character: * - width < 1: pixels = ROUND(width * (MDW + PP)) * - width >= 1: pixels = ROUND(width * MDW) + PP */ export declare function charWidthToPixel(width: number, mdw: number): number; /** * Convert pixel height to points. * 1 point = 1/72 inch, 1 pixel = 1/DPI inch * points = pixels * 72 / DPI */ export declare function pixelToPoints(pixels: number): number; /** * Convert points to pixels. * pixels = points * DPI / 72 */ export declare function pointsToPixel(points: number): number; /** * Calculate the auto-fit column width in character units for a cell's text. * * This is the main entry point for column auto-fit calculation. * * @param textWidthPx - The pixel width of the cell's text content * @param mdw - Max digit width in pixels for the workbook's default font * @param hasAutoFilter - Whether the column is part of an auto-filter * @returns Column width in Excel character units */ export declare function calculateAutoFitWidth(textWidthPx: number, mdw: number, hasAutoFilter?: boolean): number; /** * Calculate the line height in pixels for a font. * * Uses the ClosedXML-verified formula: * lineHeight = (unitsPerEm + usWinDescent) / unitsPerEm * fontSizePx * * This matches Excel's actual row height calculation. */ export declare function getLineHeightPx(font?: Partial): number; /** * Calculate the number of wrapped lines for text in a column of given width. * * Excel wraps text at word boundaries (spaces, hyphens) rather than at * arbitrary character positions. If a single word is wider than the column, * it overflows (Excel does not break mid-word in normal wrap mode). * * @param text - The cell text (may contain explicit newlines) * @param columnWidthPx - Available column width in pixels (content area, excluding padding) * @param font - Cell font * @returns Number of lines the text will occupy */ export declare function calculateWrappedLineCount(text: string, columnWidthPx: number, font?: Partial): number; /** * Calculate the auto-fit row height in points for a cell. * * @param text - Cell display text * @param font - Cell font * @param alignment - Cell alignment (for wrapText check) * @param columnWidthPx - Column content width in pixels (needed for wrapText) * @returns Row height in points */ export declare function calculateAutoFitHeight(text: string, font?: Partial, alignment?: Partial, columnWidthPx?: number): number; /** * Calculate the auto-fit row height for rich text. */ export declare function calculateRichTextAutoFitHeight(richText: RichText[], defaultFont?: Partial, alignment?: Partial, columnWidthPx?: number): number; /** * Get the content area width of a column in pixels (excluding padding). * * @param charWidth - Column width in Excel character units * @param mdw - Max digit width * @returns Content width in pixels */ export declare function getColumnContentWidthPx(charWidth: number, mdw: number): number; /** * Minimal cell shape used by cell-level measurement helpers. * Avoids importing the full `Cell` class to prevent circular dependencies. */ export interface MeasurableCell { readonly value: unknown; readonly numFmt: string | NumFmt | undefined; readonly text: string; readonly effectiveType: ValueType; readonly font: Partial | undefined; readonly alignment: Partial | undefined; } /** * Get the pixel width of a cell's display text. * * Handles all cell value types: string, number (formatted), date (formatted), * boolean, formula result, rich text, hyperlink, error. */ export declare function getCellTextWidthPx(cell: MeasurableCell): number; /** * Get the height in points a cell needs. * * Considers wrapText alignment, indent, and explicit newlines. * * @param cell - The cell to measure * @param mdw - Max digit width in pixels * @param columnWidthPx - Column content width in pixels (needed for wrapText cells) */ export declare function getCellHeightPt(cell: MeasurableCell, mdw: number, columnWidthPx?: number): number;