@leafer-ui/image 1.9.12 → 1.10.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leafer-ui/image",
3
- "version": "1.9.12",
3
+ "version": "1.10.1",
4
4
  "description": "@leafer-ui/image",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -22,11 +22,11 @@
22
22
  "leaferjs"
23
23
  ],
24
24
  "dependencies": {
25
- "@leafer/core": "1.9.12",
26
- "@leafer-ui/draw": "1.9.12"
25
+ "@leafer/core": "1.10.1",
26
+ "@leafer-ui/draw": "1.10.1"
27
27
  },
28
28
  "devDependencies": {
29
- "@leafer/interface": "1.9.12",
30
- "@leafer-ui/interface": "1.9.12"
29
+ "@leafer/interface": "1.10.1",
30
+ "@leafer-ui/interface": "1.10.1"
31
31
  }
32
32
  }
package/src/check.ts CHANGED
@@ -1,66 +1,70 @@
1
- import { ILeaferCanvas } from '@leafer/interface'
2
- import { ImageManager, Platform, ResizeEvent } from '@leafer/core'
1
+ import { ILeaferCanvas, IRenderOptions, IScaleData } from '@leafer/interface'
2
+ import { Platform, ResizeEvent } from '@leafer/core'
3
3
 
4
- import { IUI, ILeafPaint, ILeafPaintPatternData } from '@leafer-ui/interface'
5
- import { Export } from '@leafer-ui/draw'
4
+ import { IUI, ILeafPaint, IImagePaint } from '@leafer-ui/interface'
5
+ import { PaintImage } from "@leafer-ui/draw"
6
6
 
7
- import { createPattern } from './pattern'
8
7
 
8
+ export function checkImage(paint: ILeafPaint, drawImage: boolean, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): boolean {
9
+ const { scaleX, scaleY } = PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions)
10
+ const { image, data, originPaint } = paint, { exporting } = renderOptions
9
11
 
10
- export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, allowDraw?: boolean): boolean {
11
- const { scaleX, scaleY } = ui.getRenderScaleData(true, paint.scaleFixed)
12
- const { pixelRatio } = canvas, { data } = paint
13
-
14
- if (!data || (paint.patternId === scaleX + '-' + scaleY + '-' + pixelRatio && !Export.running)) {
12
+ if (!data || (paint.patternId === scaleX + '-' + scaleY && !exporting)) {
15
13
  return false // 生成图案中
16
14
  } else {
17
15
 
18
- if (allowDraw) {
16
+ if (drawImage) {
19
17
  if (data.repeat) {
20
- allowDraw = false
21
- } else if (!(paint.changeful || (Platform.name === 'miniapp' && ResizeEvent.isResizing(ui)) || Export.running)) { // 小程序resize过程中直接绘制原图(绕过垃圾回收bug)
22
- let { width, height } = data
23
- width *= scaleX * pixelRatio
24
- height *= scaleY * pixelRatio
25
- if (data.scaleX) {
26
- width *= data.scaleX
27
- height *= data.scaleY
28
- }
29
- allowDraw = (width * height > Platform.image.maxCacheSize)
18
+ drawImage = false
19
+ } else if (!((originPaint as IImagePaint).changeful || (Platform.name === 'miniapp' && ResizeEvent.isResizing(ui)) || exporting)) { // 小程序resize过程中直接绘制原图(绕过垃圾回收bug)
20
+ drawImage = Platform.image.isLarge(image, scaleX, scaleY)
30
21
  }
31
22
  }
32
23
 
33
- if (allowDraw) {
24
+ if (drawImage) {
34
25
  if (ui.__.__isFastShadow) { // fix: 快速阴影时,直接 drawImage 会无阴影,需fill一下
35
26
  canvas.fillStyle = paint.style || '#000'
36
27
  canvas.fill()
37
28
  }
38
- drawImage(ui, canvas, paint, data) // 直接绘制图像,不生成图案
29
+ PaintImage.drawImage(paint, scaleX, scaleY, ui, canvas, renderOptions) // 直接绘制图像,不生成图案
39
30
  return true
40
31
  } else {
41
- if (!paint.style || paint.sync || Export.running) {
42
- createPattern(ui, paint, pixelRatio)
43
- } else {
44
- if (!paint.patternTask) {
45
- paint.patternTask = ImageManager.patternTasker.add(async () => {
46
- paint.patternTask = null
47
- if (canvas.bounds.hit(ui.__nowWorld)) createPattern(ui, paint, pixelRatio)
48
- ui.forceUpdate('surface')
49
- }, 300)
50
- }
51
- }
32
+ if (!paint.style || (originPaint as IImagePaint).sync || exporting) PaintImage.createPattern(paint, ui, canvas, renderOptions)
33
+ else PaintImage.createPatternTask(paint, ui, canvas, renderOptions)
52
34
  return false
53
35
  }
54
36
  }
55
37
  }
56
38
 
39
+ export function drawImage(paint: ILeafPaint, _imageScaleX: number, _imageScaleY: number, ui: IUI, canvas: ILeaferCanvas, _renderOptions: IRenderOptions): void {
40
+ const { data, image } = paint, { blendMode } = paint.originPaint as IImagePaint, { opacity, transform } = data, view = image.getFull(data.filters), u = ui.__
41
+ let { width, height } = image, clipUI: any
42
+
43
+ if ((clipUI = (transform && !transform.onlyScale) || u.path || u.cornerRadius) || opacity || blendMode) {
44
+ canvas.save()
45
+ clipUI && canvas.clipUI(ui)
46
+ blendMode && (canvas.blendMode = blendMode)
47
+ opacity && (canvas.opacity *= opacity)
48
+ transform && canvas.transform(transform)
49
+ canvas.drawImage(view, 0, 0, width, height) // svg need size
50
+ canvas.restore()
51
+ } else { // 简单矩形
52
+ if (data.scaleX) width *= data.scaleX, height *= data.scaleY
53
+ canvas.drawImage(view, 0, 0, width, height)
54
+ }
55
+
56
+ }
57
57
 
58
- function drawImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, data: ILeafPaintPatternData): void { // 后续可优化
59
- canvas.save()
60
- canvas.clipUI(ui)
61
- if (paint.blendMode) canvas.blendMode = paint.blendMode
62
- if (data.opacity) canvas.opacity *= data.opacity
63
- if (data.transform) canvas.transform(data.transform)
64
- canvas.drawImage(paint.image.getFull(data.filters), 0, 0, data.width, data.height)
65
- canvas.restore()
58
+ export function getImageRenderScaleData(paint: ILeafPaint, ui: IUI, canvas?: ILeaferCanvas, _renderOptions?: IRenderOptions): IScaleData {
59
+ const scaleData = ui.getRenderScaleData(true, paint.originPaint.scaleFixed), { data } = paint
60
+ if (canvas) {
61
+ const { pixelRatio } = canvas
62
+ scaleData.scaleX *= pixelRatio
63
+ scaleData.scaleY *= pixelRatio
64
+ }
65
+ if (data && data.scaleX) {
66
+ scaleData.scaleX *= Math.abs(data.scaleX)
67
+ scaleData.scaleY *= Math.abs(data.scaleY)
68
+ }
69
+ return scaleData
66
70
  }
package/src/data.ts CHANGED
@@ -2,8 +2,7 @@ import { IBoundsData, IGap, ILeaferImage, IPointData, IPointGap, IScaleData } fr
2
2
  import { MatrixHelper, MathHelper, Bounds, AlignHelper, BoundsHelper, PointHelper, isObject, isString } from '@leafer/core'
3
3
 
4
4
  import { IImagePaint, ILeafPaint, ILeafPaintPatternData } from '@leafer-ui/interface'
5
-
6
- import { clipMode, fillOrFitMode, repeatMode, stretchMode } from './mode'
5
+ import { PaintImage } from "@leafer-ui/draw"
7
6
 
8
7
 
9
8
  const { get, translate } = MatrixHelper
@@ -12,18 +11,14 @@ const tempScaleData = {} as IScaleData
12
11
  const tempImage = {} as IBoundsData
13
12
 
14
13
  export function createData(leafPaint: ILeafPaint, image: ILeaferImage, paint: IImagePaint, box: IBoundsData): void {
15
- const { changeful, sync, scaleFixed } = paint
16
- if (changeful) leafPaint.changeful = changeful
17
- if (sync) leafPaint.sync = sync
18
- if (scaleFixed) leafPaint.scaleFixed = scaleFixed
19
- leafPaint.data = getPatternData(paint, box, image)
14
+ leafPaint.data = PaintImage.getPatternData(paint, box, image)
20
15
  }
21
16
 
22
17
  export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILeaferImage): ILeafPaintPatternData {
23
18
  if (paint.padding) box = tempBox.set(box).shrink(paint.padding)
24
19
  if (paint.mode === 'strench' as string) paint.mode = 'stretch' // 兼容代码,后续可移除
25
20
 
26
- let { width, height } = image
21
+ const { width, height } = image
27
22
  const { opacity, mode, align, offset, scale, size, rotation, skew, clipSize, repeat, gap, filters } = paint
28
23
  const sameBox = box.width === width && box.height === height
29
24
 
@@ -58,20 +53,20 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
58
53
  case 'stretch':
59
54
  if (!sameBox) {
60
55
  scaleX = box.width / width, scaleY = box.height / height
61
- stretchMode(data, box, scaleX, scaleY)
62
- }
56
+ PaintImage.stretchMode(data, box, scaleX, scaleY)
57
+ } else if (scaleX) scaleX = scaleY = undefined
63
58
  break
64
59
  case 'normal':
65
60
  case 'clip':
66
61
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) {
67
62
  let clipScaleX: number, clipScaleY: number
68
63
  if (clipSize) clipScaleX = box.width / clipSize.width, clipScaleY = box.height / clipSize.height
69
- clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY)
64
+ PaintImage.clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY)
70
65
  if (clipScaleX) scaleX = scaleX ? scaleX * clipScaleX : clipScaleX, scaleY = scaleY ? scaleY * clipScaleY : clipScaleY
71
66
  }
72
67
  break
73
68
  case 'repeat':
74
- if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform)
69
+ if (!sameBox || scaleX || rotation || skew) PaintImage.repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform)
75
70
  if (!repeat) data.repeat = 'repeat'
76
71
  const count = isObject(repeat)
77
72
  if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box)
@@ -79,22 +74,19 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
79
74
  case 'fit':
80
75
  case 'cover':
81
76
  default:
82
- if (scaleX) fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation)
77
+ if (scaleX) PaintImage.fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation)
83
78
  }
84
79
 
85
80
  if (!data.transform) {
86
81
  if (box.x || box.y) translate(data.transform = get(), box.x, box.y)
87
82
  }
88
83
 
89
- data.width = width
90
- data.height = height
91
-
92
84
  if (scaleX) {
93
85
  data.scaleX = scaleX
94
86
  data.scaleY = scaleY
95
87
  }
96
88
 
97
- if (opacity) data.opacity = opacity
89
+ if (opacity && opacity < 1) data.opacity = opacity
98
90
  if (filters) data.filters = filters
99
91
  if (repeat) data.repeat = isString(repeat) ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat'
100
92
  return data
package/src/image.ts CHANGED
@@ -2,8 +2,7 @@ import { IBoundsData, IImageEvent, ILeaferImage, IObject } from '@leafer/interfa
2
2
  import { Bounds, BoundsHelper, ImageEvent, ImageManager } from '@leafer/core'
3
3
 
4
4
  import { IUI, IImagePaint, ILeafPaint } from '@leafer-ui/interface'
5
-
6
- import { createData } from './data'
5
+ import { PaintImage } from "@leafer-ui/draw"
7
6
 
8
7
 
9
8
  interface IImagePaintCache {
@@ -102,7 +101,7 @@ function checkSizeAndCreateData(ui: IUI, attrName: string, paint: IImagePaint, i
102
101
  }
103
102
  }
104
103
 
105
- if (!leafPaint.data) createData(leafPaint, image, paint, boxBounds)
104
+ if (!leafPaint.data) PaintImage.createData(leafPaint, image, paint, boxBounds)
106
105
  return true
107
106
  }
108
107
 
package/src/index.ts CHANGED
@@ -3,17 +3,23 @@ import { IPaintImageModule } from '@leafer-ui/interface'
3
3
  import { image } from './image'
4
4
  import { createData, getPatternData } from './data'
5
5
  import { fillOrFitMode, clipMode, repeatMode, stretchMode } from './mode'
6
- import { createPattern } from './pattern'
7
- import { checkImage } from './check'
6
+ import { createPatternTask, createPattern, getPatternFixScale } from './pattern'
7
+ import { checkImage, drawImage, getImageRenderScaleData } from './check'
8
8
  import { recycleImage } from './recycle'
9
9
 
10
10
 
11
11
  export const PaintImageModule: IPaintImageModule = {
12
12
  image,
13
+
13
14
  checkImage,
14
- createPattern,
15
+ drawImage,
16
+ getImageRenderScaleData,
15
17
  recycleImage,
16
18
 
19
+ createPatternTask,
20
+ createPattern,
21
+ getPatternFixScale,
22
+
17
23
  createData,
18
24
  getPatternData,
19
25
 
package/src/mode.ts CHANGED
@@ -8,9 +8,10 @@ let origin = {} as IPointData, tempMatrix = getMatrixData()
8
8
  const { get, set, rotateOfOuter, translate, scaleOfOuter, multiplyParent, scale: scaleHelper, rotate, skew: skewHelper } = MatrixHelper
9
9
 
10
10
  export function stretchMode(data: ILeafPaintPatternData, box: IBoundsData, scaleX: number, scaleY: number): void {
11
- const transform: IMatrixData = get()
12
- translate(transform, box.x, box.y)
13
- if (scaleX) scaleHelper(transform, scaleX, scaleY)
11
+ const transform: IMatrixData = get(), { x, y } = box
12
+ if (x || y) translate(transform, x, y)
13
+ else transform.onlyScale = true
14
+ scaleHelper(transform, scaleX, scaleY)
14
15
  data.transform = transform
15
16
  }
16
17
 
package/src/pattern.ts CHANGED
@@ -1,99 +1,72 @@
1
- import { Platform, MatrixHelper } from '@leafer/core'
1
+ import { ILeaferCanvas, IRenderOptions } from '@leafer/interface'
2
+ import { Platform, MatrixHelper, MathHelper, ImageManager } from '@leafer/core'
2
3
 
3
4
  import { IUI, ILeafPaint, IMatrixData } from '@leafer-ui/interface'
5
+ import { PaintImage } from "@leafer-ui/draw"
4
6
 
5
7
 
6
8
  const { get, scale, copy } = MatrixHelper
7
- const { floor, ceil, max, abs } = Math
9
+ const { getFloorScale } = MathHelper, { abs } = Math
10
+
11
+ export function createPatternTask(paint: ILeafPaint, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): void {
12
+ if (!paint.patternTask) {
13
+ paint.patternTask = ImageManager.patternTasker.add(async () => {
14
+ paint.patternTask = null
15
+ if (canvas.bounds.hit(ui.__nowWorld)) PaintImage.createPattern(paint, ui, canvas, renderOptions)
16
+ ui.forceUpdate('surface')
17
+ }, 300)
18
+ }
19
+ }
8
20
 
9
- export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): boolean {
10
- let { scaleX, scaleY } = ui.getRenderScaleData(true, paint.scaleFixed)
11
- const id = scaleX + '-' + scaleY + '-' + pixelRatio
21
+ export function createPattern(paint: ILeafPaint, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): void {
22
+ let { scaleX, scaleY } = PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions), id = scaleX + '-' + scaleY
12
23
 
13
24
  if (paint.patternId !== id && !ui.destroyed) {
25
+ if (!(Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)) {
14
26
 
15
- const { image, data } = paint
16
- let imageScale: number, imageMatrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, transform, repeat, gap } = data
17
-
18
- scaleX *= pixelRatio
19
- scaleY *= pixelRatio
20
-
21
- if (sx) {
22
- sx = abs(sx) // maybe -1
23
- sy = abs(sy)
24
- imageMatrix = get()
25
- copy(imageMatrix, transform)
26
- scale(imageMatrix, 1 / sx, 1 / sy)
27
- scaleX *= sx
28
- scaleY *= sy
29
- }
30
-
31
- width *= scaleX
32
- height *= scaleY
33
-
34
- const size = width * height
35
-
36
- if (!repeat) {
37
- if (size > Platform.image.maxCacheSize) return false // same as check()
38
- }
39
-
40
- let maxSize = Platform.image.maxPatternSize
41
-
42
- if (image.isSVG) {
43
- const ws = width / image.width
44
- if (ws > 1) imageScale = ws / ceil(ws) // fix: svg按整数倍放大,避免产生加深线条
45
- } else {
46
- const imageSize = image.width * image.height
47
- if (maxSize > imageSize) maxSize = imageSize
48
- }
49
-
50
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize)
51
-
52
- if (imageScale) {
53
- scaleX /= imageScale
54
- scaleY /= imageScale
55
- width /= imageScale
56
- height /= imageScale
57
- }
27
+ const { image, data } = paint, { transform, gap } = data, fixScale = PaintImage.getPatternFixScale(paint, scaleX, scaleY)
28
+ let imageMatrix: IMatrixData, xGap: number, yGap: number, { width, height } = image
58
29
 
59
- if (sx) {
60
- scaleX /= sx
61
- scaleY /= sy
62
- }
30
+ if (fixScale) scaleX *= fixScale, scaleY *= fixScale
63
31
 
64
- // 间距
65
- const xGap = gap && (gap.x * scaleX)
66
- const yGap = gap && (gap.y * scaleY)
32
+ width *= scaleX
33
+ height *= scaleY
67
34
 
68
- if (transform || scaleX !== 1 || scaleY !== 1) {
35
+ // 平铺间距
36
+ if (gap) {
37
+ xGap = gap.x * scaleX / abs(data.scaleX || 1)
38
+ yGap = gap.y * scaleY / abs(data.scaleY || 1)
39
+ }
69
40
 
70
- // 缩放至floor画布宽高的状态
71
- const canvasWidth = width + (xGap || 0)
72
- const canvasHeight = height + (yGap || 0)
73
- scaleX /= canvasWidth / max(floor(canvasWidth), 1)
74
- scaleY /= canvasHeight / max(floor(canvasHeight), 1)
41
+ if (transform || scaleX !== 1 || scaleY !== 1) {
42
+ scaleX *= getFloorScale(width + (xGap || 0)) // 缩放至floor画布宽高的状态
43
+ scaleY *= getFloorScale(height + (yGap || 0))
75
44
 
76
- if (!imageMatrix) {
77
45
  imageMatrix = get()
78
46
  if (transform) copy(imageMatrix, transform)
47
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY)
79
48
  }
80
49
 
81
- scale(imageMatrix, 1 / scaleX, 1 / scaleY)
50
+ const imageCanvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth)
51
+ const pattern = image.getPattern(imageCanvas, data.repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint)
82
52
 
83
- }
53
+ paint.style = pattern
54
+ paint.patternId = id
84
55
 
85
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth)
86
- const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint)
87
-
88
- paint.style = pattern
89
- paint.patternId = id
56
+ }
57
+ }
58
+ }
90
59
 
91
- return true
60
+ export function getPatternFixScale(paint: ILeafPaint, imageScaleX: number, imageScaleY: number): number {
61
+ const { image } = paint
62
+ let fixScale: number, maxSize = Platform.image.maxPatternSize, imageSize = image.width * image.height
92
63
 
64
+ if (image.isSVG) {
65
+ if (imageScaleX > 1) fixScale = Math.ceil(imageScaleX) / imageScaleX // fix: svg按整数倍放大,避免产生加深线条
93
66
  } else {
94
-
95
- return false
96
-
67
+ if (maxSize > imageSize) maxSize = imageSize // 防止大于元素自身宽高
97
68
  }
98
69
 
70
+ if ((imageSize *= imageScaleX * imageScaleY) > maxSize) fixScale = Math.sqrt(maxSize / imageSize)
71
+ return fixScale
99
72
  }