pixel-data-js 0.25.2 → 0.27.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/dist/index.prod.cjs +1696 -1526
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +414 -311
- package/dist/index.prod.js +1676 -1519
- package/dist/index.prod.js.map +1 -1
- package/package.json +8 -9
- package/src/Algorithm/floodFillSelection.ts +49 -80
- package/src/Canvas/PixelCanvas.ts +1 -1
- package/src/Canvas/ReusableCanvas.ts +1 -1
- package/src/History/HistoryAction.ts +6 -5
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyMask.ts +39 -0
- package/src/History/PixelMutator/{mutatorBlendPixelDataAlphaMask.ts → mutatorBlendAlphaMask.ts} +9 -9
- package/src/History/PixelMutator/{mutatorBlendPixelDataBinaryMask.ts → mutatorBlendBinaryMask.ts} +9 -9
- package/src/History/PixelMutator/mutatorBlendColor.ts +8 -9
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +51 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +51 -0
- package/src/History/PixelMutator/{mutatorBlendPaintMask.ts → mutatorBlendColorPaintMask.ts} +3 -3
- package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +55 -0
- package/src/History/PixelMutator/mutatorBlendMask.ts +43 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +8 -9
- package/src/History/PixelMutator/mutatorClear.ts +13 -11
- package/src/History/PixelMutator/mutatorFill.ts +2 -2
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +3 -4
- package/src/History/PixelMutator/mutatorInvert.ts +8 -9
- package/src/History/PixelMutator.ts +20 -4
- package/src/History/PixelWriter.ts +11 -13
- package/src/Input/fileToImageData.ts +1 -1
- package/src/Internal/helpers.ts +4 -1
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +8 -10
- package/src/Paint/PaintBuffer.ts +3 -3
- package/src/Paint/PaintBufferCanvasRenderer.ts +1 -1
- package/src/Paint/makePaintMask.ts +5 -5
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +3 -3
- package/src/PixelData/applyAlphaMaskToPixelData.ts +14 -16
- package/src/PixelData/applyBinaryMaskToPixelData.ts +14 -16
- package/src/PixelData/applyMaskToPixelData.ts +22 -0
- package/src/PixelData/blendColorPixelData.ts +12 -15
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataMask.ts +16 -0
- package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintMask.ts +35 -0
- package/src/PixelData/blendPixelData.ts +14 -16
- package/src/PixelData/blendPixelDataAlphaMask.ts +17 -19
- package/src/PixelData/blendPixelDataBinaryMask.ts +17 -19
- package/src/PixelData/blendPixelDataMask.ts +16 -0
- package/src/PixelData/blendPixelDataPaintBuffer.ts +1 -1
- package/src/PixelData/{clearPixelData.ts → clearPixelDataFast.ts} +2 -2
- package/src/PixelData/fillPixelDataBinaryMask.ts +8 -22
- package/src/PixelData/fillPixelDataFast.ts +2 -2
- package/src/PixelData/invertPixelData.ts +13 -16
- package/src/_types.ts +8 -7
- package/src/index.ts +41 -31
- package/dist/index.dev.cjs +0 -5419
- package/dist/index.dev.cjs.map +0 -1
- package/dist/index.dev.js +0 -5208
- package/dist/index.dev.js.map +0 -1
- package/src/Canvas/_constants.ts +0 -2
- package/src/PixelData/PixelBuffer32.ts +0 -28
|
@@ -8,27 +8,27 @@ import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
|
8
8
|
* If the width (`w`) or height (`h`) are omitted from the options, they will safely
|
|
9
9
|
* default to the dimensions of the provided mask to prevent out-of-bounds memory access.
|
|
10
10
|
*
|
|
11
|
-
* @param
|
|
11
|
+
* @param target - The destination {@link IPixelData32} buffer to modify.
|
|
12
12
|
* @param color - The solid color to apply.
|
|
13
13
|
* @param mask - The mask defining the per-pixel opacity of the target area.
|
|
14
14
|
* @param opts - Configuration options including placement coordinates, bounds, global alpha, and mask offsets.
|
|
15
15
|
* @returns true if any pixels were actually modified.
|
|
16
16
|
*/
|
|
17
17
|
export function blendColorPixelDataAlphaMask(
|
|
18
|
-
|
|
18
|
+
target: IPixelData32,
|
|
19
19
|
color: Color32,
|
|
20
20
|
mask: AlphaMask,
|
|
21
|
-
opts
|
|
21
|
+
opts?: ColorBlendMaskOptions,
|
|
22
22
|
): boolean {
|
|
23
|
-
const targetX = opts
|
|
24
|
-
const targetY = opts
|
|
25
|
-
const w = opts
|
|
26
|
-
const h = opts
|
|
27
|
-
const globalAlpha = opts
|
|
28
|
-
const blendFn = opts
|
|
29
|
-
const mx = opts
|
|
30
|
-
const my = opts
|
|
31
|
-
const invertMask = opts
|
|
23
|
+
const targetX = opts?.x ?? 0
|
|
24
|
+
const targetY = opts?.y ?? 0
|
|
25
|
+
const w = opts?.w ?? mask.w
|
|
26
|
+
const h = opts?.h ?? mask.h
|
|
27
|
+
const globalAlpha = opts?.alpha ?? 255
|
|
28
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect
|
|
29
|
+
const mx = opts?.mx ?? 0
|
|
30
|
+
const my = opts?.my ?? 0
|
|
31
|
+
const invertMask = opts?.invertMask ?? false
|
|
32
32
|
|
|
33
33
|
if (globalAlpha === 0) return false
|
|
34
34
|
|
|
@@ -52,16 +52,16 @@ export function blendColorPixelDataAlphaMask(
|
|
|
52
52
|
y = 0
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
actualW = Math.min(actualW,
|
|
56
|
-
actualH = Math.min(actualH,
|
|
55
|
+
actualW = Math.min(actualW, target.width - x)
|
|
56
|
+
actualH = Math.min(actualH, target.height - y)
|
|
57
57
|
|
|
58
58
|
if (actualW <= 0 || actualH <= 0) return false
|
|
59
59
|
|
|
60
60
|
const dx = (x - targetX) | 0
|
|
61
61
|
const dy = (y - targetY) | 0
|
|
62
62
|
|
|
63
|
-
const dst32 =
|
|
64
|
-
const dw =
|
|
63
|
+
const dst32 = target.data32
|
|
64
|
+
const dw = target.width
|
|
65
65
|
const mPitch = mask.w
|
|
66
66
|
const maskData = mask.data
|
|
67
67
|
|
|
@@ -8,27 +8,27 @@ import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
|
8
8
|
* If the width (`w`) or height (`h`) are omitted from the options, they will safely
|
|
9
9
|
* default to the dimensions of the provided mask to prevent out-of-bounds memory access.
|
|
10
10
|
*
|
|
11
|
-
* @param
|
|
11
|
+
* @param target - The destination {@link IPixelData32} buffer to modify.
|
|
12
12
|
* @param color - The solid color to apply.
|
|
13
13
|
* @param mask - The mask defining the per-pixel opacity of the target area.
|
|
14
14
|
* @param opts - Configuration options including placement coordinates, bounds, global alpha, and mask offsets.
|
|
15
15
|
* @returns true if any pixels were actually modified.
|
|
16
16
|
*/
|
|
17
17
|
export function blendColorPixelDataBinaryMask(
|
|
18
|
-
|
|
18
|
+
target: IPixelData32,
|
|
19
19
|
color: Color32,
|
|
20
20
|
mask: BinaryMask,
|
|
21
|
-
opts
|
|
21
|
+
opts?: ColorBlendMaskOptions,
|
|
22
22
|
): boolean {
|
|
23
|
-
const targetX = opts
|
|
24
|
-
const targetY = opts
|
|
25
|
-
let w = opts
|
|
26
|
-
let h = opts
|
|
27
|
-
const globalAlpha = opts
|
|
28
|
-
const blendFn = opts
|
|
29
|
-
const mx = opts
|
|
30
|
-
const my = opts
|
|
31
|
-
const invertMask = opts
|
|
23
|
+
const targetX = opts?.x ?? 0
|
|
24
|
+
const targetY = opts?.y ?? 0
|
|
25
|
+
let w = opts?.w ?? mask.w
|
|
26
|
+
let h = opts?.h ?? mask.h
|
|
27
|
+
const globalAlpha = opts?.alpha ?? 255
|
|
28
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect
|
|
29
|
+
const mx = opts?.mx ?? 0
|
|
30
|
+
const my = opts?.my ?? 0
|
|
31
|
+
const invertMask = opts?.invertMask ?? false
|
|
32
32
|
|
|
33
33
|
if (globalAlpha === 0) return false
|
|
34
34
|
|
|
@@ -50,8 +50,8 @@ export function blendColorPixelDataBinaryMask(
|
|
|
50
50
|
y = 0
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const actualW = Math.min(w,
|
|
54
|
-
const actualH = Math.min(h,
|
|
53
|
+
const actualW = Math.min(w, target.width - x)
|
|
54
|
+
const actualH = Math.min(h, target.height - y)
|
|
55
55
|
|
|
56
56
|
if (actualW <= 0 || actualH <= 0) return false
|
|
57
57
|
|
|
@@ -65,8 +65,8 @@ export function blendColorPixelDataBinaryMask(
|
|
|
65
65
|
|
|
66
66
|
const dx = (x - targetX) | 0
|
|
67
67
|
const dy = (y - targetY) | 0
|
|
68
|
-
const dst32 =
|
|
69
|
-
const dw =
|
|
68
|
+
const dst32 = target.data32
|
|
69
|
+
const dw = target.width
|
|
70
70
|
const mPitch = mask.w
|
|
71
71
|
const maskData = mask.data
|
|
72
72
|
let dIdx = (y * dw + x) | 0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Color32, type ColorBlendMaskOptions, type IPixelData32, type Mask, MaskType } from '../_types'
|
|
2
|
+
import { blendColorPixelDataAlphaMask } from './blendColorPixelDataAlphaMask'
|
|
3
|
+
import { blendColorPixelDataBinaryMask } from './blendColorPixelDataBinaryMask'
|
|
4
|
+
|
|
5
|
+
export function blendColorPixelDataMask(
|
|
6
|
+
dst: IPixelData32,
|
|
7
|
+
color: Color32,
|
|
8
|
+
mask: Mask,
|
|
9
|
+
opts?: ColorBlendMaskOptions,
|
|
10
|
+
): boolean {
|
|
11
|
+
if (mask.type === MaskType.BINARY) {
|
|
12
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, opts)
|
|
13
|
+
} else {
|
|
14
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, opts)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Color32, type IPixelData32, type PaintAlphaMask } from '../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
|
+
import { blendColorPixelDataAlphaMask } from './blendColorPixelDataAlphaMask'
|
|
4
|
+
|
|
5
|
+
const SCRATCH_OPTS = {
|
|
6
|
+
x: 0,
|
|
7
|
+
y: 0,
|
|
8
|
+
alpha: 255,
|
|
9
|
+
blendFn: sourceOverPerfect,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function blendColorPixelDataPaintAlphaMask(
|
|
13
|
+
dst: IPixelData32,
|
|
14
|
+
color: Color32,
|
|
15
|
+
mask: PaintAlphaMask,
|
|
16
|
+
x: number,
|
|
17
|
+
y: number,
|
|
18
|
+
alpha = 255,
|
|
19
|
+
blendFn = sourceOverPerfect,
|
|
20
|
+
): boolean {
|
|
21
|
+
const tx = x + mask.centerOffsetX
|
|
22
|
+
const ty = y + mask.centerOffsetY
|
|
23
|
+
|
|
24
|
+
SCRATCH_OPTS.x = tx
|
|
25
|
+
SCRATCH_OPTS.y = ty
|
|
26
|
+
SCRATCH_OPTS.alpha = alpha
|
|
27
|
+
SCRATCH_OPTS.blendFn = blendFn
|
|
28
|
+
|
|
29
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS)
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Color32, type IPixelData32, type PaintBinaryMask } from '../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
|
+
import { blendColorPixelDataBinaryMask } from './blendColorPixelDataBinaryMask'
|
|
4
|
+
|
|
5
|
+
const SCRATCH_OPTS = {
|
|
6
|
+
x: 0,
|
|
7
|
+
y: 0,
|
|
8
|
+
alpha: 255,
|
|
9
|
+
blendFn: sourceOverPerfect,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function blendColorPixelDataPaintBinaryMask(
|
|
13
|
+
dst: IPixelData32,
|
|
14
|
+
color: Color32,
|
|
15
|
+
mask: PaintBinaryMask,
|
|
16
|
+
x: number,
|
|
17
|
+
y: number,
|
|
18
|
+
alpha = 255,
|
|
19
|
+
blendFn = sourceOverPerfect,
|
|
20
|
+
): boolean {
|
|
21
|
+
const tx = x + mask.centerOffsetX
|
|
22
|
+
const ty = y + mask.centerOffsetY
|
|
23
|
+
|
|
24
|
+
SCRATCH_OPTS.x = tx
|
|
25
|
+
SCRATCH_OPTS.y = ty
|
|
26
|
+
SCRATCH_OPTS.alpha = alpha
|
|
27
|
+
SCRATCH_OPTS.blendFn = blendFn
|
|
28
|
+
|
|
29
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS)
|
|
30
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Color32, type IPixelData32, MaskType, type PaintMask } from '../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
|
+
import { blendColorPixelDataAlphaMask } from './blendColorPixelDataAlphaMask'
|
|
4
|
+
import { blendColorPixelDataBinaryMask } from './blendColorPixelDataBinaryMask'
|
|
5
|
+
|
|
6
|
+
const SCRATCH_OPTS = {
|
|
7
|
+
x: 0,
|
|
8
|
+
y: 0,
|
|
9
|
+
alpha: 255,
|
|
10
|
+
blendFn: sourceOverPerfect,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function blendColorPixelDataPaintMask(
|
|
14
|
+
dst: IPixelData32,
|
|
15
|
+
color: Color32,
|
|
16
|
+
mask: PaintMask,
|
|
17
|
+
x: number,
|
|
18
|
+
y: number,
|
|
19
|
+
alpha = 255,
|
|
20
|
+
blendFn = sourceOverPerfect,
|
|
21
|
+
): boolean {
|
|
22
|
+
const tx = x + mask.centerOffsetX
|
|
23
|
+
const ty = y + mask.centerOffsetY
|
|
24
|
+
|
|
25
|
+
SCRATCH_OPTS.x = tx
|
|
26
|
+
SCRATCH_OPTS.y = ty
|
|
27
|
+
SCRATCH_OPTS.alpha = alpha
|
|
28
|
+
SCRATCH_OPTS.blendFn = blendFn
|
|
29
|
+
|
|
30
|
+
if (mask.type === MaskType.BINARY) {
|
|
31
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS)
|
|
32
|
+
} else {
|
|
33
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -16,20 +16,18 @@ import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
|
16
16
|
* });
|
|
17
17
|
*/
|
|
18
18
|
export function blendPixelData(
|
|
19
|
-
|
|
19
|
+
target: IPixelData32,
|
|
20
20
|
src: IPixelData32,
|
|
21
|
-
opts
|
|
21
|
+
opts?: PixelBlendOptions,
|
|
22
22
|
): boolean {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
blendFn = sourceOverPerfect,
|
|
32
|
-
} = opts
|
|
23
|
+
const targetX = opts?.x ?? 0
|
|
24
|
+
const targetY = opts?.y ?? 0
|
|
25
|
+
const sourceX = opts?.sx ?? 0
|
|
26
|
+
const sourceY = opts?.sy ?? 0
|
|
27
|
+
const width = opts?.w ?? src.width
|
|
28
|
+
const height = opts?.h ?? src.height
|
|
29
|
+
const globalAlpha = opts?.alpha ?? 255
|
|
30
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect
|
|
33
31
|
|
|
34
32
|
if (globalAlpha === 0) return false
|
|
35
33
|
|
|
@@ -63,13 +61,13 @@ export function blendPixelData(
|
|
|
63
61
|
y = 0
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
const actualW = Math.min(w,
|
|
67
|
-
const actualH = Math.min(h,
|
|
64
|
+
const actualW = Math.min(w, target.width - x)
|
|
65
|
+
const actualH = Math.min(h, target.height - y)
|
|
68
66
|
if (actualW <= 0 || actualH <= 0) return false
|
|
69
67
|
|
|
70
|
-
const dst32 =
|
|
68
|
+
const dst32 = target.data32
|
|
71
69
|
const src32 = src.data32
|
|
72
|
-
const dw =
|
|
70
|
+
const dw = target.width
|
|
73
71
|
const sw = src.width
|
|
74
72
|
|
|
75
73
|
let dIdx = (y * dw + x) | 0
|
|
@@ -2,24 +2,22 @@ import { type AlphaMask, type Color32, type IPixelData32, type PixelBlendMaskOpt
|
|
|
2
2
|
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
3
|
|
|
4
4
|
export function blendPixelDataAlphaMask(
|
|
5
|
-
|
|
5
|
+
target: IPixelData32,
|
|
6
6
|
src: IPixelData32,
|
|
7
7
|
alphaMask: AlphaMask,
|
|
8
|
-
opts
|
|
8
|
+
opts?: PixelBlendMaskOptions,
|
|
9
9
|
): boolean {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
invertMask = false,
|
|
22
|
-
} = opts
|
|
10
|
+
const targetX = opts?.x ?? 0
|
|
11
|
+
const targetY = opts?.y ?? 0
|
|
12
|
+
const sourceX = opts?.sx ?? 0
|
|
13
|
+
const sourceY = opts?.sy ?? 0
|
|
14
|
+
const width = opts?.w ?? src.width
|
|
15
|
+
const height = opts?.h ?? src.height
|
|
16
|
+
const globalAlpha = opts?.alpha ?? 255
|
|
17
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect
|
|
18
|
+
const mx = opts?.mx ?? 0
|
|
19
|
+
const my = opts?.my ?? 0
|
|
20
|
+
const invertMask = opts?.invertMask ?? false
|
|
23
21
|
|
|
24
22
|
if (globalAlpha === 0) return false
|
|
25
23
|
|
|
@@ -54,12 +52,12 @@ export function blendPixelDataAlphaMask(
|
|
|
54
52
|
y = 0
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
const actualW = Math.min(w,
|
|
58
|
-
const actualH = Math.min(h,
|
|
55
|
+
const actualW = Math.min(w, target.width - x)
|
|
56
|
+
const actualH = Math.min(h, target.height - y)
|
|
59
57
|
if (actualW <= 0 || actualH <= 0) return false
|
|
60
58
|
|
|
61
59
|
// 2. Index Setup
|
|
62
|
-
const dw =
|
|
60
|
+
const dw = target.width
|
|
63
61
|
const sw = src.width
|
|
64
62
|
const mPitch = alphaMask.w
|
|
65
63
|
const maskData = alphaMask.data
|
|
@@ -69,7 +67,7 @@ export function blendPixelDataAlphaMask(
|
|
|
69
67
|
const dx = (x - targetX) | 0
|
|
70
68
|
const dy = (y - targetY) | 0
|
|
71
69
|
|
|
72
|
-
const dst32 =
|
|
70
|
+
const dst32 = target.data32
|
|
73
71
|
const src32 = src.data32
|
|
74
72
|
|
|
75
73
|
let dIdx = (y * dw + x) | 0
|
|
@@ -2,24 +2,22 @@ import type { BinaryMask, Color32, IPixelData32, PixelBlendMaskOptions } from '.
|
|
|
2
2
|
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
3
|
|
|
4
4
|
export function blendPixelDataBinaryMask(
|
|
5
|
-
|
|
5
|
+
target: IPixelData32,
|
|
6
6
|
src: IPixelData32,
|
|
7
7
|
binaryMask: BinaryMask,
|
|
8
|
-
opts
|
|
8
|
+
opts?: PixelBlendMaskOptions,
|
|
9
9
|
): boolean {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
invertMask = false,
|
|
22
|
-
} = opts
|
|
10
|
+
const targetX = opts?.x ?? 0
|
|
11
|
+
const targetY = opts?.y ?? 0
|
|
12
|
+
const sourceX = opts?.sx ?? 0
|
|
13
|
+
const sourceY = opts?.sy ?? 0
|
|
14
|
+
const width = opts?.w ?? src.width
|
|
15
|
+
const height = opts?.h ?? src.height
|
|
16
|
+
const globalAlpha = opts?.alpha ?? 255
|
|
17
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect
|
|
18
|
+
const mx = opts?.mx ?? 0
|
|
19
|
+
const my = opts?.my ?? 0
|
|
20
|
+
const invertMask = opts?.invertMask ?? false
|
|
23
21
|
|
|
24
22
|
if (globalAlpha === 0) return false
|
|
25
23
|
|
|
@@ -56,8 +54,8 @@ export function blendPixelDataBinaryMask(
|
|
|
56
54
|
y = 0
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
const actualW = Math.min(w,
|
|
60
|
-
const actualH = Math.min(h,
|
|
57
|
+
const actualW = Math.min(w, target.width - x)
|
|
58
|
+
const actualH = Math.min(h, target.height - y)
|
|
61
59
|
|
|
62
60
|
if (actualW <= 0 || actualH <= 0) return false
|
|
63
61
|
|
|
@@ -67,9 +65,9 @@ export function blendPixelDataBinaryMask(
|
|
|
67
65
|
const dx = (x - targetX) | 0
|
|
68
66
|
const dy = (y - targetY) | 0
|
|
69
67
|
|
|
70
|
-
const dst32 =
|
|
68
|
+
const dst32 = target.data32
|
|
71
69
|
const src32 = src.data32
|
|
72
|
-
const dw =
|
|
70
|
+
const dw = target.width
|
|
73
71
|
const sw = src.width
|
|
74
72
|
const mPitch = binaryMask.w
|
|
75
73
|
const maskData = binaryMask.data
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type IPixelData32, type Mask, MaskType, type PixelBlendMaskOptions } from '../_types'
|
|
2
|
+
import { blendPixelDataAlphaMask } from './blendPixelDataAlphaMask'
|
|
3
|
+
import { blendPixelDataBinaryMask } from './blendPixelDataBinaryMask'
|
|
4
|
+
|
|
5
|
+
export function blendPixelDataMask(
|
|
6
|
+
target: IPixelData32,
|
|
7
|
+
src: IPixelData32,
|
|
8
|
+
mask: Mask,
|
|
9
|
+
opts?: PixelBlendMaskOptions,
|
|
10
|
+
): boolean {
|
|
11
|
+
if (mask.type === MaskType.BINARY) {
|
|
12
|
+
return blendPixelDataBinaryMask(target, src, mask, opts)
|
|
13
|
+
} else {
|
|
14
|
+
return blendPixelDataAlphaMask(target, src, mask, opts)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -3,9 +3,9 @@ import { fillPixelDataFast } from './fillPixelDataFast'
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Clears a region of the PixelData to transparent (0x00000000).
|
|
6
|
-
* Internally uses the optimized
|
|
6
|
+
* Internally uses the optimized fillPixelDataFast.
|
|
7
7
|
*/
|
|
8
|
-
export function
|
|
8
|
+
export function clearPixelDataFast(
|
|
9
9
|
dst: IPixelData32,
|
|
10
10
|
rect?: Partial<BinaryMaskRect>,
|
|
11
11
|
): void {
|
|
@@ -5,22 +5,19 @@ const SCRATCH_RECT = makeClippedRect()
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Fills a region of the {@link IPixelData32} buffer with a solid color using a mask.
|
|
8
|
-
* @param
|
|
8
|
+
* @param target - The target to modify.
|
|
9
9
|
* @param color - The color to apply.
|
|
10
10
|
* @param mask - The mask defining the area to fill.
|
|
11
|
-
* @param alpha - The overall opacity of the fill (0-255).
|
|
12
11
|
* @param x - Starting horizontal coordinate for the mask placement.
|
|
13
12
|
* @param y - Starting vertical coordinate for the mask placement.
|
|
14
13
|
*/
|
|
15
14
|
export function fillPixelDataBinaryMask(
|
|
16
|
-
|
|
15
|
+
target: IPixelData32,
|
|
17
16
|
color: Color32,
|
|
18
17
|
mask: BinaryMask,
|
|
19
|
-
alpha = 255,
|
|
20
18
|
x = 0,
|
|
21
19
|
y = 0,
|
|
22
20
|
): boolean {
|
|
23
|
-
if (alpha === 0) return false
|
|
24
21
|
|
|
25
22
|
const maskW = mask.w
|
|
26
23
|
const maskH = mask.h
|
|
@@ -30,8 +27,8 @@ export function fillPixelDataBinaryMask(
|
|
|
30
27
|
y,
|
|
31
28
|
maskW,
|
|
32
29
|
maskH,
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
target.width,
|
|
31
|
+
target.height,
|
|
35
32
|
SCRATCH_RECT,
|
|
36
33
|
)
|
|
37
34
|
|
|
@@ -45,19 +42,8 @@ export function fillPixelDataBinaryMask(
|
|
|
45
42
|
} = clip
|
|
46
43
|
|
|
47
44
|
const maskData = mask.data
|
|
48
|
-
const dst32 =
|
|
49
|
-
const dw =
|
|
50
|
-
|
|
51
|
-
// Pre-calculate the alpha-adjusted color once outside the loop
|
|
52
|
-
let finalCol = color
|
|
53
|
-
|
|
54
|
-
if (alpha < 255) {
|
|
55
|
-
const baseSrcAlpha = color >>> 24
|
|
56
|
-
const colorRGB = color & 0x00ffffff
|
|
57
|
-
const a = (baseSrcAlpha * alpha + 128) >> 8
|
|
58
|
-
|
|
59
|
-
finalCol = ((colorRGB | (a << 24)) >>> 0) as Color32
|
|
60
|
-
}
|
|
45
|
+
const dst32 = target.data32
|
|
46
|
+
const dw = target.width
|
|
61
47
|
|
|
62
48
|
let hasChanged = false
|
|
63
49
|
|
|
@@ -75,8 +61,8 @@ export function fillPixelDataBinaryMask(
|
|
|
75
61
|
|
|
76
62
|
if (maskData[maskIndex]) {
|
|
77
63
|
const current = dst32[dstRowOffset + currentX]
|
|
78
|
-
if (current !==
|
|
79
|
-
dst32[dstRowOffset + currentX] =
|
|
64
|
+
if (current !== color) {
|
|
65
|
+
dst32[dstRowOffset + currentX] = color
|
|
80
66
|
hasChanged = true
|
|
81
67
|
}
|
|
82
68
|
}
|
|
@@ -8,13 +8,13 @@ const SCRATCH_RECT = makeClippedRect()
|
|
|
8
8
|
* This function is faster than {@link fillPixelData} but does not
|
|
9
9
|
* return a boolean value indicating changes were made.
|
|
10
10
|
*
|
|
11
|
-
* @param
|
|
11
|
+
* @param target - The target to modify.
|
|
12
12
|
* @param color - The color to apply.
|
|
13
13
|
* @param rect - Defines the area to fill. If omitted, the entire
|
|
14
14
|
* buffer is filled.
|
|
15
15
|
*/
|
|
16
16
|
export function fillPixelDataFast(
|
|
17
|
-
|
|
17
|
+
target: IPixelData32,
|
|
18
18
|
color: Color32,
|
|
19
19
|
rect?: Partial<Rect>,
|
|
20
20
|
): void
|
|
@@ -4,22 +4,19 @@ import { makeClippedRect, resolveRectClipping } from '../Internal/resolveClippin
|
|
|
4
4
|
const SCRATCH_RECT = makeClippedRect()
|
|
5
5
|
|
|
6
6
|
export function invertPixelData(
|
|
7
|
-
|
|
8
|
-
opts
|
|
7
|
+
target: IPixelData32,
|
|
8
|
+
opts?: PixelMutateOptions,
|
|
9
9
|
): boolean {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
my = 0,
|
|
19
|
-
invertMask = false,
|
|
20
|
-
} = opts
|
|
10
|
+
const mask = opts?.mask
|
|
11
|
+
const targetX = opts?.x ?? 0
|
|
12
|
+
const targetY = opts?.y ?? 0
|
|
13
|
+
const mx = opts?.mx ?? 0
|
|
14
|
+
const my = opts?.my ?? 0
|
|
15
|
+
const width = opts?.w ?? target.width
|
|
16
|
+
const height = opts?.h ?? target.height
|
|
17
|
+
const invertMask = opts?.invertMask ?? false
|
|
21
18
|
|
|
22
|
-
const clip = resolveRectClipping(targetX, targetY, width, height,
|
|
19
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, target.width, target.height, SCRATCH_RECT)
|
|
23
20
|
|
|
24
21
|
if (!clip.inBounds) return false
|
|
25
22
|
|
|
@@ -30,8 +27,8 @@ export function invertPixelData(
|
|
|
30
27
|
h: actualH,
|
|
31
28
|
} = clip
|
|
32
29
|
|
|
33
|
-
const dst32 =
|
|
34
|
-
const dw =
|
|
30
|
+
const dst32 = target.data32
|
|
31
|
+
const dw = target.width
|
|
35
32
|
const mPitch = mask?.w ?? width
|
|
36
33
|
|
|
37
34
|
const dx = x - targetX
|
package/src/_types.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { PixelWriter, sourceOverPerfect } from './index'
|
|
2
|
-
|
|
3
1
|
/** ALL values are 0-255 (including alpha which in CSS is 0-1) */
|
|
4
2
|
export type RGBA = { r: number, g: number, b: number, a: number }
|
|
5
3
|
|
|
@@ -63,20 +61,22 @@ export enum MaskType {
|
|
|
63
61
|
BINARY
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
export interface
|
|
64
|
+
export interface BaseMask {
|
|
67
65
|
readonly type: MaskType
|
|
68
66
|
readonly data: Uint8Array
|
|
69
67
|
readonly w: number
|
|
70
68
|
readonly h: number
|
|
71
69
|
}
|
|
72
70
|
|
|
71
|
+
export type Mask = BinaryMask | AlphaMask
|
|
72
|
+
|
|
73
73
|
/** Strictly 0 or 1 */
|
|
74
|
-
export interface BinaryMask extends
|
|
74
|
+
export interface BinaryMask extends BaseMask {
|
|
75
75
|
readonly type: MaskType.BINARY
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/** Strictly 0-255 */
|
|
79
|
-
export interface AlphaMask extends
|
|
79
|
+
export interface AlphaMask extends BaseMask {
|
|
80
80
|
readonly type: MaskType.ALPHA
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -210,6 +210,9 @@ export interface ColorBlendOptions extends PixelRect, Alpha {
|
|
|
210
210
|
export interface ColorBlendMaskOptions extends ColorBlendOptions, MaskOffset, InvertMask {
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
export interface ColorBlendPaintMaskOptions extends Omit<ColorBlendOptions, 'w' | 'h'> {
|
|
214
|
+
}
|
|
215
|
+
|
|
213
216
|
export type MaskRect<T extends MaskType> = Rect & {
|
|
214
217
|
type: T
|
|
215
218
|
data: Uint8Array
|
|
@@ -235,8 +238,6 @@ export type NullableMaskRect = Rect & ({
|
|
|
235
238
|
data?: null
|
|
236
239
|
})
|
|
237
240
|
|
|
238
|
-
export type HistoryMutator<T extends {}, D extends {}> = (writer: PixelWriter<any>, deps?: Partial<D>) => T
|
|
239
|
-
|
|
240
241
|
export interface IPixelData32 {
|
|
241
242
|
readonly data32: Uint32Array
|
|
242
243
|
readonly width: number
|