@segnavia/format 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ import { MarkSegment } from "./paper.js";
2
+ import { Imposition } from "./index.js";
3
+ //#region src/imposition-marks.d.ts
4
+ export declare const MIN_MARK_LENGTH_MM = 2;
5
+ export type ImpositionMarkEdge = 'top' | 'right' | 'bottom' | 'left';
6
+ export interface OmittedImpositionMark {
7
+ side: 'front' | 'back';
8
+ edge: ImpositionMarkEdge;
9
+ cutPosition: number;
10
+ }
11
+ export interface ImpositionSideMarks {
12
+ side: 'front' | 'back';
13
+ marks: MarkSegment[];
14
+ omittedMarks: OmittedImpositionMark[];
15
+ }
16
+ /** Computes physical crop-mark geometry without changing the fixed paper size. */
17
+ export declare function impositionMarks(imposition: Imposition): ImpositionSideMarks[];
18
+ //#endregion
@@ -0,0 +1,198 @@
1
+ import { roundMillimeters } from "./paper.js";
2
+ import { impose } from "./imposition.js";
3
+ //#region src/imposition-marks.ts
4
+ const MIN_MARK_LENGTH_MM = 2;
5
+ const unique = (values) => [...new Set(values.map(roundMillimeters))].sort((a, b) => a - b);
6
+ function addMark(result, edge, cutPosition, start, available, horizontal, direction) {
7
+ const length = Math.min(5, roundMillimeters(available));
8
+ if (length < 2) {
9
+ result.omittedMarks.push({
10
+ side: result.side,
11
+ edge,
12
+ cutPosition
13
+ });
14
+ return;
15
+ }
16
+ const end = roundMillimeters(start + direction * length);
17
+ result.marks.push(horizontal ? {
18
+ x1: Math.min(start, end),
19
+ y1: cutPosition,
20
+ x2: Math.max(start, end),
21
+ y2: cutPosition
22
+ } : {
23
+ x1: cutPosition,
24
+ y1: Math.min(start, end),
25
+ x2: cutPosition,
26
+ y2: Math.max(start, end)
27
+ });
28
+ }
29
+ function outerMarks(side, placements, paper) {
30
+ const verticalCuts = unique(placements.flatMap(({ trim }) => [trim.x, trim.x + trim.width]));
31
+ const horizontalCuts = unique(placements.flatMap(({ trim }) => [trim.y, trim.y + trim.height]));
32
+ const top = Math.min(...placements.map(({ bleedBox }) => bleedBox.y));
33
+ const right = Math.max(...placements.map(({ bleedBox }) => bleedBox.x + bleedBox.width));
34
+ const bottom = Math.max(...placements.map(({ bleedBox }) => bleedBox.y + bleedBox.height));
35
+ const left = Math.min(...placements.map(({ bleedBox }) => bleedBox.x));
36
+ for (const cut of verticalCuts) {
37
+ addMark(side, "top", cut, roundMillimeters(top - 1), top - 1, false, -1);
38
+ addMark(side, "bottom", cut, roundMillimeters(bottom + 1), paper.height - bottom - 1, false, 1);
39
+ }
40
+ for (const cut of horizontalCuts) {
41
+ addMark(side, "left", cut, roundMillimeters(left - 1), left - 1, true, -1);
42
+ addMark(side, "right", cut, roundMillimeters(right + 1), paper.width - right - 1, true, 1);
43
+ }
44
+ }
45
+ function intersectsBleed(mark, boxes) {
46
+ return boxes.some((box) => Math.max(mark.x1, box.x) <= Math.min(mark.x2, box.x + box.width) && Math.max(mark.y1, box.y) <= Math.min(mark.y2, box.y + box.height));
47
+ }
48
+ function rayRoom(start, cut, horizontal, direction, boxes) {
49
+ const obstacles = boxes.filter((box) => {
50
+ const acrossStart = horizontal ? box.y : box.x;
51
+ const acrossEnd = acrossStart + (horizontal ? box.height : box.width);
52
+ if (cut < acrossStart || cut > acrossEnd) return false;
53
+ const alongStart = horizontal ? box.x : box.y;
54
+ const alongEnd = alongStart + (horizontal ? box.width : box.height);
55
+ return direction < 0 ? alongEnd <= start : alongStart >= start;
56
+ }).map((box) => {
57
+ const alongStart = horizontal ? box.x : box.y;
58
+ const alongEnd = alongStart + (horizontal ? box.width : box.height);
59
+ return direction < 0 ? start - alongEnd - 1 : alongStart - start - 1;
60
+ });
61
+ return Math.max(0, Math.min(5, ...obstacles));
62
+ }
63
+ function cornerMarks(side, placements, rows) {
64
+ const boxes = placements.map(({ bleedBox }) => bleedBox);
65
+ const left = Math.min(...placements.map(({ trim }) => trim.x));
66
+ const right = Math.max(...placements.map(({ trim }) => trim.x + trim.width));
67
+ for (const placement of placements) {
68
+ const { trim, bleedBox, row } = placement;
69
+ const candidates = [];
70
+ if (row > 0) {
71
+ candidates.push([
72
+ "top",
73
+ trim.x,
74
+ bleedBox.y - 1,
75
+ false,
76
+ -1
77
+ ]);
78
+ candidates.push([
79
+ "top",
80
+ trim.x + trim.width,
81
+ bleedBox.y - 1,
82
+ false,
83
+ -1
84
+ ]);
85
+ }
86
+ if (row < rows - 1) {
87
+ candidates.push([
88
+ "bottom",
89
+ trim.x,
90
+ bleedBox.y + bleedBox.height + 1,
91
+ false,
92
+ 1
93
+ ]);
94
+ candidates.push([
95
+ "bottom",
96
+ trim.x + trim.width,
97
+ bleedBox.y + bleedBox.height + 1,
98
+ false,
99
+ 1
100
+ ]);
101
+ }
102
+ if (trim.x > left) {
103
+ candidates.push([
104
+ "left",
105
+ trim.y,
106
+ bleedBox.x - 1,
107
+ true,
108
+ -1
109
+ ]);
110
+ candidates.push([
111
+ "left",
112
+ trim.y + trim.height,
113
+ bleedBox.x - 1,
114
+ true,
115
+ -1
116
+ ]);
117
+ }
118
+ if (trim.x + trim.width < right) {
119
+ candidates.push([
120
+ "right",
121
+ trim.y,
122
+ bleedBox.x + bleedBox.width + 1,
123
+ true,
124
+ 1
125
+ ]);
126
+ candidates.push([
127
+ "right",
128
+ trim.y + trim.height,
129
+ bleedBox.x + bleedBox.width + 1,
130
+ true,
131
+ 1
132
+ ]);
133
+ }
134
+ for (const [edge, cut, start, horizontal, direction] of candidates) {
135
+ const before = side.marks.length;
136
+ addMark(side, edge, roundMillimeters(cut), roundMillimeters(start), rayRoom(start, cut, horizontal, direction, boxes), horizontal, direction);
137
+ const mark = side.marks.at(-1);
138
+ if (side.marks.length > before && mark && intersectsBleed(mark, boxes)) {
139
+ side.marks.pop();
140
+ side.omittedMarks.push({
141
+ side: side.side,
142
+ edge,
143
+ cutPosition: roundMillimeters(cut)
144
+ });
145
+ }
146
+ }
147
+ }
148
+ }
149
+ /** Computes physical crop-mark geometry without changing the fixed paper size. */
150
+ function impositionMarks(imposition) {
151
+ if (!imposition.marks) return [];
152
+ const cellCount = imposition.columns * imposition.rows;
153
+ const frontImposed = impose({
154
+ ...imposition,
155
+ sides: "one",
156
+ fill: "sequence",
157
+ skip: 0
158
+ }, cellCount);
159
+ const frontPlacements = frontImposed.placements;
160
+ const build = (sideName, placements) => {
161
+ const side = {
162
+ side: sideName,
163
+ marks: [],
164
+ omittedMarks: []
165
+ };
166
+ outerMarks(side, placements, frontImposed.paper);
167
+ if (imposition.cornerMarks) cornerMarks(side, placements, imposition.rows);
168
+ return side;
169
+ };
170
+ const front = build("front", frontPlacements);
171
+ if (imposition.sides === "one") return [front];
172
+ const portrait = frontImposed.paper.width <= frontImposed.paper.height;
173
+ const axis = imposition.flip === "long" === portrait ? "x" : "y";
174
+ const mirrorMark = (mark) => axis === "x" ? {
175
+ ...mark,
176
+ x1: roundMillimeters(frontImposed.paper.width - mark.x1),
177
+ x2: roundMillimeters(frontImposed.paper.width - mark.x2)
178
+ } : {
179
+ ...mark,
180
+ y1: roundMillimeters(frontImposed.paper.height - mark.y1),
181
+ y2: roundMillimeters(frontImposed.paper.height - mark.y2)
182
+ };
183
+ const mirrorEdge = (edge) => {
184
+ if (axis === "x") return edge === "left" ? "right" : edge === "right" ? "left" : edge;
185
+ return edge === "top" ? "bottom" : edge === "bottom" ? "top" : edge;
186
+ };
187
+ return [front, {
188
+ side: "back",
189
+ marks: front.marks.map(mirrorMark),
190
+ omittedMarks: front.omittedMarks.map(({ edge, cutPosition }) => ({
191
+ side: "back",
192
+ edge: mirrorEdge(edge),
193
+ cutPosition: roundMillimeters(axis === "x" && (edge === "top" || edge === "bottom") ? frontImposed.paper.width - cutPosition : axis === "y" && (edge === "left" || edge === "right") ? frontImposed.paper.height - cutPosition : cutPosition)
194
+ }))
195
+ }];
196
+ }
197
+ //#endregion
198
+ export { MIN_MARK_LENGTH_MM, impositionMarks };
package/dist/index.d.ts CHANGED
@@ -9,8 +9,9 @@ import { assignMembership, fitSection, fitTouchedSections, makeRoom, settleBoard
9
9
  import { Book, BookContents, BookFrontMatterEntry, BookInput, BookMode, BookPage, BookSection, BookView, BookViewInput, Chapter, isBookContents, isHebrew, noteMarkerIssues } from "./book.js";
10
10
  import { DeckFromSlidesOptions, SlideRow, deckFromSlides } from "./deck-from-slides.js";
11
11
  import { Direction, TextDirection, firstStrongDirection, languageDirection, resolveDirection } from "./direction.js";
12
- import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, NamedPaper, NamedPaperMetadata, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperBox, PaperGroup, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
12
+ import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, MarkSegment, NAMED_PAPERS, NamedPaper, NamedPaperMetadata, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperBox, PaperGroup, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
13
13
  import { Imposed, MillimeterEdges, PageFit, PagePlacementKind, PagePlacementLayout, Placement, fitPage, impose, mirrorPlacement, pagePlacementLayout } from "./imposition.js";
14
+ import { ImpositionMarkEdge, ImpositionSideMarks, MIN_MARK_LENGTH_MM, OmittedImpositionMark, impositionMarks } from "./imposition-marks.js";
14
15
  import { Lexicon, PronunciationEntry, lexiconVersion } from "./lexicon.js";
15
16
  import { NoteMarker, NumberSystem, formatNumber, noteMarker } from "./numbering.js";
16
17
  import { Scripts } from "./scripts.js";
@@ -167,6 +168,8 @@ export declare const Imposition: z.ZodObject<{
167
168
  ltr: "ltr";
168
169
  rtl: "rtl";
169
170
  }>>;
171
+ marks: z.ZodDefault<z.ZodBoolean>;
172
+ cornerMarks: z.ZodDefault<z.ZodBoolean>;
170
173
  }, z.core.$strip>;
171
174
  export type Imposition = z.infer<typeof Imposition>;
172
175
  export type ImpositionInput = z.input<typeof Imposition>;
@@ -631,6 +634,8 @@ export declare function jsonSchemas(): {
631
634
  ltr: "ltr";
632
635
  rtl: "rtl";
633
636
  }>>;
637
+ marks: z.ZodDefault<z.ZodBoolean>;
638
+ cornerMarks: z.ZodDefault<z.ZodBoolean>;
634
639
  }, z.core.$strip>>;
635
640
  deck: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
636
641
  title: z.ZodString;
@@ -1134,4 +1139,4 @@ export declare function jsonSchemas(): {
1134
1139
  }>>>;
1135
1140
  };
1136
1141
  //#endregion
1137
- export { Annotation, type ArrangeOptions, Board, type BoardInput, BoardItem, type BoardItemAnchor, BoardLabel, type BoardListingGroup, BoardSection, type BoardShapes, type BoardView, Book, BookContents, BookFrontMatterEntry, type BookInput, BookMode, BookPage, BookSection, BookView, type BookViewInput, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, type DeckFromSlidesOptions, type DeckInput, type DeckLimits, Direction, Fill, GridCell, type GridDropTarget, ImageFit, type Imposed, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, type MillimeterEdges, NAMED_PAPERS, type NamedPaper, type NamedPaperMetadata, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, type PageFit, type PagePlacementKind, type PagePlacementLayout, Paper, type PaperBox, type PaperGroup, PaperUnit, type Placement, Playback, type PlaybackMode, Point, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, type ShotUse, Size, Slide, SlideContent, type SlideRow, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotSource, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, TextDirection, Transition, TransitionInput, Word, type ZoomBounds, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
1142
+ export { Annotation, type ArrangeOptions, Board, type BoardInput, BoardItem, type BoardItemAnchor, BoardLabel, type BoardListingGroup, BoardSection, type BoardShapes, type BoardView, Book, BookContents, BookFrontMatterEntry, type BookInput, BookMode, BookPage, BookSection, BookView, type BookViewInput, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, type DeckFromSlidesOptions, type DeckInput, type DeckLimits, Direction, Fill, GridCell, type GridDropTarget, ImageFit, type Imposed, type ImpositionMarkEdge, type ImpositionSideMarks, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_MARK_LENGTH_MM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, type MarkSegment, type MillimeterEdges, NAMED_PAPERS, type NamedPaper, type NamedPaperMetadata, Narration, NoteMarker, NumberSystem, ORIENTATIONS, type OmittedImpositionMark, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, type PageFit, type PagePlacementKind, type PagePlacementLayout, Paper, type PaperBox, type PaperGroup, PaperUnit, type Placement, Playback, type PlaybackMode, Point, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, type ShotUse, Size, Slide, SlideContent, type SlideRow, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotSource, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, TextDirection, Transition, TransitionInput, Word, type ZoomBounds, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, impositionMarks, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, paperPixels, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { DEFAULT_TRANSITION_DURATION_MS, MAX_TRANSITION_DURATION_MS, MIN_TRANSIT
6
6
  import { Annotation, Box, Cue, DECK_SIZE, Deck, DeckShape, ImageFit, Manifest, Narration, PLAYBACK_MODES, Playback, Point, PublishedShot, SHOT_KEY, Shot, Size, Slide, SlideContent, Word, annotationCueIssues, exceedsLimits, parsePlayback } from "./deck.js";
7
7
  import { Board, BoardItem, BoardLabel, BoardSection, GridCell } from "./board.js";
8
8
  import { NoteMarker, NumberSystem, formatNumber, noteMarker } from "./numbering.js";
9
- import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
9
+ import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
10
10
  import { Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookShape, BookView, Chapter, isBookContents, isHebrew, noteMarkerIssues } from "./book.js";
11
11
  import { Lexicon, PronunciationEntry, lexiconVersion } from "./lexicon.js";
12
12
  import { MIN_BOARD_ITEM_WIDTH, addItem, moveItems, moveSection, removeItems, resizeItem } from "./board-edit.js";
@@ -17,6 +17,7 @@ import { deriveSectionCells, gridDropMarkerBox, gridDropTarget, insertIntoGrid,
17
17
  import { assignMembership, fitSection, fitTouchedSections, makeRoom, settleBoard } from "./board-sections.js";
18
18
  import { deckFromSlides } from "./deck-from-slides.js";
19
19
  import { fitPage, impose, mirrorPlacement, pagePlacementLayout } from "./imposition.js";
20
+ import { MIN_MARK_LENGTH_MM, impositionMarks } from "./imposition-marks.js";
20
21
  import { shotsUsed } from "./shots-used.js";
21
22
  import { z } from "zod";
22
23
  //#region src/index.ts
@@ -78,9 +79,16 @@ const Imposition = z.object({
78
79
  sides: z.enum(["one", "two"]).default("one"),
79
80
  flip: z.enum(["long", "short"]).default("long"),
80
81
  skip: z.number().int().nonnegative().default(0),
81
- dir: z.enum(["ltr", "rtl"]).default("ltr")
82
+ dir: z.enum(["ltr", "rtl"]).default("ltr"),
83
+ marks: z.boolean().default(false),
84
+ cornerMarks: z.boolean().default(false)
82
85
  }).superRefine((imposition, ctx) => {
83
86
  const cellCount = BigInt(imposition.columns) * BigInt(imposition.rows);
87
+ if (imposition.cornerMarks && !imposition.marks) ctx.addIssue({
88
+ code: "custom",
89
+ path: ["cornerMarks"],
90
+ message: "cornerMarks requires marks to be true"
91
+ });
84
92
  if (imposition.columns > 1e4 || imposition.rows > 1e4 || cellCount > BigInt(1e4)) {
85
93
  ctx.addIssue({
86
94
  code: "custom",
@@ -162,4 +170,4 @@ function jsonSchemas() {
162
170
  };
163
171
  }
164
172
  //#endregion
165
- export { Annotation, Board, BoardItem, BoardLabel, BoardSection, Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookView, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, Direction, GridCell, ImageFit, Imposition, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_IMPOSITION_CELLS, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, Margin, NAMED_PAPERS, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, Page, PageSize, Paper, PaperUnit, Playback, Point, Print, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, Size, Slide, SlideContent, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, TextDirection, Transition, Word, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, jsonSchemas, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
173
+ export { Annotation, Board, BoardItem, BoardLabel, BoardSection, Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookView, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, Direction, GridCell, ImageFit, Imposition, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_IMPOSITION_CELLS, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_MARK_LENGTH_MM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, Margin, NAMED_PAPERS, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, Page, PageSize, Paper, PaperUnit, Playback, Point, Print, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, Size, Slide, SlideContent, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, TextDirection, Transition, Word, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, impositionMarks, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, jsonSchemas, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, paperPixels, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
package/dist/paper.d.ts CHANGED
@@ -303,6 +303,7 @@ export declare function sheetMm(print: Pick<Print, 'paper' | 'orientation'>): {
303
303
  height: number;
304
304
  };
305
305
  export declare const PX_PER_MM: number;
306
+ export declare const paperPixels: (millimeters: number) => number;
306
307
  export declare function printProperties(print: Pick<Print, 'bleed' | 'safe'>, unit?: 'mm' | 'in' | 'pt'): string;
307
308
  export declare function printPadding(edges: {
308
309
  top: number;
package/dist/paper.js CHANGED
@@ -373,6 +373,7 @@ function sheetMm(print) {
373
373
  };
374
374
  }
375
375
  const PX_PER_MM = 96 / 25.4;
376
+ const paperPixels = (millimeters) => Math.ceil(millimeters * PX_PER_MM - 1e-9);
376
377
  function printProperties(print, unit = "mm") {
377
378
  return `:root{--segnavia-bleed:${roundMillimeters(toMillimeters(print.bleed, unit))}mm;--segnavia-safe:${roundMillimeters(toMillimeters(print.safe, unit))}mm}`;
378
379
  }
@@ -482,4 +483,4 @@ function printBoxes(print) {
482
483
  };
483
484
  }
484
485
  //#endregion
485
- export { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters };
486
+ export { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters };
package/dist/slots.d.ts CHANGED
@@ -191,7 +191,7 @@ export interface SlotsOptions {
191
191
  source?: Fill;
192
192
  fill?: Fill;
193
193
  declarations?: SlotDeclarationInput[];
194
- /** Resolve an asset without network access. Hosts should honour the signal so timed-out renders stop this work promptly. */
194
+ /** Resolve an asset without network access. Hosts should honor the signal so timed-out renders stop this work promptly. */
195
195
  resolveAsset?: (ref: string, options: {
196
196
  signal: AbortSignal;
197
197
  }) => Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segnavia/format",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {