@leafer-in/export 1.7.0 → 1.8.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.
package/src/export.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { IExportModule, IExportOptions, IExportResult, IExportResultFunction, IUI, IExportFileType, IFunction, IRenderOptions, IBoundsData, IBounds, ILocationType, ILeaf } from '@leafer-ui/interface'
2
- import { Creator, Matrix, TaskProcessor, FileHelper, Bounds, Platform, MathHelper, Resource } from '@leafer-ui/draw'
2
+ import { Creator, Matrix, TaskProcessor, FileHelper, Bounds, Platform, MathHelper, Resource, Export } from '@leafer-ui/draw'
3
3
 
4
4
  import { getTrimBounds } from './trim'
5
5
 
@@ -8,146 +8,154 @@ export const ExportModule: IExportModule = {
8
8
 
9
9
  syncExport(leaf: IUI, filename: string, options?: IExportOptions | number | boolean): IExportResult {
10
10
 
11
- this.running = true
11
+ Export.running = true
12
12
 
13
13
  let result: IExportResult
14
- const fileType = FileHelper.fileType(filename)
15
- const isDownload = filename.includes('.')
16
- options = FileHelper.getExportOptions(options)
17
14
 
18
- const { toURL } = Platform
19
- const { download } = Platform.origin
15
+ try {
20
16
 
17
+ const fileType = FileHelper.fileType(filename)
18
+ const isDownload = filename.includes('.')
19
+ options = FileHelper.getExportOptions(options)
21
20
 
22
- if (fileType === 'json') {
21
+ const { toURL } = Platform
22
+ const { download } = Platform.origin
23
23
 
24
- isDownload && download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename)
25
- result = { data: isDownload ? true : leaf.toJSON(options.json) }
26
24
 
27
- } else if (fileType === 'svg') {
25
+ if (fileType === 'json') {
28
26
 
29
- isDownload && download(toURL(leaf.toSVG(), 'svg'), filename)
30
- result = { data: isDownload ? true : leaf.toSVG() }
27
+ isDownload && download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename)
28
+ result = { data: isDownload ? true : leaf.toJSON(options.json) }
31
29
 
32
- } else {
30
+ } else if (fileType === 'svg') {
33
31
 
34
- let renderBounds: IBoundsData, trimBounds: IBounds, scaleX = 1, scaleY = 1
35
- const { worldTransform, isLeafer, leafer, isFrame } = leaf
36
- const { slice, clip, trim, screenshot, padding, onCanvas } = options
37
- const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth
38
- const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined)
32
+ isDownload && download(toURL(leaf.toSVG(), 'svg'), filename)
33
+ result = { data: isDownload ? true : leaf.toSVG() }
39
34
 
40
- const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill // leafer use
41
- const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix()
42
-
43
- // 获取元素大小
44
- if (screenshot) {
45
- renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot
46
35
  } else {
47
- let relative: ILocationType | ILeaf = options.relative || (isLeafer ? 'inner' : 'local')
48
-
49
- scaleX = worldTransform.scaleX
50
- scaleY = worldTransform.scaleY
51
-
52
- switch (relative) {
53
- case 'inner':
54
- matrix.set(worldTransform)
55
- break
56
- case 'local':
57
- matrix.set(worldTransform).divide(leaf.localTransform)
58
- scaleX /= leaf.scaleX
59
- scaleY /= leaf.scaleY
60
- break
61
- case 'world':
62
- scaleX = 1
63
- scaleY = 1
64
- break
65
- case 'page':
66
- relative = leafer || leaf
67
- default:
68
- matrix.set(worldTransform).divide(leaf.getTransform(relative))
69
- const l = relative.worldTransform
70
- scaleX /= scaleX / l.scaleX
71
- scaleY /= scaleY / l.scaleY
36
+
37
+ let renderBounds: IBoundsData, trimBounds: IBounds, scaleX = 1, scaleY = 1
38
+ const { worldTransform, isLeafer, leafer, isFrame } = leaf
39
+ const { slice, clip, trim, screenshot, padding, onCanvas } = options
40
+ const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth
41
+ const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined)
42
+
43
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill // leafer use
44
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix()
45
+
46
+ // 获取元素大小
47
+ if (screenshot) {
48
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot
49
+ } else {
50
+ let relative: ILocationType | ILeaf = options.relative || (isLeafer ? 'inner' : 'local')
51
+
52
+ scaleX = worldTransform.scaleX
53
+ scaleY = worldTransform.scaleY
54
+
55
+ switch (relative) {
56
+ case 'inner':
57
+ matrix.set(worldTransform)
58
+ break
59
+ case 'local':
60
+ matrix.set(worldTransform).divide(leaf.localTransform)
61
+ scaleX /= leaf.scaleX
62
+ scaleY /= leaf.scaleY
63
+ break
64
+ case 'world':
65
+ scaleX = 1
66
+ scaleY = 1
67
+ break
68
+ case 'page':
69
+ relative = leafer || leaf
70
+ default:
71
+ matrix.set(worldTransform).divide(leaf.getTransform(relative))
72
+ const l = relative.worldTransform
73
+ scaleX /= scaleX / l.scaleX
74
+ scaleY /= scaleY / l.scaleY
75
+ }
76
+
77
+ renderBounds = leaf.getBounds('render', relative)
72
78
  }
73
79
 
74
- renderBounds = leaf.getBounds('render', relative)
75
- }
76
80
 
81
+ // 缩放元素
82
+ const scaleData = { scaleX: 1, scaleY: 1 }
83
+ MathHelper.getScaleData(options.scale, options.size, renderBounds, scaleData)
77
84
 
78
- // 缩放元素
79
- const scaleData = { scaleX: 1, scaleY: 1 }
80
- MathHelper.getScaleData(options.scale, options.size, renderBounds, scaleData)
85
+ let pixelRatio = options.pixelRatio || 1
81
86
 
82
- let pixelRatio = options.pixelRatio || 1
83
87
 
88
+ // 导出元素
89
+ let { x, y, width, height } = new Bounds(renderBounds).scale(scaleData.scaleX, scaleData.scaleY)
90
+ if (clip) x += clip.x, y += clip.y, width = clip.width, height = clip.height
84
91
 
85
- // 导出元素
86
- let { x, y, width, height } = new Bounds(renderBounds).scale(scaleData.scaleX, scaleData.scaleY)
87
- if (clip) x += clip.x, y += clip.y, width = clip.width, height = clip.height
92
+ const renderOptions: IRenderOptions = { exporting: true, matrix: matrix.scale(1 / scaleData.scaleX, 1 / scaleData.scaleY).invert().translate(-x, -y).withScale(1 / scaleX * scaleData.scaleX, 1 / scaleY * scaleData.scaleY) }
93
+ let canvas = Creator.canvas({ width: Math.floor(width), height: Math.floor(height), pixelRatio, smooth, contextSettings })
88
94
 
89
- const renderOptions: IRenderOptions = { exporting: true, matrix: matrix.scale(1 / scaleData.scaleX, 1 / scaleData.scaleY).invert().translate(-x, -y).withScale(1 / scaleX * scaleData.scaleX, 1 / scaleY * scaleData.scaleY) }
90
- let canvas = Creator.canvas({ width: Math.floor(width), height: Math.floor(height), pixelRatio, smooth, contextSettings })
95
+ let sliceLeaf: IUI
96
+ if (slice) {
97
+ sliceLeaf = leaf
98
+ sliceLeaf.__worldOpacity = 0 // hide slice
91
99
 
92
- let sliceLeaf: IUI
93
- if (slice) {
94
- sliceLeaf = leaf
95
- sliceLeaf.__worldOpacity = 0 // hide slice
100
+ leaf = leafer || leaf // render all in bounds
101
+ renderOptions.bounds = canvas.bounds
102
+ }
96
103
 
97
- leaf = leafer || leaf // render all in bounds
98
- renderOptions.bounds = canvas.bounds
99
- }
100
104
 
105
+ canvas.save()
101
106
 
102
- canvas.save()
107
+ if (isFrame && fill !== undefined) {
108
+ const oldFill = leaf.get('fill')
109
+ leaf.fill = ''
110
+ leaf.__render(canvas, renderOptions)
111
+ leaf.fill = oldFill as string
112
+ } else {
113
+ leaf.__render(canvas, renderOptions)
114
+ }
103
115
 
104
- if (isFrame && fill !== undefined) {
105
- const oldFill = leaf.get('fill')
106
- leaf.fill = ''
107
- leaf.__render(canvas, renderOptions)
108
- leaf.fill = oldFill as string
109
- } else {
110
- leaf.__render(canvas, renderOptions)
111
- }
116
+ canvas.restore()
112
117
 
113
- canvas.restore()
114
118
 
119
+ if (sliceLeaf) sliceLeaf.__updateWorldOpacity() // show slice
115
120
 
116
- if (sliceLeaf) sliceLeaf.__updateWorldOpacity() // show slice
121
+ if (trim) {
122
+ trimBounds = getTrimBounds(canvas)
123
+ const old = canvas, { width, height } = trimBounds
124
+ const config = { x: 0, y: 0, width, height, pixelRatio }
117
125
 
118
- if (trim) {
119
- trimBounds = getTrimBounds(canvas)
120
- const old = canvas, { width, height } = trimBounds
121
- const config = { x: 0, y: 0, width, height, pixelRatio }
126
+ canvas = Creator.canvas(config)
127
+ canvas.copyWorld(old, trimBounds, config)
128
+ }
122
129
 
123
- canvas = Creator.canvas(config)
124
- canvas.copyWorld(old, trimBounds, config)
125
- }
130
+ if (padding) {
131
+ const [top, right, bottom, left] = MathHelper.fourNumber(padding)
132
+ const old = canvas, { width, height } = old
126
133
 
127
- if (padding) {
128
- const [top, right, bottom, left] = MathHelper.fourNumber(padding)
129
- const old = canvas, { width, height } = old
134
+ canvas = Creator.canvas({ width: width + left + right, height: height + top + bottom, pixelRatio })
135
+ canvas.copyWorld(old, old.bounds, { x: left, y: top, width, height })
136
+ }
130
137
 
131
- canvas = Creator.canvas({ width: width + left + right, height: height + top + bottom, pixelRatio })
132
- canvas.copyWorld(old, old.bounds, { x: left, y: top, width, height })
133
- }
138
+ if (needFill) canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over')
139
+ if (onCanvas) onCanvas(canvas)
140
+
141
+ const data = filename === 'canvas' ? canvas : canvas.export(filename, options)
142
+ result = { data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }
134
143
 
135
- if (needFill) canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over')
136
- if (onCanvas) onCanvas(canvas)
144
+ }
137
145
 
138
- const data = filename === 'canvas' ? canvas : canvas.export(filename, options)
139
- result = { data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }
146
+ } catch (error) {
140
147
 
148
+ result = { data: '', error }
141
149
  }
142
150
 
143
- this.running = false
151
+ Export.running = false
144
152
 
145
153
  return result
146
154
  },
147
155
 
148
156
  export(leaf: IUI, filename: IExportFileType | string, options?: IExportOptions | number | boolean): Promise<IExportResult> {
149
157
 
150
- this.running = true
158
+ Export.running = true
151
159
 
152
160
  return addTask((success: IExportResultFunction) =>
153
161
 
@@ -155,7 +163,7 @@ export const ExportModule: IExportModule = {
155
163
 
156
164
  const getResult = async () => {
157
165
  if (!Resource.isComplete) return Platform.requestRender(getResult)
158
- const result: IExportResult = ExportModule.syncExport(leaf, filename, options)
166
+ const result: IExportResult = Export.syncExport(leaf, filename, options)
159
167
  if (result.data instanceof Promise) result.data = await result.data
160
168
  success(result)
161
169
  resolve()
package/src/trim.ts CHANGED
@@ -19,6 +19,9 @@ export function getTrimBounds(canvas: ILeaferCanvas): IBounds {
19
19
  }
20
20
 
21
21
  const bounds = new Bounds()
22
- toBounds(pointBounds, bounds)
23
- return bounds.scale(1 / canvas.pixelRatio).ceil()
22
+ if (pointBounds) {
23
+ toBounds(pointBounds, bounds)
24
+ bounds.scale(1 / canvas.pixelRatio).ceil()
25
+ }
26
+ return bounds
24
27
  }