You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@leafer-ui/export

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@leafer-ui/export - npm Package Compare versions

Comparing version
1.0.0-rc.19
to
1.0.0-rc.20
+137
src/export.ts
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"
}
}

@@ -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)
})
})
}