pixel-data-js 0.27.0 → 0.29.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.
Files changed (148) hide show
  1. package/README.md +12 -2
  2. package/dist/index.prod.cjs +2355 -1124
  3. package/dist/index.prod.cjs.map +1 -1
  4. package/dist/index.prod.d.ts +558 -424
  5. package/dist/index.prod.js +2304 -1115
  6. package/dist/index.prod.js.map +1 -1
  7. package/package.json +11 -11
  8. package/src/Algorithm/floodFillSelection.ts +8 -6
  9. package/src/Algorithm/forEachLinePoint.ts +6 -6
  10. package/src/{Internal/resample32.ts → Algorithm/resampleUint32Array.ts} +11 -21
  11. package/src/BlendModes/blend-modes-fast.ts +169 -0
  12. package/src/BlendModes/blend-modes-perfect.ts +207 -0
  13. package/src/BlendModes/blend-modes.ts +9 -0
  14. package/src/Canvas/CanvasFrameRenderer.ts +20 -28
  15. package/src/Canvas/CanvasPixelDataRenderer.ts +23 -0
  16. package/src/Canvas/PixelCanvas.ts +2 -7
  17. package/src/Canvas/ReusableCanvas.ts +4 -12
  18. package/src/Canvas/_canvas-types.ts +26 -0
  19. package/src/History/PixelAccumulator.ts +17 -17
  20. package/src/History/PixelEngineConfig.ts +3 -3
  21. package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +4 -3
  22. package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +4 -3
  23. package/src/History/PixelMutator/mutatorApplyMask.ts +4 -3
  24. package/src/History/PixelMutator/mutatorBlendAlphaMask.ts +6 -4
  25. package/src/History/PixelMutator/mutatorBlendBinaryMask.ts +6 -4
  26. package/src/History/PixelMutator/mutatorBlendColor.ts +2 -2
  27. package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +2 -1
  28. package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +2 -1
  29. package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +3 -1
  30. package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +3 -3
  31. package/src/History/PixelMutator/mutatorBlendMask.ts +6 -4
  32. package/src/History/PixelMutator/mutatorBlendPixelData.ts +5 -4
  33. package/src/History/PixelMutator/mutatorClear.ts +4 -3
  34. package/src/History/PixelMutator/mutatorFill.ts +5 -4
  35. package/src/History/PixelMutator/mutatorFillBinaryMask.ts +2 -1
  36. package/src/History/PixelMutator/mutatorInvert.ts +2 -2
  37. package/src/History/PixelMutator.ts +1 -1
  38. package/src/History/PixelPatchTiles.ts +7 -7
  39. package/src/History/PixelWriter.ts +12 -63
  40. package/src/ImageData/ImageDataLike.ts +1 -1
  41. package/src/ImageData/_ImageData-types.ts +13 -0
  42. package/src/ImageData/copyImageData.ts +1 -1
  43. package/src/ImageData/extractImageDataBuffer.ts +3 -2
  44. package/src/ImageData/imageDataToUint32Array.ts +18 -0
  45. package/src/ImageData/resampleImageData.ts +3 -3
  46. package/src/ImageData/resizeImageData.ts +1 -1
  47. package/src/ImageData/serialization.ts +1 -1
  48. package/src/ImageData/uInt32ArrayToImageData.ts +1 -1
  49. package/src/ImageData/writeImageData.ts +2 -2
  50. package/src/ImageData/writeImageDataBuffer.ts +2 -2
  51. package/src/IndexedImage/IndexedImage.ts +56 -98
  52. package/src/IndexedImage/_indexedImage-types.ts +18 -0
  53. package/src/IndexedImage/getIndexedImageColorCounts.ts +3 -3
  54. package/src/IndexedImage/indexedImageToAverageColor.ts +1 -1
  55. package/src/IndexedImage/indexedImageToImageData.ts +4 -6
  56. package/src/IndexedImage/resampleIndexedImage.ts +7 -15
  57. package/src/Input/fileToImageData.ts +1 -1
  58. package/src/Internal/_constants.ts +3 -0
  59. package/src/Internal/_errors.ts +2 -0
  60. package/src/Internal/macros.ts +14 -0
  61. package/src/Mask/AlphaMask.ts +1 -1
  62. package/src/Mask/BinaryMask/makeBinaryMaskFromAlphaMask.ts +23 -0
  63. package/src/Mask/BinaryMask/makeBinaryMaskOutline.ts +88 -0
  64. package/src/Mask/BinaryMask/makeCircleBinaryMaskOutline.ts +104 -0
  65. package/src/Mask/BinaryMask/makeRectBinaryMaskOutline.ts +34 -0
  66. package/src/Mask/BinaryMask.ts +1 -1
  67. package/src/Mask/_mask-types.ts +73 -0
  68. package/src/Mask/applyBinaryMaskToAlphaMask.ts +2 -1
  69. package/src/Mask/copyMask.ts +1 -1
  70. package/src/Mask/extractMask.ts +2 -1
  71. package/src/Mask/extractMaskBuffer.ts +1 -1
  72. package/src/Mask/mergeAlphaMasks.ts +6 -3
  73. package/src/Mask/mergeBinaryMasks.ts +2 -1
  74. package/src/Mask/setMaskData.ts +1 -1
  75. package/src/MaskRect/merge2BinaryMaskRects.ts +2 -2
  76. package/src/MaskRect/mergeBinaryMaskRects.ts +1 -1
  77. package/src/MaskRect/subtractBinaryMaskRects.ts +1 -1
  78. package/src/Paint/AlphaMaskPaintBuffer.ts +283 -0
  79. package/src/Paint/BinaryMaskPaintBuffer.ts +198 -0
  80. package/src/Paint/{PaintBuffer.ts → ColorPaintBuffer.ts} +95 -77
  81. package/src/Paint/Commit/AlphaMaskPaintBufferCommitter.ts +26 -0
  82. package/src/Paint/Commit/AlphaMaskPaintBufferManager.ts +34 -0
  83. package/src/Paint/Commit/BinaryMaskPaintBufferCommitter.ts +26 -0
  84. package/src/Paint/Commit/BinaryMaskPaintBufferManager.ts +31 -0
  85. package/src/Paint/Commit/ColorPaintBufferCommitter.ts +23 -0
  86. package/src/Paint/Commit/ColorPaintBufferManager.ts +34 -0
  87. package/src/Paint/Commit/commitColorPaintBuffer.ts +55 -0
  88. package/src/Paint/Commit/commitMaskPaintBuffer.ts +78 -0
  89. package/src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts +78 -0
  90. package/src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts +67 -0
  91. package/src/Paint/{PaintBufferCanvasRenderer.ts → Render/ColorPaintBufferCanvasRenderer.ts} +13 -14
  92. package/src/Paint/Render/PaintCursorRenderer.ts +118 -0
  93. package/src/Paint/_paint-types.ts +22 -0
  94. package/src/Paint/eachTileInBounds.ts +45 -0
  95. package/src/Paint/makeCirclePaintMask.ts +74 -0
  96. package/src/Paint/makePaintMask.ts +5 -2
  97. package/src/Paint/makeRectFalloffPaintAlphaMask.ts +4 -2
  98. package/src/PixelData/PixelData.ts +15 -19
  99. package/src/PixelData/ReusablePixelData.ts +36 -0
  100. package/src/PixelData/_pixelData-types.ts +17 -0
  101. package/src/PixelData/applyAlphaMaskToPixelData.ts +80 -43
  102. package/src/PixelData/applyBinaryMaskToPixelData.ts +10 -8
  103. package/src/PixelData/applyMaskToPixelData.ts +4 -9
  104. package/src/PixelData/blendColorPixelData.ts +9 -8
  105. package/src/PixelData/blendColorPixelDataAlphaMask.ts +9 -7
  106. package/src/PixelData/blendColorPixelDataBinaryMask.ts +9 -7
  107. package/src/PixelData/blendColorPixelDataMask.ts +4 -2
  108. package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +4 -2
  109. package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +4 -2
  110. package/src/PixelData/blendColorPixelDataPaintMask.ts +5 -2
  111. package/src/PixelData/blendPixel.ts +6 -5
  112. package/src/PixelData/blendPixelData.ts +14 -13
  113. package/src/PixelData/blendPixelDataAlphaMask.ts +15 -13
  114. package/src/PixelData/blendPixelDataBinaryMask.ts +15 -13
  115. package/src/PixelData/blendPixelDataMask.ts +5 -3
  116. package/src/PixelData/blendPixelDataPaintBuffer.ts +5 -4
  117. package/src/PixelData/clearPixelDataFast.ts +4 -2
  118. package/src/PixelData/copyPixelData.ts +14 -0
  119. package/src/PixelData/extractPixelData.ts +8 -7
  120. package/src/PixelData/extractPixelDataBuffer.ts +9 -8
  121. package/src/PixelData/fillPixelData.ts +16 -14
  122. package/src/PixelData/fillPixelDataBinaryMask.ts +10 -8
  123. package/src/PixelData/fillPixelDataFast.ts +16 -14
  124. package/src/PixelData/invertPixelData.ts +9 -8
  125. package/src/PixelData/pixelDataToAlphaMask.ts +9 -8
  126. package/src/PixelData/reflectPixelData.ts +9 -9
  127. package/src/PixelData/resamplePixelData.ts +20 -9
  128. package/src/PixelData/rotatePixelData.ts +8 -7
  129. package/src/PixelData/uInt32ArrayToPixelData.ts +15 -0
  130. package/src/PixelData/writePaintBufferToPixelData.ts +5 -5
  131. package/src/PixelData/writePixelDataBuffer.ts +10 -9
  132. package/src/Rect/_rect-types.ts +7 -0
  133. package/src/Rect/getRectsBounds.ts +1 -1
  134. package/src/Rect/trimMaskRectBounds.ts +2 -1
  135. package/src/Rect/trimRectBounds.ts +1 -1
  136. package/src/Tile/MaskTile.ts +40 -0
  137. package/src/Tile/PixelTile.ts +23 -0
  138. package/src/{PixelTile/PixelTilePool.ts → Tile/TilePool.ts} +9 -9
  139. package/src/Tile/_tile-types.ts +33 -0
  140. package/src/_errors.ts +1 -0
  141. package/src/_types.ts +2 -118
  142. package/src/index.ts +57 -21
  143. package/src/ImageData/imageDataToUInt32Array.ts +0 -13
  144. package/src/Internal/helpers.ts +0 -5
  145. package/src/Paint/makeCirclePaintAlphaMask.ts +0 -41
  146. package/src/Paint/makeCirclePaintBinaryMask.ts +0 -29
  147. package/src/PixelTile/PixelTile.ts +0 -21
  148. /package/src/{Internal → Rect}/resolveClipping.ts +0 -0
@@ -1,78 +1,60 @@
1
- import type { Color32, PaintAlphaMask, PaintBinaryMask, Rect } from '../_types'
1
+ import type { Color32 } from '../_types'
2
2
  import { forEachLinePoint } from '../Algorithm/forEachLinePoint'
3
3
  import type { PixelEngineConfig } from '../History/PixelEngineConfig'
4
- import { _macro_paintRectCenterOffset } from '../Internal/helpers'
5
- import type { PixelTile } from '../PixelTile/PixelTile'
6
- import type { PixelTilePool } from '../PixelTile/PixelTilePool'
4
+ import { _macro_paintRectCenterOffset } from '../Internal/macros'
5
+ import type { Rect } from '../Rect/_rect-types'
7
6
  import { trimRectBounds } from '../Rect/trimRectBounds'
7
+ import type { PixelTile } from '../Tile/_tile-types'
8
+ import type { TilePool } from '../Tile/TilePool'
9
+ import type { PaintAlphaMask, PaintBinaryMask } from './_paint-types'
10
+ import { eachTileInBounds } from './eachTileInBounds'
8
11
 
9
- export class PaintBuffer {
12
+ export class ColorPaintBuffer {
10
13
  readonly lookup: (PixelTile | undefined)[]
11
14
  private readonly scratchBounds: Rect = { x: 0, y: 0, w: 0, h: 0 }
12
15
 
13
16
  constructor(
14
17
  readonly config: PixelEngineConfig,
15
- readonly tilePool: PixelTilePool,
18
+ readonly tilePool: TilePool<PixelTile>,
16
19
  ) {
17
20
  this.lookup = []
18
21
  }
19
22
 
20
- private eachTileInBounds(
21
- bounds: Rect,
22
- callback: (tile: PixelTile, bX: number, bY: number, bW: number, bH: number) => void,
23
- ): void {
24
- const { tileShift, targetColumns, targetRows, tileSize } = this.config
25
-
26
- const x1 = Math.max(0, bounds.x >> tileShift)
27
- const y1 = Math.max(0, bounds.y >> tileShift)
28
- const x2 = Math.min(targetColumns - 1, (bounds.x + bounds.w - 1) >> tileShift)
29
- const y2 = Math.min(targetRows - 1, (bounds.y + bounds.h - 1) >> tileShift)
30
-
31
- if (x1 > x2 || y1 > y2) return
32
-
33
- const lookup = this.lookup
34
- const tilePool = this.tilePool
35
-
36
- for (let ty = y1; ty <= y2; ty++) {
37
- const rowOffset = ty * targetColumns
38
- const tileTop = ty << tileShift
39
-
40
- for (let tx = x1; tx <= x2; tx++) {
41
- const id = rowOffset + tx
42
- const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty))
43
- const tileLeft = tx << tileShift
44
-
45
- const startX = bounds.x > tileLeft ? bounds.x : tileLeft
46
- const startY = bounds.y > tileTop ? bounds.y : tileTop
47
-
48
- const maskEndX = bounds.x + bounds.w
49
- const tileEndX = tileLeft + tileSize
50
- const endX = maskEndX < tileEndX ? maskEndX : tileEndX
51
-
52
- const maskEndY = bounds.y + bounds.h
53
- const tileEndY = tileTop + tileSize
54
- const endY = maskEndY < tileEndY ? maskEndY : tileEndY
55
-
56
- callback(tile, startX, startY, endX - startX, endY - startY)
57
- }
58
- }
59
- }
60
-
61
- writePaintAlphaMaskStroke(
23
+ paintAlphaMask(
24
+ color: Color32,
25
+ brush: PaintAlphaMask,
26
+ x: number,
27
+ y: number,
28
+ ): boolean
29
+ paintAlphaMask(
30
+ color: Color32,
31
+ brush: PaintAlphaMask,
32
+ startX: number,
33
+ startY: number,
34
+ endX: number,
35
+ endY: number,
36
+ ): boolean
37
+ paintAlphaMask(
62
38
  color: Color32,
63
39
  brush: PaintAlphaMask,
64
40
  x0: number,
65
41
  y0: number,
66
- x1: number,
67
- y1: number,
42
+ x1: number = x0,
43
+ y1: number = y0,
68
44
  ): boolean {
69
45
  const cA = color >>> 24
70
46
  if (cA === 0) return false
71
47
 
72
- const { tileShift, tileMask, target } = this.config
48
+ const scratch = this.scratchBounds
49
+ const lookup = this.lookup
50
+ const tilePool = this.tilePool
51
+ const config = this.config
52
+ const tileShift = config.tileShift
53
+ const tileMask = config.tileMask
54
+ const target = config.target
55
+
73
56
  const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
74
57
  const cRGB = color & 0x00ffffff
75
- const scratch = this.scratchBounds
76
58
 
77
59
  let changed = false
78
60
 
@@ -85,15 +67,15 @@ export class PaintBuffer {
85
67
  topLeftY,
86
68
  bW,
87
69
  bH,
88
- target.width,
89
- target.height,
70
+ target.w,
71
+ target.h,
90
72
  scratch,
91
73
  )
92
74
 
93
75
  if (scratch.w <= 0 || scratch.h <= 0) return
94
76
 
95
- this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
96
- const d32 = tile.data32
77
+ eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
78
+ const d32 = tile.data
97
79
  let tileChanged = false
98
80
 
99
81
  for (let i = 0; i < bH_t; i++) {
@@ -127,20 +109,40 @@ export class PaintBuffer {
127
109
  return changed
128
110
  }
129
111
 
130
- writePaintBinaryMaskStroke(
112
+ paintBinaryMask(
113
+ color: Color32,
114
+ brush: PaintBinaryMask,
115
+ x: number,
116
+ y: number,
117
+ ): boolean
118
+ paintBinaryMask(
119
+ color: Color32,
120
+ brush: PaintBinaryMask,
121
+ startX: number,
122
+ startY: number,
123
+ endX: number,
124
+ endY: number,
125
+ ): boolean
126
+ paintBinaryMask(
131
127
  color: Color32,
132
128
  brush: PaintBinaryMask,
133
129
  x0: number,
134
130
  y0: number,
135
- x1: number,
136
- y1: number,
131
+ x1: number = x0,
132
+ y1: number = y0,
137
133
  ): boolean {
138
134
  const alphaIsZero = (color >>> 24) === 0
139
135
  if (alphaIsZero) return false
140
136
 
141
- const { tileShift, tileMask, target } = this.config
142
- const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
143
137
  const scratch = this.scratchBounds
138
+ const lookup = this.lookup
139
+ const tilePool = this.tilePool
140
+ const config = this.config
141
+ const tileShift = config.tileShift
142
+ const tileMask = config.tileMask
143
+ const target = config.target
144
+
145
+ const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
144
146
  let changed = false
145
147
 
146
148
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
@@ -152,15 +154,15 @@ export class PaintBuffer {
152
154
  topLeftY,
153
155
  bW,
154
156
  bH,
155
- target.width,
156
- target.height,
157
+ target.w,
158
+ target.h,
157
159
  scratch,
158
160
  )
159
161
 
160
162
  if (scratch.w <= 0 || scratch.h <= 0) return
161
163
 
162
- this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
163
- const d32 = tile.data32
164
+ eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
165
+ const d32 = tile.data
164
166
  let tileChanged = false
165
167
 
166
168
  for (let i = 0; i < bH_t; i++) {
@@ -187,26 +189,44 @@ export class PaintBuffer {
187
189
  return changed
188
190
  }
189
191
 
190
- writeRectStroke(
192
+ paintRect(
193
+ color: Color32,
194
+ brushWidth: number,
195
+ brushHeight: number,
196
+ x: number,
197
+ y: number,
198
+ ): boolean
199
+ paintRect(
200
+ color: Color32,
201
+ brushWidth: number,
202
+ brushHeight: number,
203
+ startX: number,
204
+ startY: number,
205
+ endX: number,
206
+ endY: number,
207
+ ): boolean
208
+ paintRect(
191
209
  color: Color32,
192
210
  brushWidth: number,
193
211
  brushHeight: number,
194
212
  x0: number,
195
213
  y0: number,
196
- x1: number,
197
- y1: number,
214
+ x1: number = x0,
215
+ y1: number = y0,
198
216
  ): boolean {
199
217
  const alphaIsZero = (color >>> 24) === 0
200
218
  if (alphaIsZero) return false
201
219
 
220
+ const scratch = this.scratchBounds
221
+ const lookup = this.lookup
222
+ const tilePool = this.tilePool
202
223
  const config = this.config
203
224
  const tileShift = config.tileShift
204
225
  const tileMask = config.tileMask
205
226
  const target = config.target
206
- const scratch = this.scratchBounds
207
227
 
208
- const centerOffsetX = -_macro_paintRectCenterOffset(brushWidth)
209
- const centerOffsetY = -_macro_paintRectCenterOffset(brushHeight)
228
+ const centerOffsetX = _macro_paintRectCenterOffset(brushWidth)
229
+ const centerOffsetY = _macro_paintRectCenterOffset(brushHeight)
210
230
 
211
231
  let changed = false
212
232
 
@@ -224,17 +244,15 @@ export class PaintBuffer {
224
244
  topLeftY,
225
245
  brushWidth,
226
246
  brushHeight,
227
- target.width,
228
- target.height,
247
+ target.w,
248
+ target.h,
229
249
  scratch,
230
250
  )
231
251
 
232
252
  if (scratch.w <= 0 || scratch.h <= 0) return
233
253
 
234
- this.eachTileInBounds(
235
- scratch,
236
- (tile, bX, bY, bW_t, bH_t) => {
237
- const d32 = tile.data32
254
+ eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
255
+ const d32 = tile.data
238
256
  let tileChanged = false
239
257
 
240
258
  for (let i = 0; i < bH_t; i++) {
@@ -0,0 +1,26 @@
1
+ import type { Color32 } from '../../_types'
2
+ import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
3
+ import type { PixelAccumulator } from '../../History/PixelAccumulator'
4
+ import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
5
+ import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
6
+ import { commitMaskPaintBuffer } from './commitMaskPaintBuffer'
7
+
8
+ export function makeAlphaMaskPaintBufferCommitter(
9
+ accumulator: PixelAccumulator,
10
+ paintBuffer: AlphaMaskPaintBuffer,
11
+ ) {
12
+ return function commitAlphaMaskPaintBufferToAccumulator(
13
+ color: Color32,
14
+ alpha = 255,
15
+ blendFn = sourceOverPerfect,
16
+ ) {
17
+ return commitMaskPaintBuffer(
18
+ accumulator,
19
+ paintBuffer,
20
+ color,
21
+ alpha,
22
+ blendFn,
23
+ blendColorPixelDataAlphaMask,
24
+ )
25
+ }
26
+ }
@@ -0,0 +1,34 @@
1
+ import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
2
+ import type { PixelWriter } from '../../History/PixelWriter'
3
+ import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
4
+ import { makeAlphaMaskTile } from '../../Tile/MaskTile'
5
+ import { TilePool } from '../../Tile/TilePool'
6
+ import { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
7
+ import { makeAlphaMaskPaintBufferCanvasRenderer } from '../Render/AlphaMaskPaintBufferCanvasRenderer'
8
+ import { makeAlphaMaskPaintBufferCommitter } from './AlphaMaskPaintBufferCommitter'
9
+
10
+ export type AlphaMaskPaintBufferManager =
11
+ Pick<AlphaMaskPaintBuffer, 'paintAlphaMask' | 'paintBinaryMask' | 'paintRect'>
12
+ & {
13
+ commit: ReturnType<typeof makeAlphaMaskPaintBufferCommitter>
14
+ draw: ReturnType<typeof makeAlphaMaskPaintBufferCanvasRenderer>
15
+ clear: () => void
16
+ }
17
+
18
+ export function makeAlphaMaskPaintBufferManager(
19
+ writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
20
+ canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
21
+ ): AlphaMaskPaintBufferManager {
22
+ const pool = new TilePool(writer.config, makeAlphaMaskTile)
23
+ const buffer = new AlphaMaskPaintBuffer(writer.config, pool)
24
+ const draw = makeAlphaMaskPaintBufferCanvasRenderer(buffer, canvasFactory)
25
+
26
+ return {
27
+ clear: buffer.clear.bind(buffer),
28
+ paintRect: buffer.paintRect.bind(buffer),
29
+ paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
30
+ paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
31
+ commit: makeAlphaMaskPaintBufferCommitter(writer.accumulator, buffer),
32
+ draw,
33
+ }
34
+ }
@@ -0,0 +1,26 @@
1
+ import type { Color32 } from '../../_types'
2
+ import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
3
+ import type { PixelAccumulator } from '../../History/PixelAccumulator'
4
+ import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
5
+ import type { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
6
+ import { commitMaskPaintBuffer } from './commitMaskPaintBuffer'
7
+
8
+ export function makeBinaryMaskPaintBufferCommitter(
9
+ accumulator: PixelAccumulator,
10
+ paintBuffer: BinaryMaskPaintBuffer,
11
+ ) {
12
+ return function commitBinaryMaskPaintBufferToAccumulator(
13
+ color: Color32,
14
+ alpha = 255,
15
+ blendFn = sourceOverPerfect,
16
+ ) {
17
+ return commitMaskPaintBuffer(
18
+ accumulator,
19
+ paintBuffer,
20
+ color,
21
+ alpha,
22
+ blendFn,
23
+ blendColorPixelDataBinaryMask,
24
+ )
25
+ }
26
+ }
@@ -0,0 +1,31 @@
1
+ import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
2
+ import type { PixelWriter } from '../../History/PixelWriter'
3
+ import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
4
+ import { makeBinaryMaskTile } from '../../Tile/MaskTile'
5
+ import { TilePool } from '../../Tile/TilePool'
6
+ import { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
7
+ import { makeBinaryMaskPaintBufferCanvasRenderer } from '../Render/BinaryMaskPaintBufferCanvasRenderer'
8
+ import { makeBinaryMaskPaintBufferCommitter } from './BinaryMaskPaintBufferCommitter'
9
+
10
+ export type BinaryMaskPaintBufferManager = Pick<BinaryMaskPaintBuffer, 'paintBinaryMask' | 'paintRect'> & {
11
+ commit: ReturnType<typeof makeBinaryMaskPaintBufferCommitter>
12
+ draw: ReturnType<typeof makeBinaryMaskPaintBufferCanvasRenderer>
13
+ clear: () => void
14
+ }
15
+
16
+ export function makeBinaryMaskPaintBufferManager(
17
+ writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
18
+ canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
19
+ ): BinaryMaskPaintBufferManager {
20
+ const pool = new TilePool(writer.config, makeBinaryMaskTile)
21
+ const buffer = new BinaryMaskPaintBuffer(writer.config, pool)
22
+ const draw = makeBinaryMaskPaintBufferCanvasRenderer(buffer, canvasFactory)
23
+
24
+ return {
25
+ clear: buffer.clear.bind(buffer),
26
+ paintRect: buffer.paintRect.bind(buffer),
27
+ paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
28
+ commit: makeBinaryMaskPaintBufferCommitter(writer.accumulator, buffer),
29
+ draw,
30
+ }
31
+ }
@@ -0,0 +1,23 @@
1
+ import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
2
+ import type { PixelAccumulator } from '../../History/PixelAccumulator'
3
+ import { blendPixelData } from '../../PixelData/blendPixelData'
4
+ import type { ColorPaintBuffer } from '../ColorPaintBuffer'
5
+ import { commitColorPaintBuffer } from './commitColorPaintBuffer'
6
+
7
+ export function makeColorPaintBufferCommitter(
8
+ accumulator: PixelAccumulator,
9
+ paintBuffer: ColorPaintBuffer,
10
+ ) {
11
+ return function commitColorPaintBufferToAccumulator(
12
+ alpha = 255,
13
+ blendFn = sourceOverPerfect,
14
+ ) {
15
+ return commitColorPaintBuffer(
16
+ accumulator,
17
+ paintBuffer,
18
+ alpha,
19
+ blendFn,
20
+ blendPixelData,
21
+ )
22
+ }
23
+ }
@@ -0,0 +1,34 @@
1
+ import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
2
+ import type { PixelWriter } from '../../History/PixelWriter'
3
+ import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
4
+ import { makePixelTile } from '../../Tile/PixelTile'
5
+ import { TilePool } from '../../Tile/TilePool'
6
+ import { ColorPaintBuffer } from '../ColorPaintBuffer'
7
+ import { makeColorPaintBufferCanvasRenderer } from '../Render/ColorPaintBufferCanvasRenderer'
8
+ import { makeColorPaintBufferCommitter } from './ColorPaintBufferCommitter'
9
+
10
+ export type ColorPaintBufferManager =
11
+ Pick<ColorPaintBuffer, 'paintAlphaMask' | 'paintBinaryMask' | 'paintRect'>
12
+ & {
13
+ commit: ReturnType<typeof makeColorPaintBufferCommitter>
14
+ draw: ReturnType<typeof makeColorPaintBufferCanvasRenderer>
15
+ clear: () => void
16
+ }
17
+
18
+ export function makeColorPaintBufferManager(
19
+ writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
20
+ canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
21
+ ): ColorPaintBufferManager {
22
+ const pool = new TilePool(writer.config, makePixelTile)
23
+ const buffer = new ColorPaintBuffer(writer.config, pool)
24
+ const draw = makeColorPaintBufferCanvasRenderer(buffer, canvasFactory)
25
+
26
+ return {
27
+ clear: buffer.clear.bind(buffer),
28
+ paintRect: buffer.paintRect.bind(buffer),
29
+ paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
30
+ paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
31
+ commit: makeColorPaintBufferCommitter(writer.accumulator, buffer),
32
+ draw,
33
+ }
34
+ }
@@ -0,0 +1,55 @@
1
+ import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
2
+ import type { PixelAccumulator } from '../../History/PixelAccumulator'
3
+ import { blendPixelData } from '../../PixelData/blendPixelData'
4
+ import type { ColorPaintBuffer } from '../ColorPaintBuffer'
5
+
6
+ const SCRATCH_OPTS = {
7
+ alpha: 255,
8
+ blendFn: sourceOverPerfect,
9
+ x: 0,
10
+ y: 0,
11
+ w: 0,
12
+ h: 0,
13
+ }
14
+
15
+ export function commitColorPaintBuffer(
16
+ accumulator: PixelAccumulator,
17
+ paintBuffer: ColorPaintBuffer,
18
+ alpha = 255,
19
+ blendFn = sourceOverPerfect,
20
+ blendPixelDataFn = blendPixelData,
21
+ ) {
22
+ const config = accumulator.config
23
+ const tileShift = config.tileShift
24
+ const lookup = paintBuffer.lookup
25
+
26
+ SCRATCH_OPTS.alpha = alpha
27
+ SCRATCH_OPTS.blendFn = blendFn
28
+
29
+ for (let i = 0; i < lookup.length; i++) {
30
+ const tile = lookup[i]
31
+
32
+ if (tile) {
33
+ const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty)
34
+
35
+ const dx = tile.tx << tileShift
36
+ const dy = tile.ty << tileShift
37
+
38
+ SCRATCH_OPTS.x = dx
39
+ SCRATCH_OPTS.y = dy
40
+ SCRATCH_OPTS.w = tile.w
41
+ SCRATCH_OPTS.h = tile.h
42
+
43
+ didChange(
44
+ blendPixelDataFn(
45
+ config.target,
46
+ tile,
47
+ SCRATCH_OPTS,
48
+ ),
49
+ )
50
+ }
51
+ }
52
+
53
+ paintBuffer.clear()
54
+ }
55
+
@@ -0,0 +1,78 @@
1
+ import { type Color32 } from '../../_types'
2
+ import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
3
+ import type { PixelAccumulator } from '../../History/PixelAccumulator'
4
+ import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
5
+ import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
6
+ import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
7
+ import type { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
8
+
9
+ const SCRATCH_OPTS = {
10
+ alpha: 255,
11
+ blendFn: sourceOverPerfect,
12
+ x: 0,
13
+ y: 0,
14
+ w: 0,
15
+ h: 0,
16
+ }
17
+
18
+ export function commitMaskPaintBuffer(
19
+ accumulator: PixelAccumulator,
20
+ paintBuffer: BinaryMaskPaintBuffer,
21
+ color: Color32,
22
+ alpha: number | undefined,
23
+ blendFn: typeof sourceOverPerfect | undefined,
24
+ blendColorPixelDataMaskFn: typeof blendColorPixelDataBinaryMask,
25
+ ): void
26
+
27
+ export function commitMaskPaintBuffer(
28
+ accumulator: PixelAccumulator,
29
+ paintBuffer: AlphaMaskPaintBuffer,
30
+ color: Color32,
31
+ alpha: number | undefined,
32
+ blendFn: typeof sourceOverPerfect | undefined,
33
+ blendColorPixelDataMaskFn: typeof blendColorPixelDataAlphaMask,
34
+ ): void
35
+
36
+ export function commitMaskPaintBuffer(
37
+ accumulator: PixelAccumulator,
38
+ paintBuffer: any,
39
+ color: Color32,
40
+ alpha = 255,
41
+ blendFn = sourceOverPerfect,
42
+ blendColorPixelDataMaskFn: any,
43
+ ) {
44
+ const config = accumulator.config
45
+ const tileShift = config.tileShift
46
+ const lookup = paintBuffer.lookup
47
+
48
+ SCRATCH_OPTS.alpha = alpha
49
+ SCRATCH_OPTS.blendFn = blendFn
50
+
51
+ for (let i = 0; i < lookup.length; i++) {
52
+ const tile = lookup[i]
53
+
54
+ if (tile) {
55
+ const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty)
56
+
57
+ const dx = tile.tx << tileShift
58
+ const dy = tile.ty << tileShift
59
+
60
+ SCRATCH_OPTS.x = dx
61
+ SCRATCH_OPTS.y = dy
62
+ SCRATCH_OPTS.w = tile.w
63
+ SCRATCH_OPTS.h = tile.h
64
+
65
+ didChange(
66
+ blendColorPixelDataMaskFn(
67
+ config.target,
68
+ color,
69
+ tile,
70
+ SCRATCH_OPTS,
71
+ ),
72
+ )
73
+ }
74
+ }
75
+
76
+ paintBuffer.clear()
77
+ }
78
+
@@ -0,0 +1,78 @@
1
+ import type { Color32 } from '../../_types'
2
+ import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
3
+ import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
4
+ import { CANVAS_CTX_FAILED } from '../../Internal/_errors'
5
+ import { makePixelData } from '../../PixelData/PixelData'
6
+ import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
7
+
8
+ export type AlphaMaskPaintBufferCanvasRenderer = ReturnType<typeof makeAlphaMaskPaintBufferCanvasRenderer>
9
+
10
+ export function makeAlphaMaskPaintBufferCanvasRenderer(
11
+ paintBuffer: AlphaMaskPaintBuffer,
12
+ canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
13
+ ) {
14
+ const config = paintBuffer.config
15
+ const tileSize = config.tileSize
16
+ const tileShift = config.tileShift
17
+ const tileArea = config.tileArea
18
+ const lookup = paintBuffer.lookup
19
+
20
+ const canvas = canvasFactory(tileSize, tileSize)
21
+ const ctx = canvas.getContext('2d')
22
+ if (!ctx) throw new Error(CANVAS_CTX_FAILED)
23
+ ctx.imageSmoothingEnabled = false
24
+
25
+ const bridge = makePixelData(new ImageData(tileSize, tileSize))
26
+ const view32 = bridge.data
27
+
28
+ return function drawPaintBuffer(
29
+ targetCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
30
+ color: Color32,
31
+ alpha = 255,
32
+ compOperation: GlobalCompositeOperation = 'source-over',
33
+ ): void {
34
+ if (alpha === 0) return
35
+
36
+ const baseSrcAlpha = (color >>> 24)
37
+ const colorRGB = color & 0x00ffffff
38
+
39
+ if (baseSrcAlpha === 0) return
40
+
41
+ targetCtx.globalAlpha = alpha / 255
42
+ targetCtx.globalCompositeOperation = compOperation
43
+
44
+ for (let i = 0; i < lookup.length; i++) {
45
+ const tile = lookup[i]
46
+
47
+ if (tile) {
48
+ const data8 = tile.data
49
+ view32.fill(0)
50
+
51
+ for (let p = 0; p < tileArea; p++) {
52
+ const maskA = data8[p]
53
+ if (maskA === 0) continue
54
+
55
+ // If mask is solid, the final pixel is just the unmodified color
56
+ if (maskA === 255) {
57
+ view32[p] = color
58
+ } else {
59
+ // Otherwise, blend the color's inherent alpha with the mask's alpha
60
+ const t = baseSrcAlpha * maskA + 128
61
+ const finalA = (t + (t >> 8)) >> 8
62
+
63
+ view32[p] = ((colorRGB | (finalA << 24)) >>> 0) as Color32
64
+ }
65
+ }
66
+
67
+ const dx = tile.tx << tileShift
68
+ const dy = tile.ty << tileShift
69
+
70
+ ctx.putImageData(bridge.imageData, 0, 0)
71
+ targetCtx.drawImage(canvas, dx, dy)
72
+ }
73
+ }
74
+
75
+ targetCtx.globalAlpha = 1
76
+ targetCtx.globalCompositeOperation = 'source-over'
77
+ }
78
+ }