Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,15 @@ export type PaperSizeName =
export interface PageSetup {
paperSize?: PaperSize
orientation?: "portrait" | "landscape"
/**
* Scale the sheet to fit `fitToWidth` × `fitToHeight` pages instead of
* printing at `scale`. The writer turns this on when either count is
* set; pass `false` to keep the counts out of the file.
*/
fitToPage?: boolean
/** Pages wide to fit the sheet to. `0` means as many as needed. Implies `fitToPage`. */
fitToWidth?: number
/** Pages tall to fit the sheet to. `0` means as many as needed. Implies `fitToPage`. */
fitToHeight?: number
scale?: number
margins?: PageMargins
Expand Down
18 changes: 15 additions & 3 deletions src/xlsx/worksheet-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,9 @@ export function writeWorksheetXml(
// `<pageSetup fitToWidth>` alone does nothing in Excel — the scaling
// mode is switched by this flag, and the fit counts are read only
// once it is on. It also carries `fitToPage: true` on its own, which
// previously emitted no XML whatsoever. See #407.
if (sheet.pageSetup?.fitToPage) {
// previously emitted no XML whatsoever. See #407. Either count also
// implies the flag; see `isFitToPage` (#596).
if (sheet.pageSetup && isFitToPage(sheet.pageSetup)) {
sheetPrChildren.push(xmlSelfClose("pageSetUpPr", { fitToPage: 1 }))
}
if (sheetPrChildren.length > 0) {
Expand Down Expand Up @@ -1398,6 +1399,17 @@ function serializePrintOptions(ps: PageSetup | undefined): string {

// ── Page Setup Serialization ─────────────────────────────────────────

/**
* Whether the sheet prints in fit-to-page mode. The page counts do nothing
* without the mode, so writing them without it would be a field that looks
* set and prints at 100% — the counts imply the mode unless the caller
* says otherwise. The reader already treats either count as turning it on.
* See #596.
*/
function isFitToPage(ps: PageSetup): boolean {
return ps.fitToPage ?? (ps.fitToWidth !== undefined || ps.fitToHeight !== undefined)
}

function serializePageSetup(ps: PageSetup): string {
const attrs: Record<string, string | number> = {}

Expand All @@ -1416,7 +1428,7 @@ function serializePageSetup(ps: PageSetup): string {
attrs["scale"] = ps.scale
}

if (ps.fitToPage) {
if (isFitToPage(ps)) {
if (ps.fitToWidth !== undefined) {
attrs["fitToWidth"] = ps.fitToWidth
}
Expand Down
54 changes: 54 additions & 0 deletions test/print-settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,49 @@ describe("page setup — writing", () => {
expect(findChild(sheetPr, "pageSetUpPr").attrs["fitToPage"]).toBe("1")
})

it("turns on fit to page when only the page counts are given", () => {
// The counts used to be dropped without `fitToPage: true`, so the
// sheet printed at 100%. See #596.
const doc = parseSheet(
writeXml({ name: "Test", rows: [["Data"]], pageSetup: { fitToWidth: 1, fitToHeight: 0 } }),
)

const ps = findChild(doc, "pageSetup")
expect(ps).toBeDefined()
expect(ps.attrs["fitToWidth"]).toBe("1")
expect(ps.attrs["fitToHeight"]).toBe("0")
const sheetPr = findChild(doc, "sheetPr")
expect(sheetPr).toBeDefined()
expect(findChild(sheetPr, "pageSetUpPr").attrs["fitToPage"]).toBe("1")
})

it("turns on fit to page when only fitToHeight is given", () => {
const doc = parseSheet(
writeXml({ name: "Test", rows: [["Data"]], pageSetup: { fitToHeight: 2 } }),
)

const ps = findChild(doc, "pageSetup")
expect(ps).toBeDefined()
expect(ps.attrs["fitToHeight"]).toBe("2")
expect(ps.attrs["fitToWidth"]).toBeUndefined()
const sheetPr = findChild(doc, "sheetPr")
expect(sheetPr).toBeDefined()
expect(findChild(sheetPr, "pageSetUpPr").attrs["fitToPage"]).toBe("1")
})

it("lets an explicit fitToPage: false override the page counts", () => {
const doc = parseSheet(
writeXml({
name: "Test",
rows: [["Data"]],
pageSetup: { fitToPage: false, fitToWidth: 1, fitToHeight: 0 },
}),
)

expect(findChild(doc, "sheetPr")).toBeUndefined()
expect(findChild(doc, "pageSetup")).toBeUndefined()
})

it("writes all paper sizes correctly", () => {
const paperSizes: Array<[string, string]> = [
["letter", "1"],
Expand Down Expand Up @@ -458,6 +501,17 @@ describe("page setup — round-trip", () => {
expect(ps!.fitToHeight).toBeUndefined()
})

it("round-trips the page counts without fitToPage (#596)", async () => {
const data = await writeXlsx({
sheets: [{ name: "Sheet1", rows: [["Data"]], pageSetup: { fitToWidth: 1, fitToHeight: 0 } }],
})

const ps = (await readXlsx(data)).sheets[0].pageSetup
expect(ps!.fitToPage).toBe(true)
expect(ps!.fitToWidth).toBe(1)
expect(ps!.fitToHeight).toBe(0)
})

it("round-trips all paper sizes", async () => {
const sizes = ["letter", "legal", "a3", "a4", "a5", "b4", "b5", "executive", "tabloid"] as const

Expand Down