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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Rect } from '../Rect/_rect-types'
|
|
2
|
+
import type { MutablePixelData, PixelData, PixelData32 } from './_pixelData-types'
|
|
3
|
+
import { cropPixelData } from './cropPixelData'
|
|
4
|
+
|
|
5
|
+
export function getPixelDataTransparentTrimmedBounds(target: PixelData32): Rect | null {
|
|
6
|
+
let minX = target.w
|
|
7
|
+
let minY = target.h
|
|
8
|
+
let maxX = -1
|
|
9
|
+
let maxY = -1
|
|
10
|
+
|
|
11
|
+
for (let y = 0; y < target.h; y++) {
|
|
12
|
+
for (let x = 0; x < target.w; x++) {
|
|
13
|
+
const alpha = target.data[y * target.w + x] >>> 24
|
|
14
|
+
if (alpha !== 0) {
|
|
15
|
+
if (x < minX) minX = x
|
|
16
|
+
if (x > maxX) maxX = x
|
|
17
|
+
if (y < minY) minY = y
|
|
18
|
+
if (y > maxY) maxY = y
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (maxX === -1) return null
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
x: minX,
|
|
27
|
+
y: minY,
|
|
28
|
+
w: maxX - minX + 1,
|
|
29
|
+
h: maxY - minY + 1,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function trimTransparentPixelData(target: PixelData32): PixelData {
|
|
34
|
+
const r = getPixelDataTransparentTrimmedBounds(target)
|
|
35
|
+
if (!r) {
|
|
36
|
+
throw new Error('PixelData is fully transparent — no crop bounds found')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return cropPixelData(target, r.x, r.y, r.w, r.h)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function trimTransparentPixelDataInPlace(target: MutablePixelData) {
|
|
43
|
+
const r = getPixelDataTransparentTrimmedBounds(target)
|
|
44
|
+
if (!r) {
|
|
45
|
+
throw new Error('PixelData is fully transparent — no crop bounds found')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
cropPixelData(target, r.x, r.y, r.w, r.h, target)
|
|
49
|
+
}
|
|
@@ -10,17 +10,13 @@ export function writePaintBufferToPixelData(
|
|
|
10
10
|
paintBuffer: ColorPaintBuffer,
|
|
11
11
|
writePixelDataBufferFn = writePixelDataBuffer,
|
|
12
12
|
) {
|
|
13
|
-
const tileShift = paintBuffer.config.tileShift
|
|
14
13
|
const lookup = paintBuffer.lookup
|
|
15
14
|
|
|
16
15
|
for (let i = 0; i < lookup.length; i++) {
|
|
17
16
|
const tile = lookup[i]
|
|
18
17
|
|
|
19
18
|
if (tile) {
|
|
20
|
-
|
|
21
|
-
const dy = tile.ty << tileShift
|
|
22
|
-
|
|
23
|
-
writePixelDataBufferFn(target, tile.data, dx, dy, tile.w, tile.h)
|
|
19
|
+
writePixelDataBufferFn(target, tile.data, tile.x, tile.y, tile.w, tile.h)
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
}
|
package/src/Tile/MaskTile.ts
CHANGED
|
@@ -14,6 +14,8 @@ export const makeAlphaMaskTile: TileFactory<AlphaMaskTile> = (
|
|
|
14
14
|
data: new Uint8Array(tileArea),
|
|
15
15
|
w: tileSize,
|
|
16
16
|
h: tileSize,
|
|
17
|
+
x: tx * tileSize,
|
|
18
|
+
y: ty * tileSize,
|
|
17
19
|
id,
|
|
18
20
|
tx,
|
|
19
21
|
ty,
|
|
@@ -33,6 +35,8 @@ export const makeBinaryMaskTile: TileFactory<BinaryMaskTile> = (
|
|
|
33
35
|
data: new Uint8Array(tileArea),
|
|
34
36
|
w: tileSize,
|
|
35
37
|
h: tileSize,
|
|
38
|
+
x: tx * tileSize,
|
|
39
|
+
y: ty * tileSize,
|
|
36
40
|
id,
|
|
37
41
|
tx,
|
|
38
42
|
ty,
|
package/src/Tile/PixelTile.ts
CHANGED
package/src/Tile/TilePool.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import type { PixelEngineConfig } from '../History/PixelEngineConfig'
|
|
2
1
|
import type { Tile, TileFactory } from './_tile-types'
|
|
3
2
|
|
|
4
3
|
export class TilePool<T extends Tile> {
|
|
5
4
|
public pool: T[]
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
private tileArea: number
|
|
6
|
+
protected tileArea: number
|
|
9
7
|
|
|
10
8
|
constructor(
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
protected tileSize: number,
|
|
10
|
+
protected tileFactory: TileFactory<T>,
|
|
13
11
|
) {
|
|
14
12
|
this.pool = []
|
|
15
|
-
this.tileSize =
|
|
16
|
-
this.tileArea =
|
|
13
|
+
this.tileSize = tileSize
|
|
14
|
+
this.tileArea = tileSize * tileSize
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
getTile(
|
|
@@ -22,11 +20,14 @@ export class TilePool<T extends Tile> {
|
|
|
22
20
|
ty: number,
|
|
23
21
|
): T {
|
|
24
22
|
let tile = this.pool.pop()
|
|
23
|
+
const tileSize = this.tileSize
|
|
25
24
|
|
|
26
25
|
if (tile) {
|
|
27
26
|
tile.id = id
|
|
28
27
|
tile.tx = tx
|
|
29
28
|
tile.ty = ty
|
|
29
|
+
tile.x = tx * tileSize
|
|
30
|
+
tile.y = ty * tileSize
|
|
30
31
|
|
|
31
32
|
// Wipe dirty memory from previous uses before handing it out
|
|
32
33
|
tile.data.fill(0)
|
|
@@ -38,7 +39,7 @@ export class TilePool<T extends Tile> {
|
|
|
38
39
|
id,
|
|
39
40
|
tx,
|
|
40
41
|
ty,
|
|
41
|
-
|
|
42
|
+
tileSize,
|
|
42
43
|
this.tileArea,
|
|
43
44
|
)
|
|
44
45
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PixelData } from '../PixelData/_pixelData-types'
|
|
2
|
+
import type { TileTargetConfig, TileTargetMeta } from './_tile-types'
|
|
3
|
+
|
|
4
|
+
export function makeTileTargetConfig(
|
|
5
|
+
tileSize: number,
|
|
6
|
+
target: PixelData,
|
|
7
|
+
): TileTargetConfig {
|
|
8
|
+
return {
|
|
9
|
+
target,
|
|
10
|
+
...makeTileTargetMeta(tileSize, target),
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function makeTileTargetMeta(
|
|
15
|
+
tileSize: number,
|
|
16
|
+
target: { w: number, h: number },
|
|
17
|
+
): TileTargetMeta {
|
|
18
|
+
return {
|
|
19
|
+
targetWidth: target.w,
|
|
20
|
+
targetHeight: target.h,
|
|
21
|
+
tileSize: tileSize,
|
|
22
|
+
invTileSize: 1 / tileSize,
|
|
23
|
+
tileArea: tileSize * tileSize,
|
|
24
|
+
targetColumns: Math.ceil(target.w / tileSize),
|
|
25
|
+
targetRows: Math.ceil(target.h / tileSize),
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/Tile/_tile-types.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface BaseTile {
|
|
|
11
11
|
id: number
|
|
12
12
|
tx: number
|
|
13
13
|
ty: number
|
|
14
|
+
x: number
|
|
15
|
+
y: number
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface PixelTile extends PixelData, BaseTile {
|
|
@@ -31,3 +33,17 @@ export type TileFactory<T extends Tile> = (
|
|
|
31
33
|
tileSize: number,
|
|
32
34
|
tileArea: number,
|
|
33
35
|
) => T
|
|
36
|
+
|
|
37
|
+
export interface TileTargetMeta {
|
|
38
|
+
readonly tileArea: number
|
|
39
|
+
readonly targetColumns: number
|
|
40
|
+
readonly targetRows: number
|
|
41
|
+
readonly targetWidth: number
|
|
42
|
+
readonly targetHeight: number
|
|
43
|
+
readonly tileSize: number
|
|
44
|
+
readonly invTileSize: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface TileTargetConfig extends TileTargetMeta {
|
|
48
|
+
readonly target: PixelData
|
|
49
|
+
}
|
package/src/_types.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
+
import type { Color32 } from './Color/_color-types'
|
|
1
2
|
import type { BinaryMask } from './Mask/_mask-types'
|
|
2
3
|
|
|
3
|
-
/** ALL values are 0-255 (including alpha which in CSS is 0-1) */
|
|
4
|
-
export type RGBA = { r: number, g: number, b: number, a: number }
|
|
5
|
-
|
|
6
|
-
/** Represents a 32-bit color in 0xAABBGGRR (Little endian) */
|
|
7
|
-
export type Color32 = number & { readonly __brandColor32: unique symbol }
|
|
8
|
-
|
|
9
4
|
/**
|
|
10
5
|
* A function that defines how to combine a source color with a destination color.
|
|
11
6
|
* @param src - The incoming color (source).
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// generated by `npm run re-index`
|
|
1
|
+
// generated by `npm run re-index`
|
|
2
2
|
|
|
3
3
|
export * from './_errors'
|
|
4
4
|
export * from './_types'
|
|
@@ -24,7 +24,10 @@ export * from './Clipboard/getImageDataFromClipboard'
|
|
|
24
24
|
export * from './Clipboard/writeImageDataToClipboard'
|
|
25
25
|
export * from './Clipboard/writeImgBlobToClipboard'
|
|
26
26
|
|
|
27
|
-
export * from './
|
|
27
|
+
export * from './Color/_color-types'
|
|
28
|
+
export * from './Color/lerpColor32'
|
|
29
|
+
export * from './Color/convert-color'
|
|
30
|
+
export * from './Color/pack-color'
|
|
28
31
|
|
|
29
32
|
export * from './Control/BatchedQueue'
|
|
30
33
|
export * from './Control/RenderQueue'
|
|
@@ -32,7 +35,6 @@ export * from './Control/RenderQueue'
|
|
|
32
35
|
export * from './History/HistoryAction'
|
|
33
36
|
export * from './History/HistoryManager'
|
|
34
37
|
export * from './History/PixelAccumulator'
|
|
35
|
-
export * from './History/PixelEngineConfig'
|
|
36
38
|
export * from './History/PixelMutator'
|
|
37
39
|
|
|
38
40
|
export * from './History/PixelMutator/mutatorApplyAlphaMask'
|
|
@@ -152,6 +154,7 @@ export * from './PixelData/blendPixelDataMask'
|
|
|
152
154
|
export * from './PixelData/blendPixelDataPaintBuffer'
|
|
153
155
|
export * from './PixelData/clearPixelDataFast'
|
|
154
156
|
export * from './PixelData/copyPixelData'
|
|
157
|
+
export * from './PixelData/cropPixelData'
|
|
155
158
|
export * from './PixelData/extractPixelData'
|
|
156
159
|
export * from './PixelData/extractPixelDataBuffer'
|
|
157
160
|
export * from './PixelData/fillPixelData'
|
|
@@ -165,6 +168,7 @@ export * from './PixelData/resamplePixelData'
|
|
|
165
168
|
export * from './PixelData/resizePixelData'
|
|
166
169
|
export * from './PixelData/ReusablePixelData'
|
|
167
170
|
export * from './PixelData/rotatePixelData'
|
|
171
|
+
export * from './PixelData/trimPixelData'
|
|
168
172
|
export * from './PixelData/uInt32ArrayToPixelData'
|
|
169
173
|
export * from './PixelData/writePaintBufferToPixelData'
|
|
170
174
|
export * from './PixelData/writePixelData'
|
|
@@ -179,3 +183,5 @@ export * from './Tile/_tile-types'
|
|
|
179
183
|
export * from './Tile/MaskTile'
|
|
180
184
|
export * from './Tile/PixelTile'
|
|
181
185
|
export * from './Tile/TilePool'
|
|
186
|
+
export * from './Tile/TileTargetConfig'
|
|
187
|
+
export { colorDistance } from './Color/colorDistance'
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { PixelData } from '../PixelData/_pixelData-types'
|
|
2
|
-
|
|
3
|
-
export class PixelEngineConfig {
|
|
4
|
-
readonly tileSize: number
|
|
5
|
-
// pixelX = tileX << tileShift
|
|
6
|
-
// pixelY = tileY << tileShift
|
|
7
|
-
readonly tileShift: number
|
|
8
|
-
readonly tileMask: number
|
|
9
|
-
readonly tileArea: number
|
|
10
|
-
readonly target!: PixelData
|
|
11
|
-
readonly targetColumns: number = 0
|
|
12
|
-
readonly targetRows: number = 0
|
|
13
|
-
|
|
14
|
-
constructor(tileSize: number, target: PixelData) {
|
|
15
|
-
// Ensure it's a power of 2 to guarantee bitwise math works
|
|
16
|
-
if ((tileSize & (tileSize - 1)) !== 0) {
|
|
17
|
-
throw new Error('tileSize must be a power of 2')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
this.tileSize = tileSize
|
|
21
|
-
this.tileShift = 31 - Math.clz32(tileSize)
|
|
22
|
-
this.tileMask = tileSize - 1
|
|
23
|
-
this.tileArea = tileSize * tileSize
|
|
24
|
-
this.target = target
|
|
25
|
-
this.targetColumns = (target.w + this.tileMask) >> this.tileShift
|
|
26
|
-
this.targetRows = (target.h + this.tileMask) >> this.tileShift
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/color.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import type { Color32, RGBA } from './_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
|
-
}
|
|
39
|
-
|
|
40
|
-
export function colorDistance(a: Color32, b: Color32): number {
|
|
41
|
-
const dr = (a & 0xFF) - (b & 0xFF)
|
|
42
|
-
const dg = ((a >>> 8) & 0xFF) - ((b >>> 8) & 0xFF)
|
|
43
|
-
const db = ((a >>> 16) & 0xFF) - ((b >>> 16) & 0xFF)
|
|
44
|
-
const da = ((a >>> 24) & 0xFF) - ((b >>> 24) & 0xFF)
|
|
45
|
-
return dr * dr + dg * dg + db * db + da * da
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Linearly interpolates between two 32-bit colors using a floating-point weight.
|
|
50
|
-
* * This is the preferred method for UI animations or scenarios where high
|
|
51
|
-
* precision is required. It uses the standard `a + t * (b - a)` formula
|
|
52
|
-
* for each channel.
|
|
53
|
-
* @param a - The starting color as a 32-bit integer (AABBGGRR).
|
|
54
|
-
* @param b - The target color as a 32-bit integer (AABBGGRR).
|
|
55
|
-
* @param t - The interpolation factor between 0.0 and 1.0.
|
|
56
|
-
* @returns The interpolated 32-bit color.
|
|
57
|
-
*/
|
|
58
|
-
export function lerpColor32(a: Color32, b: Color32, t: number): Color32 {
|
|
59
|
-
const r = (a & 0xFF) + t * ((b & 0xFF) - (a & 0xFF))
|
|
60
|
-
const g = ((a >>> 8) & 0xFF) + t * (((b >>> 8) & 0xFF) - ((a >>> 8) & 0xFF))
|
|
61
|
-
const b_ = ((a >>> 16) & 0xFF) + t * (((b >>> 16) & 0xFF) - ((a >>> 16) & 0xFF))
|
|
62
|
-
const a_ = ((a >>> 24) & 0xFF) + t * (((b >>> 24) & 0xFF) - ((a >>> 24) & 0xFF))
|
|
63
|
-
|
|
64
|
-
return ((a_ << 24) | (b_ << 16) | (g << 8) | r) >>> 0 as Color32
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Linearly interpolates between two 32-bit colors using integer fixed-point math.
|
|
69
|
-
* Highly optimized for image processing and real-time blitting. It processes
|
|
70
|
-
* channels in parallel using bitmasks (RB and GA pairs).
|
|
71
|
-
* **Note:** Subject to a 1-bit drift (rounding down) due to fast bit-shift division.
|
|
72
|
-
* @param src - The source (foreground) color as a 32-bit integer.
|
|
73
|
-
* @param dst - The destination (background) color as a 32-bit integer.
|
|
74
|
-
* @param w - The blend weight as a byte value from 0 to 255. Where 0 is 100% dst and 255 is 100% src
|
|
75
|
-
* @returns The blended 32-bit color.
|
|
76
|
-
*/export function lerpColor32Fast(src: Color32, dst: Color32, w: number): Color32 {
|
|
77
|
-
const invA = 255 - w
|
|
78
|
-
|
|
79
|
-
// Masking Red and Blue: 0x00FF00FF
|
|
80
|
-
// We process R and B in one go, then shift back down
|
|
81
|
-
const rb = (((src & 0x00FF00FF) * w + (dst & 0x00FF00FF) * invA) >>> 8) & 0x00FF00FF
|
|
82
|
-
|
|
83
|
-
// Masking Green and Alpha: 0xFF00FF00
|
|
84
|
-
// We shift down first to avoid overflow, then shift back up
|
|
85
|
-
const ga = ((((src >>> 8) & 0x00FF00FF) * w + ((dst >>> 8) & 0x00FF00FF) * invA) >>> 8) & 0x00FF00FF
|
|
86
|
-
|
|
87
|
-
return (rb | (ga << 8)) >>> 0 as Color32
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Convert 0xAABBGGRR to #RRGGBBAA
|
|
91
|
-
export function color32ToHex(color: Color32): string {
|
|
92
|
-
const r = (color & 0xFF).toString(16).padStart(2, '0')
|
|
93
|
-
const g = ((color >>> 8) & 0xFF).toString(16).padStart(2, '0')
|
|
94
|
-
const b = ((color >>> 16) & 0xFF).toString(16).padStart(2, '0')
|
|
95
|
-
const a = ((color >>> 24) & 0xFF).toString(16).padStart(2, '0')
|
|
96
|
-
return `#${r}${g}${b}${a}`
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Converts a 32-bit integer (0xAABBGGRR) to a CSS rgba() string.
|
|
101
|
-
* Example: 0xFF0000FF -> "rgba(255,0,0,1)"
|
|
102
|
-
*/
|
|
103
|
-
export function color32ToCssRGBA(color: Color32): string {
|
|
104
|
-
const r = color & 0xFF
|
|
105
|
-
const g = (color >>> 8) & 0xFF
|
|
106
|
-
const b = (color >>> 16) & 0xFF
|
|
107
|
-
const a = (color >>> 24) & 0xFF
|
|
108
|
-
|
|
109
|
-
const alpha = Number((a / 255).toFixed(3))
|
|
110
|
-
|
|
111
|
-
return `rgba(${r},${g},${b},${alpha})`
|
|
112
|
-
}
|