pixel-data-js 0.36.0 → 0.38.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 +376 -305
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +109 -67
- package/dist/index.prod.js +372 -304
- 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 +13 -15
- package/src/History/PixelMutator/mutatorBlendColor.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +1 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +1 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +23 -8
- package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendPixel.ts +2 -1
- package/src/History/PixelMutator/mutatorClear.ts +1 -1
- package/src/History/PixelMutator/mutatorFill.ts +1 -1
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +1 -1
- package/src/History/PixelWriter.ts +5 -5
- package/src/ImageData/serialization.ts +7 -2
- 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 +3 -2
- package/src/Paint/eachTileInBounds.ts +9 -10
- 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/fillPixelData.ts +1 -1
- package/src/PixelData/fillPixelDataBinaryMask.ts +1 -1
- package/src/PixelData/fillPixelDataFast.ts +1 -1
- 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 +7 -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.38.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 = []
|
|
@@ -27,18 +26,17 @@ export class PixelAccumulator {
|
|
|
27
26
|
* @param y pixel y coordinate
|
|
28
27
|
*/
|
|
29
28
|
storePixelBeforeState(x: number, y: number): DidChangeFn | null {
|
|
30
|
-
const shift = this.config.tileShift
|
|
31
29
|
const columns = this.config.targetColumns
|
|
32
|
-
const targetWidth = this.config.
|
|
33
|
-
const targetHeight = this.config.
|
|
30
|
+
const targetWidth = this.config.targetWidth
|
|
31
|
+
const targetHeight = this.config.targetHeight
|
|
34
32
|
|
|
35
33
|
// Return a no-op if the pixel is outside the target boundaries
|
|
36
34
|
if (x < 0 || x >= targetWidth || y < 0 || y >= targetHeight) {
|
|
37
35
|
return null
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
const tx = x
|
|
41
|
-
const ty = y
|
|
38
|
+
const tx = (x * this.config.invTileSize) | 0
|
|
39
|
+
const ty = (y * this.config.invTileSize) | 0
|
|
42
40
|
const id = ty * columns + tx
|
|
43
41
|
|
|
44
42
|
let tile = this.lookup[id]
|
|
@@ -75,10 +73,10 @@ export class PixelAccumulator {
|
|
|
75
73
|
w: number,
|
|
76
74
|
h: number,
|
|
77
75
|
): DidChangeFn | null {
|
|
78
|
-
const shift = this.config.tileShift
|
|
79
76
|
const columns = this.config.targetColumns
|
|
80
|
-
const targetWidth = this.config.
|
|
81
|
-
const targetHeight = this.config.
|
|
77
|
+
const targetWidth = this.config.targetWidth
|
|
78
|
+
const targetHeight = this.config.targetHeight
|
|
79
|
+
const invTileSize = this.config.invTileSize
|
|
82
80
|
|
|
83
81
|
// Clamp the bounding box to the actual canvas dimensions
|
|
84
82
|
const clipX1 = Math.max(0, x)
|
|
@@ -91,10 +89,10 @@ export class PixelAccumulator {
|
|
|
91
89
|
return null
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
const startX = clipX1
|
|
95
|
-
const startY = clipY1
|
|
96
|
-
const endX = clipX2
|
|
97
|
-
const endY = clipY2
|
|
92
|
+
const startX = (clipX1 * invTileSize) | 0
|
|
93
|
+
const startY = (clipY1 * invTileSize) | 0
|
|
94
|
+
const endX = (clipX2 * invTileSize) | 0
|
|
95
|
+
const endY = (clipY2 * invTileSize) | 0
|
|
98
96
|
|
|
99
97
|
const startIndex = this.beforeTiles.length
|
|
100
98
|
|
|
@@ -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
|
|
|
@@ -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'
|
|
@@ -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'
|
|
@@ -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,
|
|
@@ -47,16 +52,26 @@ export const mutatorBlendColorPaintMask = ((writer: PixelWriter<any>, deps: Part
|
|
|
47
52
|
OPTS.y = ty
|
|
48
53
|
OPTS.alpha = alpha
|
|
49
54
|
OPTS.blendFn = blendFn
|
|
55
|
+
OPTS.w = undefined
|
|
56
|
+
OPTS.h = undefined
|
|
50
57
|
|
|
51
|
-
if (mask.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
if (mask.data) {
|
|
59
|
+
if (mask.type === MaskType.BINARY) {
|
|
60
|
+
return didChange(
|
|
61
|
+
blendColorPixelDataBinaryMask(writer.config.target, color, mask, OPTS),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
56
64
|
return didChange(
|
|
57
65
|
blendColorPixelDataAlphaMask(writer.config.target, color, mask, OPTS),
|
|
58
66
|
)
|
|
59
67
|
}
|
|
68
|
+
|
|
69
|
+
OPTS.w = mask.w
|
|
70
|
+
OPTS.h = mask.h
|
|
71
|
+
|
|
72
|
+
return didChange(
|
|
73
|
+
blendColorPixelData(writer.config.target, color, OPTS),
|
|
74
|
+
)
|
|
60
75
|
},
|
|
61
76
|
}
|
|
62
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'
|
|
@@ -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
|
|
|
@@ -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'
|
|
@@ -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'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Color32 } from '../../
|
|
1
|
+
import type { Color32 } from '../../Color/_color-types'
|
|
2
2
|
import type { BinaryMask } from '../../Mask/_mask-types'
|
|
3
3
|
import { fillPixelDataBinaryMask } from '../../PixelData/fillPixelDataBinaryMask'
|
|
4
4
|
import { type HistoryMutator, PixelWriter } from '../PixelWriter'
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { resizeImageData } from '../ImageData/resizeImageData'
|
|
2
2
|
import type { PixelData } from '../PixelData/_pixelData-types'
|
|
3
3
|
import { setPixelData } from '../PixelData/PixelData'
|
|
4
|
-
import type { PixelTile } from '../Tile/_tile-types'
|
|
4
|
+
import type { PixelTile, TileTargetConfig } from '../Tile/_tile-types'
|
|
5
5
|
import { makePixelTile } from '../Tile/PixelTile'
|
|
6
6
|
import { TilePool } from '../Tile/TilePool'
|
|
7
|
+
import { makeTileTargetConfig } from '../Tile/TileTargetConfig'
|
|
7
8
|
import { type HistoryActionFactory, makeHistoryAction } from './HistoryAction'
|
|
8
9
|
import { HistoryManager } from './HistoryManager'
|
|
9
10
|
import { PixelAccumulator } from './PixelAccumulator'
|
|
10
|
-
import { PixelEngineConfig } from './PixelEngineConfig'
|
|
11
11
|
import type { PixelPatchTiles } from './PixelPatchTiles'
|
|
12
12
|
|
|
13
13
|
export interface PixelWriterOptions {
|
|
@@ -44,7 +44,7 @@ export class PixelWriter<M> {
|
|
|
44
44
|
readonly historyManager: HistoryManager
|
|
45
45
|
readonly accumulator: PixelAccumulator
|
|
46
46
|
readonly historyActionFactory: HistoryActionFactory
|
|
47
|
-
readonly config:
|
|
47
|
+
readonly config: TileTargetConfig
|
|
48
48
|
readonly pixelTilePool: TilePool<PixelTile>
|
|
49
49
|
readonly mutator: M
|
|
50
50
|
|
|
@@ -54,10 +54,10 @@ export class PixelWriter<M> {
|
|
|
54
54
|
const tileSize = options?.tileSize ?? 256
|
|
55
55
|
const maxHistorySteps = options?.maxHistorySteps ?? 50
|
|
56
56
|
|
|
57
|
-
this.config =
|
|
57
|
+
this.config = makeTileTargetConfig(tileSize, target)
|
|
58
58
|
this.historyManager = options?.historyManager ?? new HistoryManager(maxHistorySteps)
|
|
59
59
|
this.historyActionFactory = options?.historyActionFactory ?? makeHistoryAction
|
|
60
|
-
this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config, makePixelTile)
|
|
60
|
+
this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config.tileSize, makePixelTile)
|
|
61
61
|
this.accumulator = options?.accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool)
|
|
62
62
|
this.mutator = mutatorFactory(this)
|
|
63
63
|
}
|
|
@@ -2,8 +2,11 @@ import type { Base64EncodedUInt8Array, ImageDataLike, SerializedImageData } from
|
|
|
2
2
|
|
|
3
3
|
export function base64EncodeArrayBuffer(buffer: ArrayBufferLike): Base64EncodedUInt8Array {
|
|
4
4
|
const uint8 = new Uint8Array(buffer)
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
let binary = ''
|
|
6
|
+
|
|
7
|
+
for (let i = 0; i < uint8.length; i++) {
|
|
8
|
+
binary += String.fromCharCode(uint8[i])
|
|
9
|
+
}
|
|
7
10
|
|
|
8
11
|
return btoa(binary) as Base64EncodedUInt8Array
|
|
9
12
|
}
|
|
@@ -11,9 +14,11 @@ export function base64EncodeArrayBuffer(buffer: ArrayBufferLike): Base64EncodedU
|
|
|
11
14
|
export function base64DecodeArrayBuffer(encoded: Base64EncodedUInt8Array): Uint8ClampedArray<ArrayBuffer> {
|
|
12
15
|
const binary = atob(encoded)
|
|
13
16
|
const bytes = new Uint8ClampedArray(binary.length)
|
|
17
|
+
|
|
14
18
|
for (let i = 0; i < binary.length; i++) {
|
|
15
19
|
bytes[i] = binary.charCodeAt(i)
|
|
16
20
|
}
|
|
21
|
+
|
|
17
22
|
return bytes
|
|
18
23
|
}
|
|
19
24
|
|
package/src/Mask/_mask-types.ts
CHANGED
|
@@ -64,6 +64,15 @@ export type NullableBinaryMaskRect = Rect & ({
|
|
|
64
64
|
type?: null
|
|
65
65
|
data?: null
|
|
66
66
|
})
|
|
67
|
+
|
|
68
|
+
export type NullableAlphaMaskRect = Rect & ({
|
|
69
|
+
type: MaskType.ALPHA
|
|
70
|
+
data: Uint8Array
|
|
71
|
+
} | {
|
|
72
|
+
type?: null
|
|
73
|
+
data?: null
|
|
74
|
+
})
|
|
75
|
+
|
|
67
76
|
export type NullableMaskRect = Rect & ({
|
|
68
77
|
type: MaskType
|
|
69
78
|
data: Uint8Array
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { forEachLinePoint } from '../Algorithm/forEachLinePoint'
|
|
2
|
-
import type { PixelEngineConfig } from '../History/PixelEngineConfig'
|
|
3
2
|
import type { Rect } from '../Rect/_rect-types'
|
|
4
3
|
import { trimRectBounds } from '../Rect/trimRectBounds'
|
|
5
|
-
import type { AlphaMaskTile } from '../Tile/_tile-types'
|
|
6
|
-
import
|
|
4
|
+
import type { AlphaMaskTile, TileTargetMeta } from '../Tile/_tile-types'
|
|
5
|
+
import { makeAlphaMaskTile } from '../Tile/MaskTile'
|
|
6
|
+
import { TilePool } from '../Tile/TilePool'
|
|
7
7
|
import type { PaintAlphaMask, PaintBinaryMask, PaintRect } from './_paint-types'
|
|
8
8
|
import { eachTileInBounds } from './eachTileInBounds'
|
|
9
9
|
|
|
@@ -16,8 +16,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
16
16
|
private eachTileInBoundsFn = eachTileInBounds
|
|
17
17
|
|
|
18
18
|
constructor(
|
|
19
|
-
readonly config:
|
|
20
|
-
readonly tilePool: TilePool<AlphaMaskTile
|
|
19
|
+
readonly config: TileTargetMeta,
|
|
20
|
+
readonly tilePool: TilePool<AlphaMaskTile> = new TilePool(config.tileSize, makeAlphaMaskTile),
|
|
21
21
|
) {
|
|
22
22
|
this.lookup = []
|
|
23
23
|
}
|
|
@@ -46,9 +46,9 @@ export class AlphaMaskPaintBuffer {
|
|
|
46
46
|
const lookup = this.lookup
|
|
47
47
|
const tilePool = this.tilePool
|
|
48
48
|
const config = this.config
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
49
|
+
const targetW = config.targetWidth
|
|
50
|
+
const targetH = config.targetHeight
|
|
51
|
+
const tileSize = config.tileSize
|
|
52
52
|
|
|
53
53
|
const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
|
|
54
54
|
|
|
@@ -66,8 +66,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
66
66
|
topLeftY,
|
|
67
67
|
bW,
|
|
68
68
|
bH,
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
targetW,
|
|
70
|
+
targetH,
|
|
71
71
|
scratch,
|
|
72
72
|
)
|
|
73
73
|
|
|
@@ -80,8 +80,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
80
80
|
for (let i = 0; i < bH_t; i++) {
|
|
81
81
|
const canvasY = bY + i
|
|
82
82
|
const bOff = (canvasY - topLeftY) * bW
|
|
83
|
-
const tOff = (canvasY
|
|
84
|
-
const dS = tOff + (bX
|
|
83
|
+
const tOff = (canvasY - tile.y) * tileSize
|
|
84
|
+
const dS = tOff + (bX - tile.x)
|
|
85
85
|
|
|
86
86
|
for (let j = 0; j < bW_t; j++) {
|
|
87
87
|
const canvasX = bX + j
|
|
@@ -130,9 +130,9 @@ export class AlphaMaskPaintBuffer {
|
|
|
130
130
|
const lookup = this.lookup
|
|
131
131
|
const tilePool = this.tilePool
|
|
132
132
|
const config = this.config
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
const
|
|
133
|
+
const targetW = config.targetWidth
|
|
134
|
+
const targetH = config.targetHeight
|
|
135
|
+
const tileSize = config.tileSize
|
|
136
136
|
|
|
137
137
|
const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
|
|
138
138
|
let changed = false
|
|
@@ -149,8 +149,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
149
149
|
topLeftY,
|
|
150
150
|
bW,
|
|
151
151
|
bH,
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
targetW,
|
|
153
|
+
targetH,
|
|
154
154
|
scratch,
|
|
155
155
|
)
|
|
156
156
|
|
|
@@ -163,8 +163,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
163
163
|
for (let i = 0; i < bH_t; i++) {
|
|
164
164
|
const canvasY = bY + i
|
|
165
165
|
const bOff = (canvasY - topLeftY) * bW
|
|
166
|
-
const tOff = (canvasY
|
|
167
|
-
const dS = tOff + (bX
|
|
166
|
+
const tOff = (canvasY - tile.y) * tileSize
|
|
167
|
+
const dS = tOff + (bX - tile.x)
|
|
168
168
|
|
|
169
169
|
for (let j = 0; j < bW_t; j++) {
|
|
170
170
|
const canvasX = bX + j
|
|
@@ -210,9 +210,9 @@ export class AlphaMaskPaintBuffer {
|
|
|
210
210
|
const lookup = this.lookup
|
|
211
211
|
const tilePool = this.tilePool
|
|
212
212
|
const config = this.config
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
213
|
+
const targetW = config.targetWidth
|
|
214
|
+
const targetH = config.targetHeight
|
|
215
|
+
const tileSize = config.tileSize
|
|
216
216
|
|
|
217
217
|
const brushWidth = brush.w
|
|
218
218
|
const brushHeight = brush.h
|
|
@@ -237,8 +237,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
237
237
|
topLeftY,
|
|
238
238
|
brushWidth,
|
|
239
239
|
brushHeight,
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
targetW,
|
|
241
|
+
targetH,
|
|
242
242
|
scratch,
|
|
243
243
|
)
|
|
244
244
|
|
|
@@ -250,8 +250,8 @@ export class AlphaMaskPaintBuffer {
|
|
|
250
250
|
|
|
251
251
|
for (let i = 0; i < bH_t; i++) {
|
|
252
252
|
const canvasY = bY + i
|
|
253
|
-
const tOff = (canvasY
|
|
254
|
-
const dS = tOff + (bX
|
|
253
|
+
const tOff = (canvasY - tile.y) * tileSize
|
|
254
|
+
const dS = tOff + (bX - tile.x)
|
|
255
255
|
|
|
256
256
|
for (let j = 0; j < bW_t; j++) {
|
|
257
257
|
const idx = dS + j
|