@leafer-ui/export
Advanced tools
+137
| import { IExportFileType, IFunction, IRenderOptions, IBoundsData, IBounds, ILocationType, ILeaf } from '@leafer/interface' | ||
| import { Creator, Matrix, TaskProcessor, FileHelper, Bounds } from '@leafer/core' | ||
| import { IExportModule, IExportOptions, IExportResult, IExportResultFunction, IUI } from '@leafer-ui/interface' | ||
| import { getTrimBounds } from './trim' | ||
| export const ExportModule: IExportModule = { | ||
| export(leaf: IUI, filename: IExportFileType | string, options?: IExportOptions | number | boolean): Promise<IExportResult> { | ||
| this.running = true | ||
| return addTask((success: IExportResultFunction) => | ||
| new Promise((resolve: IFunction) => { | ||
| const over = (result: IExportResult) => { | ||
| success(result) | ||
| resolve() | ||
| this.running = false | ||
| } | ||
| const { leafer } = leaf | ||
| if (leafer) { | ||
| leafer.waitViewCompleted(async () => { | ||
| options = FileHelper.getExportOptions(options) | ||
| let renderBounds: IBoundsData, trimBounds: IBounds, scaleX = 1, scaleY = 1 | ||
| const { worldTransform, isLeafer, isFrame } = leaf | ||
| const { slice, trim, onCanvas } = options | ||
| const scale = options.scale || 1 | ||
| const pixelRatio = options.pixelRatio || 1 | ||
| const screenshot = options.screenshot || leaf.isApp | ||
| const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill // leafer use | ||
| const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix() | ||
| if (screenshot) { | ||
| renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot | ||
| } else { | ||
| let relative: ILocationType | ILeaf = options.relative || (isLeafer ? 'inner' : 'local') | ||
| scaleX = worldTransform.scaleX | ||
| scaleY = worldTransform.scaleY | ||
| switch (relative) { | ||
| case 'inner': | ||
| matrix.set(worldTransform) | ||
| break | ||
| case 'local': | ||
| matrix.set(worldTransform).divide(leaf.localTransform) | ||
| scaleX /= leaf.scaleX | ||
| scaleY /= leaf.scaleY | ||
| break | ||
| case 'world': | ||
| scaleX = 1 | ||
| scaleY = 1 | ||
| break | ||
| case 'page': | ||
| relative = leaf.leafer | ||
| default: | ||
| matrix.set(worldTransform).divide(leaf.getTransform(relative)) | ||
| const l = relative.worldTransform | ||
| scaleX /= scaleX / l.scaleX | ||
| scaleY /= scaleY / l.scaleY | ||
| } | ||
| renderBounds = leaf.getBounds('render', relative) | ||
| } | ||
| const { x, y, width, height } = new Bounds(renderBounds).scale(scale) | ||
| let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio }) | ||
| const renderOptions: IRenderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) } | ||
| if (slice) { | ||
| leaf = leafer // render all in bounds | ||
| renderOptions.bounds = canvas.bounds | ||
| } | ||
| canvas.save() | ||
| if (isFrame && fill !== undefined) { | ||
| const oldFill = leaf.get('fill') | ||
| leaf.fill = '' | ||
| leaf.__render(canvas, renderOptions) | ||
| leaf.fill = oldFill as string | ||
| } else { | ||
| leaf.__render(canvas, renderOptions) | ||
| } | ||
| canvas.restore() | ||
| if (trim) { | ||
| trimBounds = getTrimBounds(canvas) | ||
| const old = canvas, { width, height } = trimBounds | ||
| const config = { x: 0, y: 0, width, height, pixelRatio } | ||
| canvas = Creator.canvas(config) | ||
| canvas.copyWorld(old, trimBounds, config) | ||
| } | ||
| if (needFill) canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over') | ||
| if (onCanvas) onCanvas(canvas) | ||
| const data = filename === 'canvas' ? canvas : await canvas.export(filename, options) | ||
| over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }) | ||
| }) | ||
| } else { | ||
| over({ data: false }) | ||
| } | ||
| }) | ||
| ) | ||
| } | ||
| } | ||
| let tasker: TaskProcessor | ||
| function addTask(task: IFunction): Promise<IExportResult> { | ||
| if (!tasker) tasker = new TaskProcessor() | ||
| return new Promise((resolve: IExportResultFunction) => { | ||
| tasker.add(async () => await task(resolve), { parallel: false }) | ||
| }) | ||
| } |
+4
-4
| { | ||
| "name": "@leafer-ui/export", | ||
| "version": "1.0.0-rc.19", | ||
| "version": "1.0.0-rc.20", | ||
| "description": "@leafer-ui/export", | ||
@@ -25,8 +25,8 @@ "author": "Chao (Leafer) Wan", | ||
| "dependencies": { | ||
| "@leafer/core": "1.0.0-rc.19" | ||
| "@leafer/core": "1.0.0-rc.20" | ||
| }, | ||
| "devDependencies": { | ||
| "@leafer/interface": "1.0.0-rc.19", | ||
| "@leafer-ui/interface": "1.0.0-rc.19" | ||
| "@leafer/interface": "1.0.0-rc.20", | ||
| "@leafer-ui/interface": "1.0.0-rc.20" | ||
| } | ||
| } |
+34
-126
@@ -1,137 +0,45 @@ | ||
| import { IExportFileType, IFunction, IRenderOptions, IBoundsData, IBounds, ILocationType, ILeaf } from '@leafer/interface' | ||
| import { Creator, Matrix, TaskProcessor, FileHelper, Bounds } from '@leafer/core' | ||
| export { ExportModule } from './export' | ||
| import { IExportModule, IExportOptions, IExportResult, IExportResultFunction, IUI } from '@leafer-ui/interface' | ||
| import { getTrimBounds } from './trim' | ||
| import { IExportOptions, IExportImageType, IExportFileType, IBlob } from '@leafer/interface' | ||
| import { LeaferCanvasBase, FileHelper, Platform, Debug } from '@leafer/core' | ||
| export const ExportModule: IExportModule = { | ||
| const canvas = LeaferCanvasBase.prototype | ||
| const debug = Debug.get('@leafer-ui/export') | ||
| export(leaf: IUI, filename: IExportFileType | string, options?: IExportOptions | number | boolean): Promise<IExportResult> { | ||
| this.running = true | ||
| return addTask((success: IExportResultFunction) => | ||
| new Promise((resolve: IFunction) => { | ||
| const over = (result: IExportResult) => { | ||
| success(result) | ||
| resolve() | ||
| this.running = false | ||
| } | ||
| const { leafer } = leaf | ||
| if (leafer) { | ||
| leafer.waitViewCompleted(async () => { | ||
| options = FileHelper.getExportOptions(options) | ||
| let renderBounds: IBoundsData, trimBounds: IBounds, scaleX = 1, scaleY = 1 | ||
| const { worldTransform, isLeafer, isFrame } = leaf | ||
| const { slice, trim, onCanvas } = options | ||
| const scale = options.scale || 1 | ||
| const pixelRatio = options.pixelRatio || 1 | ||
| const screenshot = options.screenshot || leaf.isApp | ||
| const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : undefined) : options.fill // leafer use | ||
| const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix() | ||
| if (screenshot) { | ||
| renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot | ||
| } else { | ||
| let relative: ILocationType | ILeaf = options.relative || (isLeafer ? 'inner' : 'local') | ||
| scaleX = worldTransform.scaleX | ||
| scaleY = worldTransform.scaleY | ||
| switch (relative) { | ||
| case 'inner': | ||
| matrix.set(worldTransform).invert() | ||
| break | ||
| case 'local': | ||
| matrix.set(worldTransform).divide(leaf.localTransform).invert() | ||
| scaleX /= leaf.scaleX | ||
| scaleY /= leaf.scaleY | ||
| break | ||
| case 'world': | ||
| scaleX = 1 | ||
| scaleY = 1 | ||
| break | ||
| case 'page': | ||
| relative = leaf.leafer | ||
| default: | ||
| matrix.set(worldTransform).divide(leaf.getTransform(relative)).invert() | ||
| const l = relative.worldTransform | ||
| scaleX /= scaleX / l.scaleX | ||
| scaleY /= scaleY / l.scaleY | ||
| } | ||
| renderBounds = leaf.getBounds('render', relative) | ||
| } | ||
| const { x, y, width, height } = new Bounds(renderBounds).scale(scale) | ||
| let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio }) | ||
| const renderOptions: IRenderOptions = { matrix: matrix.scale(scale).translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) } | ||
| if (slice) { | ||
| leaf = leafer // render all in bounds | ||
| renderOptions.bounds = canvas.bounds | ||
| } | ||
| canvas.save() | ||
| if (isFrame && fill !== undefined) { | ||
| const oldFill = leaf.get('fill') | ||
| leaf.fill = '' | ||
| leaf.__render(canvas, renderOptions) | ||
| leaf.fill = oldFill as string | ||
| } else { | ||
| leaf.__render(canvas, renderOptions) | ||
| } | ||
| canvas.restore() | ||
| if (trim) { | ||
| trimBounds = getTrimBounds(canvas) | ||
| const old = canvas, { width, height } = trimBounds | ||
| const config = { x: 0, y: 0, width, height, pixelRatio } | ||
| canvas = Creator.canvas(config) | ||
| canvas.copyWorld(old, trimBounds, config) | ||
| } | ||
| if (needFill) canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over') | ||
| if (onCanvas) onCanvas(canvas) | ||
| const data = filename === 'canvas' ? canvas : await canvas.export(filename, options) | ||
| over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }) | ||
| }) | ||
| } else { | ||
| over({ data: false }) | ||
| } | ||
| }) | ||
| ) | ||
| canvas.export = function (filename: IExportFileType | string, options?: IExportOptions | number | boolean): string | Promise<any> { | ||
| const { quality, blob } = FileHelper.getExportOptions(options) | ||
| if (filename.includes('.')) { | ||
| return this.saveAs(filename, quality) | ||
| } else if (blob) { | ||
| return this.toBlob(filename as IExportFileType, quality) | ||
| } else { | ||
| return this.toDataURL(filename as IExportImageType, quality) | ||
| } | ||
| } | ||
| canvas.toBlob = function (type?: IExportFileType, quality?: number): Promise<IBlob> { | ||
| return new Promise((resolve) => { | ||
| Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => { | ||
| resolve(blob) | ||
| }).catch((e) => { | ||
| debug.error(e) | ||
| resolve(null) | ||
| }) | ||
| }) | ||
| } | ||
| canvas.toDataURL = function (type?: IExportImageType, quality?: number): string | Promise<string> { | ||
| return Platform.origin.canvasToDataURL(this.view, type, quality) | ||
| } | ||
| let tasker: TaskProcessor | ||
| function addTask(task: IFunction): Promise<IExportResult> { | ||
| if (!tasker) tasker = new TaskProcessor() | ||
| return new Promise((resolve: IExportResultFunction) => { | ||
| tasker.add(async () => await task(resolve), { parallel: false }) | ||
| canvas.saveAs = function (filename: string, quality?: number): Promise<boolean> { | ||
| return new Promise((resolve) => { | ||
| Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => { | ||
| resolve(true) | ||
| }).catch((e) => { | ||
| debug.error(e) | ||
| resolve(false) | ||
| }) | ||
| }) | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
10218
18.22%7
16.67%156
31.09%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated