pixel-data-js 0.35.0 → 0.37.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 +521 -326
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +132 -78
- package/dist/index.prod.js +513 -324
- package/dist/index.prod.js.map +1 -1
- package/package.json +2 -2
- package/src/Algorithm/floodFillSelection.ts +3 -2
- package/src/BlendModes/blend-modes-fast.ts +2 -1
- package/src/BlendModes/blend-modes-perfect.ts +2 -1
- package/src/Canvas/ReusableCanvas.ts +0 -5
- package/src/Color/_color-types.ts +8 -0
- package/src/Color/colorDistance.ts +9 -0
- package/src/Color/convert-color.ts +43 -0
- package/src/Color/lerpColor32.ts +44 -0
- package/src/Color/pack-color.ts +38 -0
- package/src/History/HistoryAction.ts +2 -2
- package/src/History/PixelAccumulator.ts +32 -13
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +2 -0
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +5 -1
- package/src/History/PixelMutator/mutatorApplyMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendAlphaMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendBinaryMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendColor.ts +4 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +24 -8
- package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +4 -1
- package/src/History/PixelMutator/mutatorBlendMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +3 -1
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +1 -0
- package/src/History/PixelMutator/mutatorClear.ts +3 -2
- package/src/History/PixelMutator/mutatorFill.ts +54 -38
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +3 -2
- package/src/History/PixelMutator/mutatorInvert.ts +3 -2
- package/src/History/PixelMutator.ts +1 -2
- package/src/History/PixelWriter.ts +5 -5
- package/src/IndexedImage/IndexedImage.ts +1 -1
- package/src/IndexedImage/indexedImageToAverageColor.ts +3 -2
- package/src/Mask/_mask-types.ts +9 -0
- package/src/Paint/AlphaMaskPaintBuffer.ts +26 -26
- package/src/Paint/BinaryMaskPaintBuffer.ts +19 -19
- package/src/Paint/ColorPaintBuffer.ts +40 -42
- package/src/Paint/Commit/AlphaMaskPaintBufferCommitter.ts +1 -1
- package/src/Paint/Commit/AlphaMaskPaintBufferManager.ts +6 -7
- package/src/Paint/Commit/BinaryMaskPaintBufferCommitter.ts +1 -1
- package/src/Paint/Commit/BinaryMaskPaintBufferManager.ts +6 -7
- package/src/Paint/Commit/ColorPaintBufferManager.ts +6 -7
- package/src/Paint/Commit/commitColorPaintBuffer.ts +2 -6
- package/src/Paint/Commit/commitMaskPaintBuffer.ts +3 -7
- package/src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts +42 -25
- package/src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts +40 -24
- package/src/Paint/Render/ColorPaintBufferCanvasRenderer.ts +21 -21
- package/src/Paint/Render/PaintCursorRenderer.ts +12 -2
- package/src/Paint/eachTileInBounds.ts +9 -10
- package/src/PixelData/_pixelData-types.ts +7 -0
- package/src/PixelData/blendColorPixelData.ts +2 -1
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +2 -1
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +2 -1
- package/src/PixelData/blendColorPixelDataMask.ts +2 -1
- package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +1 -1
- package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +1 -1
- package/src/PixelData/blendColorPixelDataPaintMask.ts +19 -8
- package/src/PixelData/blendPixel.ts +2 -1
- package/src/PixelData/blendPixelData.ts +2 -1
- package/src/PixelData/blendPixelDataAlphaMask.ts +2 -1
- package/src/PixelData/blendPixelDataBinaryMask.ts +2 -1
- package/src/PixelData/blendPixelDataPaintBuffer.ts +2 -3
- package/src/PixelData/clearPixelDataFast.ts +1 -1
- package/src/PixelData/cropPixelData.ts +36 -0
- package/src/PixelData/fillPixelData.ts +7 -7
- package/src/PixelData/fillPixelDataBinaryMask.ts +1 -1
- package/src/PixelData/fillPixelDataFast.ts +1 -1
- package/src/PixelData/trimPixelData.ts +49 -0
- package/src/PixelData/writePaintBufferToPixelData.ts +1 -5
- package/src/Tile/MaskTile.ts +4 -0
- package/src/Tile/PixelTile.ts +2 -0
- package/src/Tile/TilePool.ts +9 -8
- package/src/Tile/TileTargetConfig.ts +27 -0
- package/src/Tile/_tile-types.ts +16 -0
- package/src/_types.ts +1 -6
- package/src/index.ts +9 -3
- package/src/History/PixelEngineConfig.ts +0 -28
- package/src/Internal/_constants.ts +0 -3
- package/src/color.ts +0 -112
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixel-data-js",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.37.0",
|
|
5
5
|
"packageManager": "pnpm@10.33.0",
|
|
6
6
|
"description": "JS Pixel and ImageData operations",
|
|
7
7
|
"author": {
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"typedoc-plugin-mdn-links": "^5.1.1",
|
|
89
89
|
"typedoc-rhineai-theme": "^1.2.0",
|
|
90
90
|
"typescript": "^5.9.3",
|
|
91
|
-
"unplugin-inline": "^1.
|
|
91
|
+
"unplugin-inline": "^1.16.0",
|
|
92
92
|
"vite-tsconfig-paths": "^6.1.1",
|
|
93
93
|
"vitest": "3.2.4"
|
|
94
94
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { Color32 } from '../Color/_color-types'
|
|
2
|
+
|
|
3
|
+
import { colorDistance } from '../Color/colorDistance'
|
|
3
4
|
import { extractImageDataBuffer } from '../ImageData/extractImageDataBuffer'
|
|
4
5
|
import { type BinaryMaskRect, MaskType } from '../Mask/_mask-types'
|
|
5
6
|
import type { PixelData } from '../PixelData/_pixelData-types'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BlendColor32
|
|
1
|
+
import type { BlendColor32 } from '../_types'
|
|
2
|
+
import type { Color32 } from '../Color/_color-types'
|
|
2
3
|
import { BaseBlendMode, overwriteBase } from './blend-modes'
|
|
3
4
|
import { makeBlendModeRegistry } from './BlendModeRegistry'
|
|
4
5
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BlendColor32
|
|
1
|
+
import type { BlendColor32 } from '../_types'
|
|
2
|
+
import type { Color32 } from '../Color/_color-types'
|
|
2
3
|
import { BaseBlendMode, overwriteBase } from './blend-modes'
|
|
3
4
|
import { makeBlendModeRegistry } from './BlendModeRegistry'
|
|
4
5
|
|
|
@@ -63,11 +63,6 @@ function makeReusableCanvasMeta<T extends HTMLCanvasElement | OffscreenCanvas>(
|
|
|
63
63
|
canvas.width = width
|
|
64
64
|
canvas.height = height
|
|
65
65
|
ctx!.imageSmoothingEnabled = false
|
|
66
|
-
} else {
|
|
67
|
-
// Always reset transform before clearing to ensure the whole buffer is wiped
|
|
68
|
-
ctx!.setTransform(1, 0, 0, 1, 0, 0)
|
|
69
|
-
// Same size → manually clear
|
|
70
|
-
ctx!.clearRect(0, 0, width, height)
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
return result
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Represents a 32-bit color in 0xAABBGGRR (Little endian) */
|
|
2
|
+
export type Color32 = number & { readonly __brandColor32: unique symbol }
|
|
3
|
+
|
|
4
|
+
/** ALL values are 0-255 */
|
|
5
|
+
export type RGBA = { r: number, g: number, b: number, a: number }
|
|
6
|
+
|
|
7
|
+
/** r, g, b are 0-255. a is 0-1 for css use */
|
|
8
|
+
export type CssRGBA = { r: number, g: number, b: number, a: number } & { readonly __brandCssRGBA: unique symbol }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Color32 } from './_color-types'
|
|
2
|
+
|
|
3
|
+
export function colorDistance(a: Color32, b: Color32): number {
|
|
4
|
+
const dr = (a & 0xFF) - (b & 0xFF)
|
|
5
|
+
const dg = ((a >>> 8) & 0xFF) - ((b >>> 8) & 0xFF)
|
|
6
|
+
const db = ((a >>> 16) & 0xFF) - ((b >>> 16) & 0xFF)
|
|
7
|
+
const da = ((a >>> 24) & 0xFF) - ((b >>> 24) & 0xFF)
|
|
8
|
+
return dr * dr + dg * dg + db * db + da * da
|
|
9
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Convert 0xAABBGGRR to #RRGGBBAA
|
|
2
|
+
import type { Color32, CssRGBA } from './_color-types'
|
|
3
|
+
|
|
4
|
+
export function color32ToHex(color: Color32): string {
|
|
5
|
+
const r = (color & 0xFF).toString(16).padStart(2, '0')
|
|
6
|
+
const g = ((color >>> 8) & 0xFF).toString(16).padStart(2, '0')
|
|
7
|
+
const b = ((color >>> 16) & 0xFF).toString(16).padStart(2, '0')
|
|
8
|
+
const a = ((color >>> 24) & 0xFF).toString(16).padStart(2, '0')
|
|
9
|
+
return `#${r}${g}${b}${a}`
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts a 32-bit integer (0xAABBGGRR) to a CSS rgba() string.
|
|
14
|
+
* Example: 0xFF0000FF -> "rgba(255,0,0,1)"
|
|
15
|
+
*/
|
|
16
|
+
export function color32ToCssRGBAString(color: Color32): string {
|
|
17
|
+
const r = color & 0xFF
|
|
18
|
+
const g = (color >>> 8) & 0xFF
|
|
19
|
+
const b = (color >>> 16) & 0xFF
|
|
20
|
+
const a = (color >>> 24) & 0xFF
|
|
21
|
+
|
|
22
|
+
const alpha = Number((a / 255).toFixed(3))
|
|
23
|
+
|
|
24
|
+
return `rgba(${r},${g},${b},${alpha})`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function color32ToCssRGBA(color: Color32): CssRGBA {
|
|
28
|
+
const r = color & 0xFF
|
|
29
|
+
const g = (color >>> 8) & 0xFF
|
|
30
|
+
const b = (color >>> 16) & 0xFF
|
|
31
|
+
const a = (color >>> 24) & 0xFF
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
r,
|
|
35
|
+
g,
|
|
36
|
+
b,
|
|
37
|
+
a: a / 255,
|
|
38
|
+
} as CssRGBA
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function cssRGBAToColor32({ r, g, b, a }: CssRGBA): Color32 {
|
|
42
|
+
return (((a * 255) << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
43
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Color32 } from './_color-types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Linearly interpolates between two 32-bit colors using a floating-point weight.
|
|
5
|
+
* * This is the preferred method for UI animations or scenarios where high
|
|
6
|
+
* precision is required. It uses the standard `a + t * (b - a)` formula
|
|
7
|
+
* for each channel.
|
|
8
|
+
* @param a - The starting color as a 32-bit integer (AABBGGRR).
|
|
9
|
+
* @param b - The target color as a 32-bit integer (AABBGGRR).
|
|
10
|
+
* @param t - The interpolation factor between 0.0 and 1.0.
|
|
11
|
+
* @returns The interpolated 32-bit color.
|
|
12
|
+
*/
|
|
13
|
+
export function lerpColor32(a: Color32, b: Color32, t: number): Color32 {
|
|
14
|
+
const r = (a & 0xFF) + t * ((b & 0xFF) - (a & 0xFF))
|
|
15
|
+
const g = ((a >>> 8) & 0xFF) + t * (((b >>> 8) & 0xFF) - ((a >>> 8) & 0xFF))
|
|
16
|
+
const b_ = ((a >>> 16) & 0xFF) + t * (((b >>> 16) & 0xFF) - ((a >>> 16) & 0xFF))
|
|
17
|
+
const a_ = ((a >>> 24) & 0xFF) + t * (((b >>> 24) & 0xFF) - ((a >>> 24) & 0xFF))
|
|
18
|
+
|
|
19
|
+
return ((a_ << 24) | (b_ << 16) | (g << 8) | r) >>> 0 as Color32
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Linearly interpolates between two 32-bit colors using integer fixed-point math.
|
|
24
|
+
* Highly optimized for image processing and real-time blitting. It processes
|
|
25
|
+
* channels in parallel using bitmasks (RB and GA pairs).
|
|
26
|
+
* **Note:** Subject to a 1-bit drift (rounding down) due to fast bit-shift division.
|
|
27
|
+
* @param src - The source (foreground) color as a 32-bit integer.
|
|
28
|
+
* @param dst - The destination (background) color as a 32-bit integer.
|
|
29
|
+
* @param w - The blend weight as a byte value from 0 to 255. Where 0 is 100% dst and 255 is 100% src
|
|
30
|
+
* @returns The blended 32-bit color.
|
|
31
|
+
*/
|
|
32
|
+
export function lerpColor32Fast(src: Color32, dst: Color32, w: number): Color32 {
|
|
33
|
+
const invA = 255 - w
|
|
34
|
+
|
|
35
|
+
// Masking Red and Blue: 0x00FF00FF
|
|
36
|
+
// We process R and B in one go, then shift back down
|
|
37
|
+
const rb = (((src & 0x00FF00FF) * w + (dst & 0x00FF00FF) * invA) >>> 8) & 0x00FF00FF
|
|
38
|
+
|
|
39
|
+
// Masking Green and Alpha: 0xFF00FF00
|
|
40
|
+
// We shift down first to avoid overflow, then shift back up
|
|
41
|
+
const ga = ((((src >>> 8) & 0x00FF00FF) * w + ((dst >>> 8) & 0x00FF00FF) * invA) >>> 8) & 0x00FF00FF
|
|
42
|
+
|
|
43
|
+
return (rb | (ga << 8)) >>> 0 as Color32
|
|
44
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Color32, RGBA } from './_color-types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Packs RGBA into a 32-bit integer compatible with
|
|
5
|
+
* Little-Endian Uint32Array views on ImageData.
|
|
6
|
+
*/
|
|
7
|
+
export function packColor(r: number, g: number, b: number, a: number): Color32 {
|
|
8
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function packRGBA({ r, g, b, a }: RGBA): Color32 {
|
|
12
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const unpackRed = (packed: Color32): number => (packed >>> 0) & 0xFF
|
|
16
|
+
export const unpackGreen = (packed: Color32): number => (packed >>> 8) & 0xFF
|
|
17
|
+
export const unpackBlue = (packed: Color32): number => (packed >>> 16) & 0xFF
|
|
18
|
+
export const unpackAlpha = (packed: Color32): number => (packed >>> 24) & 0xFF
|
|
19
|
+
|
|
20
|
+
export function unpackColor(packed: Color32): RGBA {
|
|
21
|
+
return {
|
|
22
|
+
r: (packed >>> 0) & 0xFF,
|
|
23
|
+
g: (packed >>> 8) & 0xFF,
|
|
24
|
+
b: (packed >>> 16) & 0xFF,
|
|
25
|
+
a: (packed >>> 24) & 0xFF,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const SCRATCH_RGBA: RGBA = { r: 0, g: 0, b: 0, a: 0 }
|
|
30
|
+
|
|
31
|
+
// uses a scratch arg for memory perf. be careful about re-use.
|
|
32
|
+
export function unpackColorTo(packed: Color32, scratch = SCRATCH_RGBA): RGBA {
|
|
33
|
+
scratch.r = (packed >>> 0) & 0xFF
|
|
34
|
+
scratch.g = (packed >>> 8) & 0xFF
|
|
35
|
+
scratch.b = (packed >>> 16) & 0xFF
|
|
36
|
+
scratch.a = (packed >>> 24) & 0xFF
|
|
37
|
+
return scratch
|
|
38
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { TileTargetConfig } from '../Tile/_tile-types'
|
|
1
2
|
import type { PixelAccumulator } from './PixelAccumulator'
|
|
2
|
-
import type { PixelEngineConfig } from './PixelEngineConfig'
|
|
3
3
|
import { applyPatchTiles, type PixelPatchTiles } from './PixelPatchTiles'
|
|
4
4
|
|
|
5
5
|
export interface HistoryAction {
|
|
@@ -11,7 +11,7 @@ export interface HistoryAction {
|
|
|
11
11
|
export type HistoryActionFactory = typeof makeHistoryAction
|
|
12
12
|
|
|
13
13
|
export function makeHistoryAction(
|
|
14
|
-
config:
|
|
14
|
+
config: TileTargetConfig,
|
|
15
15
|
accumulator: PixelAccumulator,
|
|
16
16
|
patch: PixelPatchTiles,
|
|
17
17
|
afterUndo?: (patch: PixelPatchTiles) => void,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { PixelTile } from '../Tile/_tile-types'
|
|
1
|
+
import type { PixelTile, TileTargetConfig } from '../Tile/_tile-types'
|
|
2
2
|
import type { TilePool } from '../Tile/TilePool'
|
|
3
|
-
import type { PixelEngineConfig } from './PixelEngineConfig'
|
|
4
3
|
import { applyPatchTiles, type PixelPatchTiles } from './PixelPatchTiles'
|
|
5
4
|
|
|
6
5
|
export type DidChangeFn = (didChange: boolean) => boolean
|
|
@@ -10,7 +9,7 @@ export class PixelAccumulator {
|
|
|
10
9
|
public beforeTiles: PixelTile[]
|
|
11
10
|
|
|
12
11
|
constructor(
|
|
13
|
-
readonly config:
|
|
12
|
+
readonly config: TileTargetConfig,
|
|
14
13
|
readonly pixelTilePool: TilePool<PixelTile>,
|
|
15
14
|
) {
|
|
16
15
|
this.lookup = []
|
|
@@ -26,11 +25,18 @@ export class PixelAccumulator {
|
|
|
26
25
|
* @param x pixel x coordinate
|
|
27
26
|
* @param y pixel y coordinate
|
|
28
27
|
*/
|
|
29
|
-
storePixelBeforeState(x: number, y: number): DidChangeFn {
|
|
30
|
-
const shift = this.config.tileShift
|
|
28
|
+
storePixelBeforeState(x: number, y: number): DidChangeFn | null {
|
|
31
29
|
const columns = this.config.targetColumns
|
|
32
|
-
const
|
|
33
|
-
const
|
|
30
|
+
const targetWidth = this.config.targetWidth
|
|
31
|
+
const targetHeight = this.config.targetHeight
|
|
32
|
+
|
|
33
|
+
// Return a no-op if the pixel is outside the target boundaries
|
|
34
|
+
if (x < 0 || x >= targetWidth || y < 0 || y >= targetHeight) {
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const tx = (x * this.config.invTileSize) | 0
|
|
39
|
+
const ty = (y * this.config.invTileSize) | 0
|
|
34
40
|
const id = ty * columns + tx
|
|
35
41
|
|
|
36
42
|
let tile = this.lookup[id]
|
|
@@ -66,14 +72,27 @@ export class PixelAccumulator {
|
|
|
66
72
|
y: number,
|
|
67
73
|
w: number,
|
|
68
74
|
h: number,
|
|
69
|
-
): DidChangeFn {
|
|
70
|
-
const shift = this.config.tileShift
|
|
75
|
+
): DidChangeFn | null {
|
|
71
76
|
const columns = this.config.targetColumns
|
|
77
|
+
const targetWidth = this.config.targetWidth
|
|
78
|
+
const targetHeight = this.config.targetHeight
|
|
79
|
+
const invTileSize = this.config.invTileSize
|
|
80
|
+
|
|
81
|
+
// Clamp the bounding box to the actual canvas dimensions
|
|
82
|
+
const clipX1 = Math.max(0, x)
|
|
83
|
+
const clipY1 = Math.max(0, y)
|
|
84
|
+
const clipX2 = Math.min(targetWidth - 1, x + w - 1)
|
|
85
|
+
const clipY2 = Math.min(targetHeight - 1, y + h - 1)
|
|
86
|
+
|
|
87
|
+
// If the region is entirely off-canvas, return a no-op
|
|
88
|
+
if (clipX2 < clipX1 || clipY2 < clipY1) {
|
|
89
|
+
return null
|
|
90
|
+
}
|
|
72
91
|
|
|
73
|
-
const startX =
|
|
74
|
-
const startY =
|
|
75
|
-
const endX = (
|
|
76
|
-
const endY = (
|
|
92
|
+
const startX = (clipX1 * invTileSize) | 0
|
|
93
|
+
const startY = (clipY1 * invTileSize) | 0
|
|
94
|
+
const endX = (clipX2 * invTileSize) | 0
|
|
95
|
+
const endY = (clipY2 * invTileSize) | 0
|
|
77
96
|
|
|
78
97
|
const startIndex = this.beforeTiles.length
|
|
79
98
|
|
|
@@ -26,6 +26,8 @@ export const mutatorApplyAlphaMask = ((writer: PixelWriter<any>, deps: Deps = de
|
|
|
26
26
|
const h = opts?.h ?? target.h
|
|
27
27
|
|
|
28
28
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
29
|
+
if (!didChange) return false
|
|
30
|
+
|
|
29
31
|
return didChange(applyAlphaMaskToPixelData(target, mask, opts))
|
|
30
32
|
},
|
|
31
33
|
}
|
|
@@ -26,7 +26,11 @@ export const mutatorApplyBinaryMask = ((writer: PixelWriter<any>, deps: Deps = d
|
|
|
26
26
|
const h = opts?.h ?? target.h
|
|
27
27
|
|
|
28
28
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
29
|
-
|
|
29
|
+
if (!didChange) return false
|
|
30
|
+
|
|
31
|
+
const b = applyBinaryMaskToPixelData(target, mask, opts)
|
|
32
|
+
console.log({ b })
|
|
33
|
+
return didChange(b)
|
|
30
34
|
},
|
|
31
35
|
}
|
|
32
36
|
}) satisfies HistoryMutator<any, Deps>
|
|
@@ -29,6 +29,7 @@ export const mutatorApplyMask = ((writer: PixelWriter<any>, deps: Deps = default
|
|
|
29
29
|
const h = opts?.h ?? target.h
|
|
30
30
|
|
|
31
31
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
32
|
+
if (!didChange) return false
|
|
32
33
|
|
|
33
34
|
if (mask.type === MaskType.BINARY) {
|
|
34
35
|
return didChange(applyBinaryMaskToPixelData(target, mask, opts))
|
|
@@ -27,6 +27,7 @@ export const mutatorBlendAlphaMask = ((writer: PixelWriter<any>, deps: Partial<D
|
|
|
27
27
|
const h = opts?.h ?? src.h
|
|
28
28
|
|
|
29
29
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
30
|
+
if (!didChange) return false
|
|
30
31
|
|
|
31
32
|
return didChange(
|
|
32
33
|
blendPixelDataAlphaMask(writer.config.target, src, mask, opts),
|
|
@@ -27,6 +27,7 @@ export const mutatorBlendBinaryMask = ((writer: PixelWriter<any>, deps: Partial<
|
|
|
27
27
|
const h = opts?.h ?? src.h
|
|
28
28
|
|
|
29
29
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
30
|
+
if (!didChange) return false
|
|
30
31
|
|
|
31
32
|
return didChange(
|
|
32
33
|
blendPixelDataBinaryMask(writer.config.target, src, mask, opts),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ColorBlendOptions } from '../../_types'
|
|
2
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
2
3
|
import { blendColorPixelData } from '../../PixelData/blendColorPixelData'
|
|
3
4
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
4
5
|
|
|
@@ -25,6 +26,8 @@ export const mutatorBlendColor = ((writer: PixelWriter<any>, deps: Deps = defaul
|
|
|
25
26
|
const h = opts?.h ?? target.h
|
|
26
27
|
|
|
27
28
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
29
|
+
if (!didChange) return false
|
|
30
|
+
|
|
28
31
|
return didChange(
|
|
29
32
|
blendColorPixelData(target, color, opts),
|
|
30
33
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Color32 } from '../../_types'
|
|
2
1
|
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
2
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
3
3
|
import type { PaintAlphaMask } from '../../Paint/_paint-types'
|
|
4
4
|
import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
|
|
5
5
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -37,6 +37,7 @@ export const mutatorBlendColorPaintAlphaMask = ((writer: PixelWriter<any>, deps:
|
|
|
37
37
|
const ty = y + mask.centerOffsetY
|
|
38
38
|
|
|
39
39
|
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h)
|
|
40
|
+
if (!didChange) return false
|
|
40
41
|
|
|
41
42
|
OPTS.x = tx
|
|
42
43
|
OPTS.y = ty
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Color32 } from '../../_types'
|
|
2
1
|
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
2
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
3
3
|
import type { PaintBinaryMask } from '../../Paint/_paint-types'
|
|
4
4
|
import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
|
|
5
5
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -37,6 +37,7 @@ export const mutatorBlendColorPaintBinaryMask = ((writer: PixelWriter<any>, deps
|
|
|
37
37
|
const ty = y + mask.centerOffsetY
|
|
38
38
|
|
|
39
39
|
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h)
|
|
40
|
+
if (!didChange) return false
|
|
40
41
|
|
|
41
42
|
OPTS.x = tx
|
|
42
43
|
OPTS.y = ty
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { type Color32 } from '../../_types'
|
|
2
1
|
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
2
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
3
3
|
import { MaskType } from '../../Mask/_mask-types'
|
|
4
|
-
import type { PaintMask } from '../../Paint/_paint-types'
|
|
4
|
+
import type { PaintMask, PaintRect } from '../../Paint/_paint-types'
|
|
5
|
+
import { blendColorPixelData } from '../../PixelData/blendColorPixelData'
|
|
5
6
|
import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
|
|
6
7
|
import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
|
|
7
8
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -9,6 +10,7 @@ import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
|
9
10
|
const defaults = {
|
|
10
11
|
blendColorPixelDataAlphaMask,
|
|
11
12
|
blendColorPixelDataBinaryMask,
|
|
13
|
+
blendColorPixelData,
|
|
12
14
|
}
|
|
13
15
|
type Deps = Partial<typeof defaults>
|
|
14
16
|
|
|
@@ -19,6 +21,7 @@ export const mutatorBlendColorPaintMask = ((writer: PixelWriter<any>, deps: Part
|
|
|
19
21
|
const {
|
|
20
22
|
blendColorPixelDataBinaryMask = defaults.blendColorPixelDataBinaryMask,
|
|
21
23
|
blendColorPixelDataAlphaMask = defaults.blendColorPixelDataAlphaMask,
|
|
24
|
+
blendColorPixelData = defaults.blendColorPixelData,
|
|
22
25
|
} = deps
|
|
23
26
|
|
|
24
27
|
const OPTS = {
|
|
@@ -26,12 +29,14 @@ export const mutatorBlendColorPaintMask = ((writer: PixelWriter<any>, deps: Part
|
|
|
26
29
|
y: 0,
|
|
27
30
|
blendFn: sourceOverPerfect,
|
|
28
31
|
alpha: 255,
|
|
32
|
+
w: undefined as number | undefined,
|
|
33
|
+
h: undefined as number | undefined,
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
return {
|
|
32
37
|
blendColorPaintMask(
|
|
33
38
|
color: Color32,
|
|
34
|
-
mask: PaintMask,
|
|
39
|
+
mask: PaintMask | PaintRect,
|
|
35
40
|
x: number,
|
|
36
41
|
y: number,
|
|
37
42
|
alpha = 255,
|
|
@@ -41,21 +46,32 @@ export const mutatorBlendColorPaintMask = ((writer: PixelWriter<any>, deps: Part
|
|
|
41
46
|
const ty = y + mask.centerOffsetY
|
|
42
47
|
|
|
43
48
|
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h)
|
|
49
|
+
if (!didChange) return false
|
|
44
50
|
|
|
45
51
|
OPTS.x = tx
|
|
46
52
|
OPTS.y = ty
|
|
47
53
|
OPTS.alpha = alpha
|
|
48
54
|
OPTS.blendFn = blendFn
|
|
55
|
+
OPTS.w = undefined
|
|
56
|
+
OPTS.h = undefined
|
|
49
57
|
|
|
50
|
-
if (mask.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
if (mask.data) {
|
|
59
|
+
if (mask.type === MaskType.BINARY) {
|
|
60
|
+
return didChange(
|
|
61
|
+
blendColorPixelDataBinaryMask(writer.config.target, color, mask, OPTS),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
55
64
|
return didChange(
|
|
56
65
|
blendColorPixelDataAlphaMask(writer.config.target, color, mask, OPTS),
|
|
57
66
|
)
|
|
58
67
|
}
|
|
68
|
+
|
|
69
|
+
OPTS.w = mask.w
|
|
70
|
+
OPTS.h = mask.h
|
|
71
|
+
|
|
72
|
+
return didChange(
|
|
73
|
+
blendColorPixelData(writer.config.target, color, OPTS),
|
|
74
|
+
)
|
|
59
75
|
},
|
|
60
76
|
}
|
|
61
77
|
}) satisfies HistoryMutator<any, Deps>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { BlendColor32
|
|
1
|
+
import type { BlendColor32 } from '../../_types'
|
|
2
2
|
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
3
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
3
4
|
import { _macro_paintRectCenterOffset } from '../../Internal/macros'
|
|
4
5
|
import { blendColorPixelData } from '../../PixelData/blendColorPixelData'
|
|
5
6
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -43,6 +44,8 @@ export const mutatorBlendColorPaintRect = ((writer: PixelWriter<any>, deps: Deps
|
|
|
43
44
|
OPTS.alpha = alpha
|
|
44
45
|
|
|
45
46
|
const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight)
|
|
47
|
+
if (!didChange) return false
|
|
48
|
+
|
|
46
49
|
return didChange(
|
|
47
50
|
blendColorPixelData(
|
|
48
51
|
target,
|
|
@@ -29,6 +29,7 @@ export const mutatorBlendMask = ((writer: PixelWriter<any>, deps: Partial<Deps>
|
|
|
29
29
|
const h = opts?.h ?? src.h
|
|
30
30
|
|
|
31
31
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
32
|
+
if (!didChange) return false
|
|
32
33
|
|
|
33
34
|
if (mask.type === MaskType.BINARY) {
|
|
34
35
|
return didChange(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BlendColor32
|
|
1
|
+
import type { BlendColor32 } from '../../_types'
|
|
2
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
2
3
|
import { blendPixel } from '../../PixelData/blendPixel'
|
|
3
4
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
4
5
|
|
|
@@ -23,6 +24,7 @@ export const mutatorBlendPixel = ((writer: PixelWriter<any>, deps: Partial<Deps>
|
|
|
23
24
|
): boolean {
|
|
24
25
|
|
|
25
26
|
const didChange = writer.accumulator.storePixelBeforeState(x, y)
|
|
27
|
+
if (!didChange) return false
|
|
26
28
|
|
|
27
29
|
return didChange(
|
|
28
30
|
blendPixel(writer.config.target, x, y, color, alpha, blendFn),
|
|
@@ -25,6 +25,7 @@ export const mutatorBlendPixelData = ((writer: PixelWriter<any>, deps: Partial<D
|
|
|
25
25
|
const h = opts?.h ?? src.h
|
|
26
26
|
|
|
27
27
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
28
|
+
if (!didChange) return false
|
|
28
29
|
|
|
29
30
|
return didChange(
|
|
30
31
|
blendPixelData(writer.config.target, src, opts),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Color32 } from '../../
|
|
1
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
2
2
|
import { fillPixelData } from '../../PixelData/fillPixelData'
|
|
3
3
|
import type { Rect } from '../../Rect/_rect-types'
|
|
4
4
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -18,7 +18,7 @@ export const mutatorClear = ((writer: PixelWriter<any>, deps: Deps = defaults) =
|
|
|
18
18
|
return {
|
|
19
19
|
clear(
|
|
20
20
|
rect?: Partial<Rect>,
|
|
21
|
-
) {
|
|
21
|
+
): boolean {
|
|
22
22
|
const target = writer.config.target
|
|
23
23
|
const x = rect?.x ?? 0
|
|
24
24
|
const y = rect?.y ?? 0
|
|
@@ -26,6 +26,7 @@ export const mutatorClear = ((writer: PixelWriter<any>, deps: Deps = defaults) =
|
|
|
26
26
|
const h = rect?.h ?? target.h
|
|
27
27
|
|
|
28
28
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
29
|
+
if (!didChange) return false
|
|
29
30
|
return didChange(
|
|
30
31
|
fillPixelData(target, 0 as Color32, x, y, w, h),
|
|
31
32
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Color32 } from '../../
|
|
1
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
2
2
|
import { fillPixelData } from '../../PixelData/fillPixelData'
|
|
3
3
|
import type { Rect } from '../../Rect/_rect-types'
|
|
4
4
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -14,44 +14,60 @@ export const mutatorFill = ((writer: PixelWriter<any>, deps: Deps = defaults) =>
|
|
|
14
14
|
fillPixelData = defaults.fillPixelData,
|
|
15
15
|
} = deps
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
fill(
|
|
19
|
-
color: Color32,
|
|
20
|
-
x = 0,
|
|
21
|
-
y = 0,
|
|
22
|
-
w = writer.config.target.w,
|
|
23
|
-
h = writer.config.target.h,
|
|
24
|
-
) {
|
|
25
|
-
const target = writer.config.target
|
|
26
|
-
|
|
27
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
28
|
-
return didChange(
|
|
29
|
-
fillPixelData(target, color, x, y, w, h),
|
|
30
|
-
)
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
}) satisfies HistoryMutator<any, Deps>
|
|
17
|
+
const config = writer.config
|
|
34
18
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
19
|
+
function fill(
|
|
20
|
+
color: Color32,
|
|
21
|
+
rect?: Partial<Rect>,
|
|
22
|
+
): boolean
|
|
23
|
+
|
|
24
|
+
function fill(
|
|
25
|
+
color: Color32,
|
|
26
|
+
x: number,
|
|
27
|
+
y: number,
|
|
28
|
+
w: number,
|
|
29
|
+
h: number,
|
|
30
|
+
): boolean
|
|
31
|
+
function fill(
|
|
32
|
+
color: Color32,
|
|
33
|
+
_x?: Partial<Rect> | number,
|
|
34
|
+
_y?: number,
|
|
35
|
+
_w?: number,
|
|
36
|
+
_h?: number,
|
|
37
|
+
): boolean {
|
|
38
|
+
const target = config.target
|
|
39
|
+
|
|
40
|
+
const dstW = target.w
|
|
41
|
+
const dstH = target.h
|
|
42
|
+
|
|
43
|
+
let x: number
|
|
44
|
+
let y: number
|
|
45
|
+
let w: number
|
|
46
|
+
let h: number
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
if (typeof _x === 'number') {
|
|
49
|
+
x = _x
|
|
50
|
+
y = _y!
|
|
51
|
+
w = _w!
|
|
52
|
+
h = _h!
|
|
53
|
+
} else if (typeof _x === 'object') {
|
|
54
|
+
x = _x.x ?? 0
|
|
55
|
+
y = _x.y ?? 0
|
|
56
|
+
w = _x.w ?? dstW
|
|
57
|
+
h = _x.h ?? dstH
|
|
58
|
+
} else {
|
|
59
|
+
x = 0
|
|
60
|
+
y = 0
|
|
61
|
+
w = dstW
|
|
62
|
+
h = dstH
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
66
|
+
if (!didChange) return false
|
|
67
|
+
return didChange(
|
|
68
|
+
fillPixelData(target, color, x, y, w, h),
|
|
69
|
+
)
|
|
55
70
|
}
|
|
56
|
-
}) satisfies HistoryMutator<any, Deps>
|
|
57
71
|
|
|
72
|
+
return { fill }
|
|
73
|
+
}) satisfies HistoryMutator<any, Deps>
|