1+ function getQuadPoints ( rawQuad ) {
2+ if ( ! rawQuad ) return [ ] ;
3+ if ( Array . isArray ( rawQuad ) ) return rawQuad ;
4+ return [ rawQuad . p1 , rawQuad . p2 , rawQuad . p3 , rawQuad . p4 ] . filter ( Boolean ) ;
5+ }
6+
7+ function getIrNodePoints ( node ) {
8+ if ( node . type === 'polygon' || node . type === 'polyline' ) {
9+ return node . points ?? [ ] ;
10+ }
11+
12+ if ( node . type === 'text' || node . type === 'image' ) {
13+ return node . quad ?? [ ] ;
14+ }
15+
16+ return [ ] ;
17+ }
18+
19+ function getRootQuads ( root ) {
20+ if ( ! ( 'getBoxQuads' in root ) || typeof root . getBoxQuads !== 'function' ) {
21+ return [ ] ;
22+ }
23+
24+ try {
25+ return root . getBoxQuads ( { box : 'border' } ) ;
26+ } catch {
27+ return [ ] ;
28+ }
29+ }
30+
31+ export function getViewportSizeFromMetrics ( {
32+ quads = [ ] ,
33+ rect = { width : 0 , height : 0 } ,
34+ scrollWidth = 0 ,
35+ scrollHeight = 0 ,
36+ clientWidth = 0 ,
37+ clientHeight = 0 ,
38+ } ) {
39+ if ( quads . length > 0 ) {
40+ let minX = Infinity ;
41+ let minY = Infinity ;
42+ let maxX = - Infinity ;
43+ let maxY = - Infinity ;
44+
45+ for ( const quad of quads ) {
46+ for ( const point of getQuadPoints ( quad ) ) {
47+ if ( point . x < minX ) minX = point . x ;
48+ if ( point . y < minY ) minY = point . y ;
49+ if ( point . x > maxX ) maxX = point . x ;
50+ if ( point . y > maxY ) maxY = point . y ;
51+ }
52+ }
53+
54+ if ( Number . isFinite ( minX ) && Number . isFinite ( minY ) && Number . isFinite ( maxX ) && Number . isFinite ( maxY ) ) {
55+ return {
56+ width : Math . ceil ( Math . max ( maxX - minX , scrollWidth , clientWidth ) ) || 1 ,
57+ height : Math . ceil ( Math . max ( maxY - minY , scrollHeight , clientHeight ) ) || 1 ,
58+ } ;
59+ }
60+ }
61+
62+ return {
63+ width : Math . ceil ( Math . max ( rect . width ?? 0 , scrollWidth , clientWidth ) ) || 1 ,
64+ height : Math . ceil ( Math . max ( rect . height ?? 0 , scrollHeight , clientHeight ) ) || 1 ,
65+ } ;
66+ }
67+
68+ export function getIrExtent ( irNodes ) {
69+ let maxX = 0 ;
70+ let maxY = 0 ;
71+
72+ for ( const node of irNodes ?? [ ] ) {
73+ for ( const point of getIrNodePoints ( node ) ) {
74+ if ( point . x > maxX ) maxX = point . x ;
75+ if ( point . y > maxY ) maxY = point . y ;
76+ }
77+ }
78+
79+ return { maxX, maxY } ;
80+ }
81+
82+ export function applyIrExtentFallback ( viewport , irNodes ) {
83+ const nextViewport = { ...viewport } ;
84+ const { maxX, maxY } = getIrExtent ( irNodes ) ;
85+
86+ if ( nextViewport . width <= 1 && maxX > 0 ) nextViewport . width = Math . ceil ( maxX ) ;
87+ if ( nextViewport . height <= 1 && maxY > 0 ) nextViewport . height = Math . ceil ( maxY ) ;
88+
89+ return nextViewport ;
90+ }
91+
92+ export function calculateExportSize ( root , irNodes ) {
93+ return applyIrExtentFallback (
94+ getViewportSizeFromMetrics ( {
95+ quads : getRootQuads ( root ) ,
96+ rect : root . getBoundingClientRect ( ) ,
97+ scrollWidth : root . scrollWidth ,
98+ scrollHeight : root . scrollHeight ,
99+ clientWidth : root . clientWidth ,
100+ clientHeight : root . clientHeight ,
101+ } ) ,
102+ irNodes ,
103+ ) ;
104+ }
0 commit comments