Knowledgebase (2597)
Children categories
A product list or an order detail table rarely keeps one format per cell. A description note has to be split over several lines, only a few words of a promotion line deserve to stand out, and a stock warning needs to be picked out in red. Doing that by hand means double-clicking every cell, selecting the fragment and adjusting the font one by one, which does not scale past a handful of rows. An HTML string describes exactly this kind of content — one piece of text whose parts are styled differently — and Spire.XLS for JavaScript exposes the HtmlString property, which renders a piece of HTML straight into a cell: line breaks, bold, italic, underline, color and font size all follow the tags, so a batch is one assignment inside a loop. It runs entirely in the browser on WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two feature points:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialized.
Write HTML text with line breaks into a cell
Breaking a line inside a cell normally means pressing Alt+Enter while editing it. When the data comes from a database or a form, that manual step cannot be batched, and the <br> tag in HTML means precisely "break the line here". HtmlString parses <br>, <div> and <p> into line breaks inside the cell, so a single string written into one cell becomes several lines. The steps are as follows:
- Load the font into the VFS.
- Create a workbook, take its first worksheet and widen column A.
- Build an HTML string for each entry, splitting the parts with
<br>. - Write them into the cells of column A with
HtmlString. - Save the workbook.
The complete code example below shows how to write HTML text with line breaks into an Excel cell in React:
function App() {
const setMultilineText = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check that the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a workbook, take the first worksheet and widen column A so a single line stays on one line
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
sheet.Range.get('A1:A5').ColumnWidth = 30;
// Each description has three parts, separated by <br> inside the same cell
const notes = [
'Bluetooth 5.3 dual pairing<br>30-hour battery<br>USB-C fast charge',
'Silent micro switches<br>Built-in 800 mAh battery<br>2.4G wireless',
'Dual-mic noise cancelling<br>6 hours per charge<br>Magnetic charging case',
'1080P resolution<br>780 g lightweight<br>Single USB-C cable',
'Wooden enclosure<br>Bluetooth 5.0<br>Remote control included',
];
// Write the HTML strings into column A, three lines inside one cell
notes.forEach((html, index) => {
sheet.Range.get(`A${index + 1}`).HtmlString = html;
});
// Save the workbook
const outputFileName = 'MultilineHtmlText.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Release the resources
workbook.Dispose();
// Read the result file out of the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Excel HTML rich text</h1>
<button onClick={setMultilineText}>Multiline HTML text</button>
</div>
);
}
export default App;
After running, the effect of writing HTML text with line breaks into a cell:

Format part of the text in a cell
Text inside one cell does not have to share one format. Within a single run of text, only part of it usually needs to stand out, while the rest can stay at the regular weight. HtmlString supports the <b>, <i> and <u> tags, and takes color and font size in a style attribute on a <span>. Every fragment wrapped in a tag becomes its own run of formatting without affecting the others, and the tags themselves never appear in the cell. The steps are as follows:
- As in the previous section, load the font into the VFS, create a workbook, take the first worksheet and widen column A.
- Mark the text to emphasize with
<b>,<i>and<u>, and wrap the text to highlight in<span style="color:#C00000;font-size:14pt">, giving the color as a hexadecimal value and the size in points. - Write the strings into column A; the rest of the text in the same cell keeps its original format.
- Save the workbook.
The complete code example below shows how to format part of the text in an Excel cell in React:
function App() {
const setPartialFormatting = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check that the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a workbook, take the first worksheet and widen column A so a single line stays on one line
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
sheet.Range.get('A1:A5').ColumnWidth = 30;
// Each part of a promotion line gets its own <b>, <i>, <u> or styled <span>;
// bold, italic, underline, color and font size apply only to the wrapped text
const promotions = [
'<b>Save 50 over 300</b>, <i>three days only</i>, <u>limit 2 per customer</u>, <span style="color:#C00000;font-size:14pt">only 3 left</span>',
'<b>Second one half price</b>, <i>this week only</i>, <u>not combinable</u>',
'<b>100 off instantly</b>, <i>ends at midnight</i>, <u>free carry case</u>, <span style="color:#C00000;font-size:14pt">low stock</span>',
'<b>Trade-in bonus 200</b>, <i>until month end</i>, <u>old device required</u>',
'<b>Buy one get one</b>, <i>500 sets only</i>, <u>gift chosen at random</u>, <span style="color:#E36C0A;font-size:14pt">restocking</span>',
];
// Write the HTML strings into column A
promotions.forEach((html, index) => {
sheet.Range.get(`A${index + 1}`).HtmlString = html;
});
// Save the workbook
const outputFileName = 'PartialFormattingHtml.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Release the resources
workbook.Dispose();
// Read the result file out of the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Excel HTML rich text</h1>
<button onClick={setPartialFormatting}>Partial formatting</button>
</div>
);
}
export default App;
After running, the effect of formatting part of the text in a cell as bold, italic, underlined, colored or larger:

FAQ
Does the HTML parser swallow runs of spaces?
Cause: A browser collapses consecutive spaces into one when it renders HTML, which makes it easy to assume Spire does the same and to reach for to build any padding.
Solution: It does not. A B is still five spaces when read back out of the cell, and leading spaces survive as well. works too, but ordinary alignment does not need it.
Does writing rich text wipe out the alignment the cell already had?
Cause: HtmlString does change the cell's font properties, so it is fair to wonder whether it resets the alignment set earlier along with them.
Solution: The alignment is untouched. Set Style.HorizontalAlignment first and write the HtmlString afterwards, and the alignment reads back unchanged — setting the format before the content is safe.
const cell = sheet.Range.get('A1');
cell.Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Center;
cell.HtmlString = '<b>Centered</b>';
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
A chart makes the trend behind one set of numbers visible, but it is far less good at showing the trends behind dozens of sets at once. Sparklines are built for exactly that: each one compresses a trend into a single cell, with no axes and no legend, so a whole column of trends can be taken in at a glance. Give every region's quarterly sales figures their own sparkline and you can see which row is climbing and which one turned back long before you could read it out of a column of numbers. Spire.XLS for JavaScript performs this directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers three feature points:
- Add line sparklines
- Add column sparklines and highlight the high and low points
- Clear sparklines from a worksheet
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialized.
Add Line Sparklines
A line sparkline joins a row of values in order into a single thin line, making the rise and fall of the trend immediately readable. It occupies no cell of its own and hides none of the numbers underneath, so a single narrow column can carry the trends of dozens of rows at once, and which one is climbing and which one turned back is there at a glance. A sparkline cannot exist outside a sparkline group, and the group decides the type, colors and marker settings shared by the whole batch. The steps are:
- Load the font and the sample data file into the VFS.
- Load the workbook and get the first worksheet.
- Create a line sparkline group with
SparklineGroups.AddGroup()and set the line weight and marker color. - Get the group's sparkline collection with
Add()and add one sparkline per data row in column F. - Save the workbook.
The following is the complete code example, showing how to add line sparklines to Excel data in React:
function App() {
const addLineSparkline = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the sample data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SparklineData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Create a line sparkline group on the worksheet
const sparklineGroup = sheet.SparklineGroups.AddGroup({ sparklineType: xlsModule.SparklineType.Line });
// Style the line: thicker stroke and visible data point markers
sparklineGroup.LineWeight = 1.5;
sparklineGroup.ShowMarkers = true;
sparklineGroup.MarkersColor = xlsModule.Color.get_Red();
// Get the sparkline collection of the group
const sparklines = sparklineGroup.Add();
// Add one sparkline per data row in column F
for (let row = 2; row <= 9; row++) {
sparklines.Add({
dataRange: sheet.Range.get(`B${row}:E${row}`),
referenceRange: sheet.Range.get(`F${row}`),
});
}
// Save the workbook
const outputFileName = 'AddLineSparkline.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Line Sparkline</h1>
<button onClick={addLineSparkline}>Start</button>
</div>
);
}
export default App;
After running, the effect of adding line sparklines:

Add Column Sparklines and Highlight the High and Low Points
A column sparkline represents values as a row of thin bars, which reads more directly than a line when you are comparing several numbers within the same row. It works the same way as the line sparkline, except that the color lands on each bar itself rather than on a connecting stroke.
What really makes column sparklines useful is the high and low point markers: the strongest and the weakest quarter in each row are picked out and colored on their own, so you no longer have to compare the numbers by eye to see where a row peaked and where it fell away. The steps are:
- Load the font and the sample data file into the VFS.
- Load the workbook and get the first worksheet.
- Create a column sparkline group with
SparklineGroups.AddGroup()(passingSparklineType.Column) and set the series color withSparklineColor. - Turn on
ShowHighPointandShowLowPoint, and give each its own color withHighPointColorandLowPointColor. - Get the group's sparkline collection with
Add(), add one sparkline per data row in column G and save the workbook.
The following is the complete code example, showing how to add column sparklines to Excel data and highlight the high and low points in React:
function App() {
const addColumnSparkline = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the sample data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SparklineData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Create a column sparkline group
const sparklineGroup = sheet.SparklineGroups.AddGroup({ sparklineType: xlsModule.SparklineType.Column });
// Set the color of the sparkline itself
sparklineGroup.SparklineColor = xlsModule.Color.get_CadetBlue();
// Turn on the high and low point markers and give each its own color
sparklineGroup.ShowHighPoint = true;
sparklineGroup.HighPointColor = xlsModule.Color.get_Red();
sparklineGroup.ShowLowPoint = true;
sparklineGroup.LowPointColor = xlsModule.Color.get_Purple();
const sparklines = sparklineGroup.Add();
// Add one sparkline per data row in column G
for (let row = 2; row <= 9; row++) {
sparklines.Add({
dataRange: sheet.Range.get(`B${row}:E${row}`),
referenceRange: sheet.Range.get(`G${row}`),
});
}
// Save the workbook
const outputFileName = 'AddColumnSparkline.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Column Sparkline</h1>
<button onClick={addColumnSparkline}>Start</button>
</div>
);
}
export default App;
After running, the effect of adding column sparklines and highlighting the high and low points:

Clear Sparklines from a Worksheet
When a report is revised or the figures are restated, the sparklines drawn beside the old numbers may no longer apply and need to be removed and drawn again. Sparkline groups are held by the worksheet, and once they are gone the cells return to their ordinary state, with their data and other formatting untouched. The steps are:
- Load the font and the sample data file into the VFS.
- Load the workbook and get the second worksheet, which already carries a line sparkline group.
- Clear all sparkline groups on that worksheet with
SparklineGroups.Clear(). - Save the workbook.
The following is the complete code example, showing how to clear sparklines from a worksheet in React:
function App() {
const clearSparklines = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the sample data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SparklineData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the second worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(1);
// Clear all sparkline groups on that worksheet
sheet.SparklineGroups.Clear();
// Save the workbook
const outputFileName = 'ClearSparklines.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Clear Sparklines</h1>
<button onClick={clearSparklines}>Start</button>
</div>
);
}
export default App;
After running, the effect of clearing sparklines from a worksheet:

FAQ
Reading the cells back does not show the sparklines
Cause: A sparkline is not cell content. It belongs to a sparkline group on the worksheet and is drawn over its anchor cell, while its data and settings are written into the worksheet's extension block, so walking the cells returns an empty value for the anchor column and no cell-level call can tell you whether a sparkline is there.
Solution: Read it from the worksheet-level SparklineGroups instead. get_Item(0) returns the first group, and its SparklineType tells you whether the batch is a line or a column one; the color settings are read from the same place:
const group = sheet.SparklineGroups.get_Item(0);
console.log(group.SparklineType); // SparklineType.Line or SparklineType.Column
Setting the line weight and markers on a column sparkline has no effect
Cause: LineWeight and ShowMarkers apply to line sparklines only. A column sparkline represents values as bars, so it has neither a connecting stroke nor data point markers, and although the assignment succeeds, neither property is written to the result file.
Solution: If you need a stroke and markers, create the sparkline group as a line type and set them there:
const sparklineGroup = sheet.SparklineGroups.AddGroup({ sparklineType: xlsModule.SparklineType.Line });
sparklineGroup.LineWeight = 1.5;
sparklineGroup.ShowMarkers = true;
sparklineGroup.MarkersColor = xlsModule.Color.get_Red();
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
Detect PDF Page Orientation and Rotation with JavaScript in React
2026-09-23 02:03:56 Written by Nina TangBefore printing, imposing or watermarking pages, you need to know whether each page is landscape or portrait: a document that mixes the two leaves blank edges when printed directly, and lands out of place when imposed. A page may also have been rotated as a whole, in which case the recorded page size no longer matches the direction you see. Picking those pages out before batch processing means flipping through them one at a time in desktop software.
This article shows how to detect PDF page rotation and display orientation with Spire.PDF for JavaScript. It is built on WebAssembly and loads and parses PDF documents directly in the browser, all locally, reading and writing files through a virtual file system (VFS) with no backend involved.
Two features are covered:
For installation and project setup, see Integrate Spire.PDF for JavaScript in a React project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.
Detect page rotation
PdfPageBase.Rotation reads the angle a page has been rotated by; the value falls within the PdfPageRotateAngle enumeration of 0°, 90°, 180° and 270°.
function App() {
const detectPageRotation = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to inspect into the VFS
const inputFileName = 'PageOrientationSample.pdf';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// The enumeration values are indices rather than angles, so map indices to degrees first
const DEGREES = {
[pdfModule.PdfPageRotateAngle.RotateAngle0.value]: 0,
[pdfModule.PdfPageRotateAngle.RotateAngle90.value]: 90,
[pdfModule.PdfPageRotateAngle.RotateAngle180.value]: 180,
[pdfModule.PdfPageRotateAngle.RotateAngle270.value]: 270,
};
// Read the rotation angle page by page
const lines = [];
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
lines.push(`Page ${i + 1}: rotation angle ${DEGREES[page.Rotation.value]}°`);
}
// Write the detection result into the VFS
const outputFileName = 'PageRotationResult.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, lines.join('\r\n'));
doc.Close();
// Read the generated file back from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Detect Page Rotation</h1>
<button onClick={detectPageRotation}>
Start Detection
</button>
</div>
);
}
export default App;
Detection result with the rotation angle recorded page by page:

Detect page orientation
Whether a page is landscape or portrait cannot be told from its size alone: PdfPageBase.Size gives the width and height of the visible page box and does not include the rotation; when a page is rotated by 90° or 270°, the width and height have to be swapped to get the direction the page actually shows.
function App() {
const detectPageOrientation = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to inspect into the VFS
const inputFileName = 'PageOrientationSample.pdf';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
const { RotateAngle90, RotateAngle270 } = pdfModule.PdfPageRotateAngle;
// Judge the display orientation page by page
const lines = [];
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
const pageSize = page.Size;
// Size excludes rotation: at 90° or 270° the width and height swap to give the displayed size
const quarterTurn = page.Rotation === RotateAngle90 || page.Rotation === RotateAngle270;
const width = quarterTurn ? pageSize.Height : pageSize.Width;
const height = quarterTurn ? pageSize.Width : pageSize.Height;
const orientation = width >= height ? 'Landscape' : 'Portrait';
lines.push(`Page ${i + 1}: ${orientation} (${width.toFixed(0)} × ${height.toFixed(0)} pt)`);
}
// Write the detection result into the VFS
const outputFileName = 'PageOrientationResult.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, lines.join('\r\n'));
doc.Close();
// Read the generated file back from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Detect Page Display Orientation</h1>
<button onClick={detectPageOrientation}>
Start Detection
</button>
</div>
);
}
export default App;
Detection result after judging each page by its display orientation:

FAQ
page.Rotation.value returns 0, 1, 2, 3 instead of 0, 90, 180, 270
Cause: The four members of PdfPageRotateAngle — RotateAngle0, RotateAngle90, RotateAngle180, RotateAngle270 — carry the values 0, 1, 2, 3 in the WebAssembly binding, and .value returns that index rather than the angle. Writing page.Rotation.value === 90 is always false.
Solution: Build an index-to-angle map before using the value. Rotation is corrected with an index too — page.Rotation takes an index, so passing 90 is read as index 2 and writes 180° into the document:
// Index → angle
const DEGREES = {
[pdfModule.PdfPageRotateAngle.RotateAngle0.value]: 0,
[pdfModule.PdfPageRotateAngle.RotateAngle90.value]: 90,
[pdfModule.PdfPageRotateAngle.RotateAngle180.value]: 180,
[pdfModule.PdfPageRotateAngle.RotateAngle270.value]: 270,
};
// Set the current page to 90° — .value is the index
page.Rotation = pdfModule.PdfPageRotateAngle.RotateAngle90.value;
page.Size returns portrait dimensions for a page that clearly shows as landscape
Cause: PdfPageBase.Size and ActualSize return the width and height of the page's visible box — the CropBox if one was set, otherwise the MediaBox — and that value does not follow /Rotate. Page 3 of the sample document has a page box of 595 × 842 pt with /Rotate at 90°, so it renders as an 842 × 595 landscape page while Size still returns 595 × 842.
Solution: After reading Rotation, swap the width and height yourself:
const { RotateAngle90, RotateAngle270 } = pdfModule.PdfPageRotateAngle;
const quarterTurn = page.Rotation === RotateAngle90 || page.Rotation === RotateAngle270;
const width = quarterTurn ? page.Size.Height : page.Size.Width;
const height = quarterTurn ? page.Size.Width : page.Size.Height;
doc.Sections is empty in a loaded PDF, and PageSettings.Orientation cannot be read
Cause: Sections holds page settings, and LoadFromFile does not rebuild sections for pages that already exist, so doc.Sections.Count is 0 and a following doc.Sections.get_Item(0) throws Arg_IndexOutOfRangeException. PageSettings.Orientation describes the layout intent for a newly created page, not the direction recorded in the file.
Solution: For existing pages, read page-level properties only — doc.Pages.get_Item(i) followed by Rotation and Size. Leave PageSettings.Orientation for new pages added through Sections.Add():
// Inspecting existing pages
const page = doc.Pages.get_Item(0);
const angle = DEGREES[page.Rotation.value];
// Orientation only comes into play when creating a new page
const section = doc.Sections.Add();
section.PageSettings.Orientation = pdfModule.PdfPageOrientation.Landscape;
Get a Free License
If you want to remove the evaluation message from the result documents, or lift the feature limits, contact sales for a 30-day temporary license.