pixel-data-js 0.23.1 → 0.25.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.dev.cjs +1816 -1802
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1799 -1786
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1816 -1802
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +349 -342
- package/dist/index.prod.js +1799 -1786
- package/dist/index.prod.js.map +1 -1
- package/package.json +3 -2
- package/src/Algorithm/floodFillSelection.ts +2 -2
- package/src/Canvas/CanvasFrameRenderer.ts +57 -0
- package/src/Canvas/ReusableCanvas.ts +60 -11
- package/src/Canvas/canvas-blend-modes.ts +28 -0
- package/src/History/HistoryAction.ts +38 -0
- package/src/History/HistoryManager.ts +4 -8
- package/src/History/PixelAccumulator.ts +137 -99
- package/src/History/PixelEngineConfig.ts +16 -6
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +6 -6
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +6 -6
- package/src/History/PixelMutator/mutatorBlendColor.ts +8 -5
- package/src/History/PixelMutator/mutatorBlendPixel.ts +22 -26
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +7 -5
- package/src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts +7 -5
- package/src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts +7 -5
- package/src/History/PixelMutator/mutatorClear.ts +6 -5
- package/src/History/PixelMutator/mutatorFill.ts +34 -9
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +4 -2
- package/src/History/PixelMutator/mutatorInvert.ts +8 -4
- package/src/History/PixelMutator.ts +2 -21
- package/src/History/PixelPatchTiles.ts +4 -16
- package/src/History/PixelWriter.ts +150 -31
- package/src/ImageData/ReusableImageData.ts +3 -5
- package/src/Internal/helpers.ts +2 -0
- package/src/Paint/PaintBuffer.ts +269 -0
- package/src/Paint/PaintBufferCanvasRenderer.ts +48 -0
- package/src/Paint/makeCirclePaintAlphaMask.ts +41 -0
- package/src/{Mask/CircleBrushBinaryMask.ts → Paint/makeCirclePaintBinaryMask.ts} +5 -6
- package/src/Paint/makePaintMask.ts +28 -0
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +47 -0
- package/src/PixelData/PixelBuffer32.ts +2 -2
- package/src/PixelData/PixelData.ts +2 -28
- package/src/PixelData/applyAlphaMaskToPixelData.ts +20 -10
- package/src/PixelData/applyBinaryMaskToPixelData.ts +26 -19
- package/src/PixelData/blendColorPixelData.ts +33 -9
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +19 -9
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +19 -10
- package/src/PixelData/blendPixel.ts +47 -0
- package/src/PixelData/blendPixelData.ts +17 -7
- package/src/PixelData/blendPixelDataAlphaMask.ts +15 -7
- package/src/PixelData/blendPixelDataBinaryMask.ts +16 -7
- package/src/PixelData/blendPixelDataPaintBuffer.ts +37 -0
- package/src/PixelData/clearPixelData.ts +4 -4
- package/src/PixelData/extractPixelData.ts +4 -4
- package/src/PixelData/extractPixelDataBuffer.ts +4 -4
- package/src/PixelData/fillPixelData.ts +31 -21
- package/src/PixelData/fillPixelDataBinaryMask.ts +15 -7
- package/src/PixelData/fillPixelDataFast.ts +94 -0
- package/src/PixelData/invertPixelData.ts +6 -4
- package/src/PixelData/pixelDataToAlphaMask.ts +2 -2
- package/src/PixelData/reflectPixelData.ts +3 -3
- package/src/PixelData/resamplePixelData.ts +2 -2
- package/src/PixelData/writePaintBufferToPixelData.ts +26 -0
- package/src/PixelData/writePixelDataBuffer.ts +5 -5
- package/src/PixelTile/PixelTile.ts +21 -0
- package/src/PixelTile/PixelTilePool.ts +63 -0
- package/src/Rect/trimMaskRectBounds.ts +121 -0
- package/src/Rect/trimRectBounds.ts +25 -116
- package/src/_types.ts +17 -16
- package/src/index.ts +19 -24
- package/src/History/PixelMutator/mutatorApplyCircleBrush.ts +0 -78
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +0 -181
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +0 -59
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +0 -171
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +0 -64
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +0 -182
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +0 -65
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +0 -164
- package/src/Mask/CircleBrushAlphaMask.ts +0 -32
- package/src/PixelData/applyCircleBrushToPixelData.ts +0 -91
- package/src/PixelData/applyRectBrushToPixelData.ts +0 -85
- package/src/Rect/getCircleBrushOrPencilBounds.ts +0 -43
- package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +0 -24
- package/src/Rect/getRectBrushOrPencilBounds.ts +0 -38
- package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +0 -26
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type BlendColor32,
|
|
3
|
-
type CircleBrushMask,
|
|
4
|
-
type Color32,
|
|
5
|
-
type ColorBlendMaskOptions,
|
|
6
|
-
type IPixelData,
|
|
7
|
-
MaskType,
|
|
8
|
-
type Rect,
|
|
9
|
-
} from '../_types'
|
|
10
|
-
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
11
|
-
import { getCircleBrushOrPencilBounds } from '../Rect/getCircleBrushOrPencilBounds'
|
|
12
|
-
import { blendColorPixelDataAlphaMask } from './blendColorPixelDataAlphaMask'
|
|
13
|
-
import { blendColorPixelDataBinaryMask } from './blendColorPixelDataBinaryMask'
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Applies a circular brush to pixel data using a pre-calculated alpha mask.
|
|
17
|
-
*
|
|
18
|
-
* @param target The PixelData to modify.
|
|
19
|
-
* @param color The brush color.
|
|
20
|
-
* @param centerX The center x-coordinate of the brush.
|
|
21
|
-
* @param centerY The center y-coordinate of the brush.
|
|
22
|
-
* @param brush The pre-calculated CircleBrushAlphaMask.
|
|
23
|
-
* @param alpha The overall opacity of the brush (0-255).
|
|
24
|
-
* @param blendFn
|
|
25
|
-
* @param scratchOptions
|
|
26
|
-
* @param bounds precalculated result from {@link getCircleBrushOrPencilBounds}
|
|
27
|
-
*/
|
|
28
|
-
export function applyCircleBrushToPixelData(
|
|
29
|
-
target: IPixelData,
|
|
30
|
-
color: Color32,
|
|
31
|
-
centerX: number,
|
|
32
|
-
centerY: number,
|
|
33
|
-
brush: CircleBrushMask,
|
|
34
|
-
alpha = 255,
|
|
35
|
-
blendFn: BlendColor32 = sourceOverPerfect,
|
|
36
|
-
scratchOptions: ColorBlendMaskOptions = {},
|
|
37
|
-
bounds?: Rect,
|
|
38
|
-
): void {
|
|
39
|
-
const b = bounds ?? getCircleBrushOrPencilBounds(
|
|
40
|
-
centerX,
|
|
41
|
-
centerY,
|
|
42
|
-
brush.size,
|
|
43
|
-
target.width,
|
|
44
|
-
target.height,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
if (b.w <= 0 || b.h <= 0) return
|
|
48
|
-
|
|
49
|
-
const unclippedStartX = Math.floor(centerX + brush.minOffset)
|
|
50
|
-
const unclippedStartY = Math.floor(centerY + brush.minOffset)
|
|
51
|
-
|
|
52
|
-
// Calculate the intersection between the unclipped mask rect and the allowed bounds
|
|
53
|
-
const ix = Math.max(unclippedStartX, b.x)
|
|
54
|
-
const iy = Math.max(unclippedStartY, b.y)
|
|
55
|
-
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w)
|
|
56
|
-
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h)
|
|
57
|
-
|
|
58
|
-
const iw = ir - ix
|
|
59
|
-
const ih = ib - iy
|
|
60
|
-
|
|
61
|
-
// If the mask falls entirely outside the bounds, exit
|
|
62
|
-
if (iw <= 0 || ih <= 0) return
|
|
63
|
-
|
|
64
|
-
// Apply the intersected coordinates and internal mask offsets
|
|
65
|
-
scratchOptions.x = ix
|
|
66
|
-
scratchOptions.y = iy
|
|
67
|
-
scratchOptions.w = iw
|
|
68
|
-
scratchOptions.h = ih
|
|
69
|
-
scratchOptions.mx = ix - unclippedStartX
|
|
70
|
-
scratchOptions.my = iy - unclippedStartY
|
|
71
|
-
scratchOptions.alpha = alpha
|
|
72
|
-
scratchOptions.blendFn = blendFn
|
|
73
|
-
|
|
74
|
-
if (brush.type === MaskType.ALPHA) {
|
|
75
|
-
blendColorPixelDataAlphaMask(
|
|
76
|
-
target,
|
|
77
|
-
color,
|
|
78
|
-
brush,
|
|
79
|
-
scratchOptions,
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (brush.type === MaskType.BINARY) {
|
|
84
|
-
blendColorPixelDataBinaryMask(
|
|
85
|
-
target,
|
|
86
|
-
color,
|
|
87
|
-
brush,
|
|
88
|
-
scratchOptions,
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import type { BlendColor32, Color32, IPixelData, Rect } from '../_types'
|
|
2
|
-
import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
|
|
3
|
-
import { getRectBrushOrPencilBounds } from '../Rect/getRectBrushOrPencilBounds'
|
|
4
|
-
|
|
5
|
-
export function applyRectBrushToPixelData(
|
|
6
|
-
target: IPixelData,
|
|
7
|
-
color: Color32,
|
|
8
|
-
centerX: number,
|
|
9
|
-
centerY: number,
|
|
10
|
-
brushWidth: number,
|
|
11
|
-
brushHeight: number,
|
|
12
|
-
alpha = 255,
|
|
13
|
-
fallOff: (dist: number) => number,
|
|
14
|
-
blendFn: BlendColor32 = sourceOverPerfect,
|
|
15
|
-
bounds?: Rect,
|
|
16
|
-
): void {
|
|
17
|
-
const targetWidth = target.width
|
|
18
|
-
const targetHeight = target.height
|
|
19
|
-
|
|
20
|
-
const b = bounds ?? getRectBrushOrPencilBounds(
|
|
21
|
-
centerX,
|
|
22
|
-
centerY,
|
|
23
|
-
brushWidth,
|
|
24
|
-
brushHeight,
|
|
25
|
-
targetWidth,
|
|
26
|
-
targetHeight,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
if (b.w <= 0 || b.h <= 0) return
|
|
30
|
-
|
|
31
|
-
const data32 = target.data32
|
|
32
|
-
const baseColor = color & 0x00ffffff
|
|
33
|
-
const baseSrcAlpha = color >>> 24
|
|
34
|
-
const isOpaque = alpha === 255
|
|
35
|
-
|
|
36
|
-
const invHalfW = 1 / (brushWidth / 2)
|
|
37
|
-
const invHalfH = 1 / (brushHeight / 2)
|
|
38
|
-
|
|
39
|
-
// Restore the pixel-art centering logic
|
|
40
|
-
const centerOffsetX = (brushWidth % 2 === 0) ? 0.5 : 0
|
|
41
|
-
const centerOffsetY = (brushHeight % 2 === 0) ? 0.5 : 0
|
|
42
|
-
const fCenterX = Math.floor(centerX)
|
|
43
|
-
const fCenterY = Math.floor(centerY)
|
|
44
|
-
|
|
45
|
-
const endX = b.x + b.w
|
|
46
|
-
const endY = b.y + b.h
|
|
47
|
-
const isOverwrite = (blendFn as any).isOverwrite
|
|
48
|
-
|
|
49
|
-
for (let py = b.y; py < endY; py++) {
|
|
50
|
-
const rowOffset = py * targetWidth
|
|
51
|
-
const dy = Math.abs((py - fCenterY) + centerOffsetY) * invHalfH
|
|
52
|
-
|
|
53
|
-
for (let px = b.x; px < endX; px++) {
|
|
54
|
-
const idx = rowOffset + px
|
|
55
|
-
|
|
56
|
-
const dx = Math.abs((px - fCenterX) + centerOffsetX) * invHalfW
|
|
57
|
-
const dist = dx > dy ? dx : dy
|
|
58
|
-
|
|
59
|
-
const strength = fallOff(dist)
|
|
60
|
-
const maskVal = (strength * 255) | 0
|
|
61
|
-
|
|
62
|
-
if (maskVal <= 0) continue
|
|
63
|
-
|
|
64
|
-
let weight = alpha
|
|
65
|
-
|
|
66
|
-
if (isOpaque) {
|
|
67
|
-
weight = maskVal
|
|
68
|
-
} else if (maskVal !== 255) {
|
|
69
|
-
weight = (maskVal * alpha + 128) >> 8
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let finalCol = color
|
|
73
|
-
|
|
74
|
-
if (weight < 255) {
|
|
75
|
-
const a = (baseSrcAlpha * weight + 128) >> 8
|
|
76
|
-
|
|
77
|
-
if (a === 0 && !isOverwrite) continue
|
|
78
|
-
|
|
79
|
-
finalCol = ((a << 24) | baseColor) >>> 0 as Color32
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
data32[idx] = blendFn(finalCol, data32[idx] as Color32)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { Rect } from '../_types'
|
|
2
|
-
|
|
3
|
-
export function getCircleBrushOrPencilBounds(
|
|
4
|
-
centerX: number,
|
|
5
|
-
centerY: number,
|
|
6
|
-
brushSize: number,
|
|
7
|
-
targetWidth: number,
|
|
8
|
-
targetHeight: number,
|
|
9
|
-
out?: Rect,
|
|
10
|
-
): Rect {
|
|
11
|
-
const r = brushSize / 2
|
|
12
|
-
|
|
13
|
-
const minOffset = -Math.ceil(r - 0.5)
|
|
14
|
-
const maxOffset = Math.floor(r - 0.5)
|
|
15
|
-
|
|
16
|
-
// start is inclusive, end is exclusive
|
|
17
|
-
const startX = Math.floor(centerX + minOffset)
|
|
18
|
-
const startY = Math.floor(centerY + minOffset)
|
|
19
|
-
const endX = Math.floor(centerX + maxOffset) + 1
|
|
20
|
-
const endY = Math.floor(centerY + maxOffset) + 1
|
|
21
|
-
|
|
22
|
-
const res = out ?? {
|
|
23
|
-
x: 0,
|
|
24
|
-
y: 0,
|
|
25
|
-
w: 0,
|
|
26
|
-
h: 0,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const cStartX = Math.max(0, startX)
|
|
30
|
-
const cStartY = Math.max(0, startY)
|
|
31
|
-
const cEndX = Math.min(targetWidth, endX)
|
|
32
|
-
const cEndY = Math.min(targetHeight, endY)
|
|
33
|
-
|
|
34
|
-
const w = cEndX - cStartX
|
|
35
|
-
const h = cEndY - cStartY
|
|
36
|
-
|
|
37
|
-
res.x = cStartX
|
|
38
|
-
res.y = cStartY
|
|
39
|
-
res.w = w < 0 ? 0 : w
|
|
40
|
-
res.h = h < 0 ? 0 : h
|
|
41
|
-
|
|
42
|
-
return res
|
|
43
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Rect } from '../_types'
|
|
2
|
-
|
|
3
|
-
export function getCircleBrushOrPencilStrokeBounds(
|
|
4
|
-
x0: number,
|
|
5
|
-
y0: number,
|
|
6
|
-
x1: number,
|
|
7
|
-
y1: number,
|
|
8
|
-
brushSize: number,
|
|
9
|
-
result: Rect,
|
|
10
|
-
): Rect {
|
|
11
|
-
const r = Math.ceil(brushSize / 2)
|
|
12
|
-
|
|
13
|
-
const minX = Math.min(x0, x1) - r
|
|
14
|
-
const minY = Math.min(y0, y1) - r
|
|
15
|
-
const maxX = Math.max(x0, x1) + r
|
|
16
|
-
const maxY = Math.max(x0, y1) + r
|
|
17
|
-
|
|
18
|
-
result.x = Math.floor(minX)
|
|
19
|
-
result.y = Math.floor(minY)
|
|
20
|
-
result.w = Math.ceil(maxX - minX)
|
|
21
|
-
result.h = Math.ceil(maxY - minY)
|
|
22
|
-
|
|
23
|
-
return result
|
|
24
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Rect } from '../_types'
|
|
2
|
-
|
|
3
|
-
export function getRectBrushOrPencilBounds(
|
|
4
|
-
centerX: number,
|
|
5
|
-
centerY: number,
|
|
6
|
-
brushWidth: number,
|
|
7
|
-
brushHeight: number,
|
|
8
|
-
targetWidth: number,
|
|
9
|
-
targetHeight: number,
|
|
10
|
-
out?: Rect,
|
|
11
|
-
): Rect {
|
|
12
|
-
const startX = Math.floor(centerX - brushWidth / 2)
|
|
13
|
-
const startY = Math.floor(centerY - brushHeight / 2)
|
|
14
|
-
const endX = startX + brushWidth
|
|
15
|
-
const endY = startY + brushHeight
|
|
16
|
-
|
|
17
|
-
const res = out ?? {
|
|
18
|
-
x: 0,
|
|
19
|
-
y: 0,
|
|
20
|
-
w: 0,
|
|
21
|
-
h: 0,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const cStartX = Math.max(0, startX)
|
|
25
|
-
const cStartY = Math.max(0, startY)
|
|
26
|
-
const cEndX = Math.min(targetWidth, endX)
|
|
27
|
-
const cEndY = Math.min(targetHeight, endY)
|
|
28
|
-
|
|
29
|
-
const w = cEndX - cStartX
|
|
30
|
-
const h = cEndY - cStartY
|
|
31
|
-
|
|
32
|
-
res.x = cStartX
|
|
33
|
-
res.y = cStartY
|
|
34
|
-
res.w = w < 0 ? 0 : w
|
|
35
|
-
res.h = h < 0 ? 0 : h
|
|
36
|
-
|
|
37
|
-
return res
|
|
38
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Rect } from '../_types'
|
|
2
|
-
|
|
3
|
-
export function getRectBrushOrPencilStrokeBounds(
|
|
4
|
-
x0: number,
|
|
5
|
-
y0: number,
|
|
6
|
-
x1: number,
|
|
7
|
-
y1: number,
|
|
8
|
-
brushWidth: number,
|
|
9
|
-
brushHeight: number,
|
|
10
|
-
result: Rect,
|
|
11
|
-
): Rect {
|
|
12
|
-
const halfW = brushWidth / 2
|
|
13
|
-
const halfH = brushHeight / 2
|
|
14
|
-
|
|
15
|
-
const minX = Math.min(x0, x1) - halfW
|
|
16
|
-
const minY = Math.min(y0, y1) - halfH
|
|
17
|
-
const maxX = Math.max(x0, x1) + halfW
|
|
18
|
-
const maxY = Math.max(y0, y1) + halfH
|
|
19
|
-
|
|
20
|
-
result.x = Math.floor(minX)
|
|
21
|
-
result.y = Math.floor(minY)
|
|
22
|
-
result.w = Math.ceil(maxX - minX)
|
|
23
|
-
result.h = Math.ceil(maxY - minY)
|
|
24
|
-
|
|
25
|
-
return result
|
|
26
|
-
}
|