pixel-data-js 0.2.0 → 0.3.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 +216 -245
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +214 -240
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +216 -245
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +145 -147
- package/dist/index.prod.js +214 -240
- package/dist/index.prod.js.map +1 -1
- package/package.json +3 -4
- package/src/ImageData/copyImageData.ts +13 -0
- package/src/ImageData/{read-write-pixels.ts → extractImageData.ts} +4 -51
- package/src/ImageData/writeImageData.ts +54 -0
- package/src/Mask/copyMask.ts +10 -0
- package/src/Mask/invertMask.ts +25 -0
- package/src/Mask/mergeMasks.ts +105 -0
- package/src/PixelData/applyMaskToPixelData.ts +129 -0
- package/src/PixelData/blendColorPixelData.ts +157 -0
- package/src/PixelData/blendPixelData.ts +196 -0
- package/src/PixelData/clearPixelData.ts +14 -0
- package/src/PixelData/fillPixelData.ts +56 -0
- package/src/PixelData.ts +20 -0
- package/src/_types.ts +120 -12
- package/src/{ImageData/blend-modes.ts → blend-modes.ts} +1 -1
- package/src/index.ts +5 -5
- package/src/ImageData/blit.ts +0 -177
- package/src/ImageData/mask.ts +0 -150
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type Color32, type ColorBlendOptions, MaskType } from '../_types'
|
|
2
|
+
import { sourceOverColor32 } from '../blend-modes'
|
|
3
|
+
import type { PixelData } from '../PixelData'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fills a rectangle in the destination PixelData with a single color,
|
|
7
|
+
* supporting blend modes, global alpha, and masking.
|
|
8
|
+
*/
|
|
9
|
+
export function blendColorPixelData(
|
|
10
|
+
dst: PixelData,
|
|
11
|
+
color: Color32,
|
|
12
|
+
opts: ColorBlendOptions,
|
|
13
|
+
): void {
|
|
14
|
+
const {
|
|
15
|
+
x: targetX = 0,
|
|
16
|
+
y: targetY = 0,
|
|
17
|
+
w: width = dst.width,
|
|
18
|
+
h: height = dst.height,
|
|
19
|
+
alpha: globalAlpha = 255,
|
|
20
|
+
blendFn = sourceOverColor32,
|
|
21
|
+
mask,
|
|
22
|
+
maskType = MaskType.ALPHA,
|
|
23
|
+
mw,
|
|
24
|
+
mx = 0,
|
|
25
|
+
my = 0,
|
|
26
|
+
invertMask = false,
|
|
27
|
+
} = opts
|
|
28
|
+
|
|
29
|
+
if (globalAlpha === 0) return
|
|
30
|
+
|
|
31
|
+
let x = targetX
|
|
32
|
+
let y = targetY
|
|
33
|
+
let w = width
|
|
34
|
+
let h = height
|
|
35
|
+
|
|
36
|
+
// 1. Destination Clipping
|
|
37
|
+
if (x < 0) {
|
|
38
|
+
w += x
|
|
39
|
+
x = 0
|
|
40
|
+
}
|
|
41
|
+
if (y < 0) {
|
|
42
|
+
h += y
|
|
43
|
+
y = 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const actualW = Math.min(w, dst.width - x)
|
|
47
|
+
const actualH = Math.min(h, dst.height - y)
|
|
48
|
+
|
|
49
|
+
if (actualW <= 0 || actualH <= 0) return
|
|
50
|
+
|
|
51
|
+
const dst32 = dst.data32
|
|
52
|
+
const dw = dst.width
|
|
53
|
+
const mPitch = mw ?? width
|
|
54
|
+
const isAlphaMask = maskType === MaskType.ALPHA
|
|
55
|
+
|
|
56
|
+
const dx = x - targetX
|
|
57
|
+
const dy = y - targetY
|
|
58
|
+
|
|
59
|
+
let dIdx = y * dw + x
|
|
60
|
+
let mIdx = (my + dy) * mPitch + (mx + dx)
|
|
61
|
+
|
|
62
|
+
const dStride = dw - actualW
|
|
63
|
+
const mStride = mPitch - actualW
|
|
64
|
+
|
|
65
|
+
// Pre-calculate the source color with global alpha
|
|
66
|
+
const baseSrcColor = color
|
|
67
|
+
const baseSrcAlpha = (baseSrcColor >>> 24)
|
|
68
|
+
|
|
69
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
70
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
71
|
+
|
|
72
|
+
// Early exit if source pixel is already transparent
|
|
73
|
+
if (baseSrcAlpha === 0) {
|
|
74
|
+
dIdx++
|
|
75
|
+
mIdx++
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let weight = globalAlpha
|
|
80
|
+
|
|
81
|
+
if (mask) {
|
|
82
|
+
const mVal = mask[mIdx]
|
|
83
|
+
|
|
84
|
+
if (isAlphaMask) {
|
|
85
|
+
const effectiveM = invertMask
|
|
86
|
+
? 255 - mVal
|
|
87
|
+
: mVal
|
|
88
|
+
|
|
89
|
+
// If mask is transparent, skip
|
|
90
|
+
if (effectiveM === 0) {
|
|
91
|
+
dIdx++
|
|
92
|
+
mIdx++
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// globalAlpha is not a factor
|
|
97
|
+
if (globalAlpha === 255) {
|
|
98
|
+
weight = effectiveM
|
|
99
|
+
// mask is not a factor
|
|
100
|
+
} else if (effectiveM === 255) {
|
|
101
|
+
weight = globalAlpha
|
|
102
|
+
} else {
|
|
103
|
+
// use rounding-corrected multiplication
|
|
104
|
+
weight = (effectiveM * globalAlpha + 128) >> 8
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
const isHit = invertMask
|
|
108
|
+
? mVal === 0
|
|
109
|
+
: mVal === 1
|
|
110
|
+
|
|
111
|
+
if (!isHit) {
|
|
112
|
+
dIdx++
|
|
113
|
+
mIdx++
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
weight = globalAlpha
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Final safety check for weight (can be 0 if globalAlpha or alphaMask rounds down)
|
|
121
|
+
if (weight === 0) {
|
|
122
|
+
dIdx++
|
|
123
|
+
mIdx++
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Apply Weight to Source Alpha
|
|
129
|
+
let currentSrcAlpha = baseSrcAlpha
|
|
130
|
+
let currentSrcColor = baseSrcColor
|
|
131
|
+
|
|
132
|
+
if (weight < 255) {
|
|
133
|
+
if (baseSrcAlpha === 255) {
|
|
134
|
+
currentSrcAlpha = weight
|
|
135
|
+
} else {
|
|
136
|
+
currentSrcAlpha = (baseSrcAlpha * weight + 128) >> 8
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (currentSrcAlpha === 0) {
|
|
140
|
+
dIdx++
|
|
141
|
+
mIdx++
|
|
142
|
+
continue
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
currentSrcColor = ((baseSrcColor & 0x00ffffff) | (currentSrcAlpha << 24)) >>> 0 as Color32
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx] as Color32)
|
|
149
|
+
|
|
150
|
+
dIdx++
|
|
151
|
+
mIdx++
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
dIdx += dStride
|
|
155
|
+
mIdx += mStride
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { type Color32, MaskType, type PixelBlendOptions } from '../_types'
|
|
2
|
+
import { sourceOverColor32 } from '../blend-modes'
|
|
3
|
+
import type { PixelData } from '../PixelData'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Blits source PixelData into a destination PixelData using 32-bit integer bitwise blending.
|
|
7
|
+
* This function bypasses standard ImageData limitations by operating directly on
|
|
8
|
+
* Uint32Array views. It supports various blend modes, binary/alpha masking, and
|
|
9
|
+
* automatic clipping of both source and destination bounds.
|
|
10
|
+
* @example
|
|
11
|
+
*
|
|
12
|
+
* const dst = new PixelData(ctx.getImageData(0,0,100,100))
|
|
13
|
+
* blendImageData32(dst, sprite, {
|
|
14
|
+
* blendFn: COLOR_32_BLEND_MODES.multiply,
|
|
15
|
+
* mask: brushMask,
|
|
16
|
+
* maskType: MaskType.ALPHA
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export function blendPixelData(
|
|
20
|
+
dst: PixelData,
|
|
21
|
+
src: PixelData,
|
|
22
|
+
opts: PixelBlendOptions,
|
|
23
|
+
) {
|
|
24
|
+
const {
|
|
25
|
+
x: targetX = 0,
|
|
26
|
+
y: targetY = 0,
|
|
27
|
+
sx: sourceX = 0,
|
|
28
|
+
sy: sourceY = 0,
|
|
29
|
+
w: width = src.width,
|
|
30
|
+
h: height = src.height,
|
|
31
|
+
alpha: globalAlpha = 255,
|
|
32
|
+
blendFn = sourceOverColor32,
|
|
33
|
+
mask,
|
|
34
|
+
maskType = MaskType.ALPHA,
|
|
35
|
+
mw,
|
|
36
|
+
mx = 0,
|
|
37
|
+
my = 0,
|
|
38
|
+
invertMask = false,
|
|
39
|
+
} = opts
|
|
40
|
+
|
|
41
|
+
if (globalAlpha === 0) return
|
|
42
|
+
|
|
43
|
+
let x = targetX
|
|
44
|
+
let y = targetY
|
|
45
|
+
let sx = sourceX
|
|
46
|
+
let sy = sourceY
|
|
47
|
+
let w = width
|
|
48
|
+
let h = height
|
|
49
|
+
|
|
50
|
+
// 1. Source Clipping
|
|
51
|
+
if (sx < 0) {
|
|
52
|
+
x -= sx
|
|
53
|
+
w += sx
|
|
54
|
+
sx = 0
|
|
55
|
+
}
|
|
56
|
+
if (sy < 0) {
|
|
57
|
+
y -= sy
|
|
58
|
+
h += sy
|
|
59
|
+
sy = 0
|
|
60
|
+
}
|
|
61
|
+
w = Math.min(w, src.width - sx)
|
|
62
|
+
h = Math.min(h, src.height - sy)
|
|
63
|
+
|
|
64
|
+
// 2. Destination Clipping
|
|
65
|
+
if (x < 0) {
|
|
66
|
+
sx -= x
|
|
67
|
+
w += x
|
|
68
|
+
x = 0
|
|
69
|
+
}
|
|
70
|
+
if (y < 0) {
|
|
71
|
+
sy -= y
|
|
72
|
+
h += y
|
|
73
|
+
y = 0
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const actualW = Math.min(w, dst.width - x)
|
|
77
|
+
const actualH = Math.min(h, dst.height - y)
|
|
78
|
+
|
|
79
|
+
if (actualW <= 0 || actualH <= 0) return
|
|
80
|
+
|
|
81
|
+
const dst32 = dst.data32
|
|
82
|
+
const src32 = src.data32
|
|
83
|
+
const dw = dst.width
|
|
84
|
+
const sw = src.width
|
|
85
|
+
const mPitch = mw ?? width
|
|
86
|
+
const isAlphaMask = maskType === MaskType.ALPHA
|
|
87
|
+
|
|
88
|
+
const dx = x - targetX
|
|
89
|
+
const dy = y - targetY
|
|
90
|
+
|
|
91
|
+
let dIdx = y * dw + x
|
|
92
|
+
let sIdx = sy * sw + sx
|
|
93
|
+
let mIdx = (my + dy) * mPitch + (mx + dx)
|
|
94
|
+
|
|
95
|
+
const dStride = dw - actualW
|
|
96
|
+
const sStride = sw - actualW
|
|
97
|
+
const mStride = mPitch - actualW
|
|
98
|
+
|
|
99
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
100
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
101
|
+
const baseSrcColor = src32[sIdx] as Color32
|
|
102
|
+
const baseSrcAlpha = (baseSrcColor >>> 24)
|
|
103
|
+
|
|
104
|
+
// Early exit if source pixel is already transparent
|
|
105
|
+
if (baseSrcAlpha === 0) {
|
|
106
|
+
dIdx++
|
|
107
|
+
sIdx++
|
|
108
|
+
mIdx++
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let weight = globalAlpha
|
|
113
|
+
|
|
114
|
+
if (mask) {
|
|
115
|
+
const mVal = mask[mIdx]
|
|
116
|
+
|
|
117
|
+
if (isAlphaMask) {
|
|
118
|
+
const effectiveM = invertMask
|
|
119
|
+
? 255 - mVal
|
|
120
|
+
: mVal
|
|
121
|
+
|
|
122
|
+
// If mask is transparent, skip
|
|
123
|
+
if (effectiveM === 0) {
|
|
124
|
+
dIdx++
|
|
125
|
+
sIdx++
|
|
126
|
+
mIdx++
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// globalAlpha is not a factor
|
|
131
|
+
if (globalAlpha === 255) {
|
|
132
|
+
weight = effectiveM
|
|
133
|
+
// mask is not a factor
|
|
134
|
+
} else if (effectiveM === 255) {
|
|
135
|
+
weight = globalAlpha
|
|
136
|
+
} else {
|
|
137
|
+
// use rounding-corrected multiplication
|
|
138
|
+
weight = (effectiveM * globalAlpha + 128) >> 8
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
const isHit = invertMask
|
|
142
|
+
? mVal === 0
|
|
143
|
+
: mVal === 1
|
|
144
|
+
|
|
145
|
+
if (!isHit) {
|
|
146
|
+
dIdx++
|
|
147
|
+
sIdx++
|
|
148
|
+
mIdx++
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
weight = globalAlpha
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Final safety check for weight (can be 0 if globalAlpha or alphaMask rounds down)
|
|
156
|
+
if (weight === 0) {
|
|
157
|
+
dIdx++
|
|
158
|
+
sIdx++
|
|
159
|
+
mIdx++
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Apply Weight to Source Alpha
|
|
165
|
+
let currentSrcAlpha = baseSrcAlpha
|
|
166
|
+
let currentSrcColor = baseSrcColor
|
|
167
|
+
|
|
168
|
+
if (weight < 255) {
|
|
169
|
+
if (baseSrcAlpha === 255) {
|
|
170
|
+
currentSrcAlpha = weight
|
|
171
|
+
} else {
|
|
172
|
+
currentSrcAlpha = (baseSrcAlpha * weight + 128) >> 8
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (currentSrcAlpha === 0) {
|
|
176
|
+
dIdx++
|
|
177
|
+
sIdx++
|
|
178
|
+
mIdx++
|
|
179
|
+
continue
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
currentSrcColor = ((baseSrcColor & 0x00ffffff) | (currentSrcAlpha << 24)) >>> 0 as Color32
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx] as Color32)
|
|
186
|
+
|
|
187
|
+
dIdx++
|
|
188
|
+
sIdx++
|
|
189
|
+
mIdx++
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
dIdx += dStride
|
|
193
|
+
sIdx += sStride
|
|
194
|
+
mIdx += mStride
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Color32, Rect } from '../_types'
|
|
2
|
+
import type { PixelData } from '../PixelData'
|
|
3
|
+
import { fillPixelData } from './fillPixelData'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Clears a region of the PixelData to transparent (0x00000000).
|
|
7
|
+
* Internally uses the optimized fillPixelData.
|
|
8
|
+
*/
|
|
9
|
+
export function clearPixelData(
|
|
10
|
+
dst: PixelData,
|
|
11
|
+
rect?: Partial<Rect>,
|
|
12
|
+
): void {
|
|
13
|
+
fillPixelData(dst, 0 as Color32, rect)
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Color32, Rect } from '../_types'
|
|
2
|
+
import type { PixelData } from '../PixelData'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A high-performance solid fill for PixelData.
|
|
6
|
+
*/
|
|
7
|
+
export function fillPixelData(
|
|
8
|
+
dst: PixelData,
|
|
9
|
+
color: Color32,
|
|
10
|
+
rect?: Partial<Rect>,
|
|
11
|
+
): void {
|
|
12
|
+
const {
|
|
13
|
+
x: targetX = 0,
|
|
14
|
+
y: targetY = 0,
|
|
15
|
+
w: width = dst.width,
|
|
16
|
+
h: height = dst.height,
|
|
17
|
+
} = rect || {}
|
|
18
|
+
|
|
19
|
+
let x = targetX
|
|
20
|
+
let y = targetY
|
|
21
|
+
let w = width
|
|
22
|
+
let h = height
|
|
23
|
+
|
|
24
|
+
// Destination Clipping
|
|
25
|
+
if (x < 0) {
|
|
26
|
+
w += x
|
|
27
|
+
x = 0
|
|
28
|
+
}
|
|
29
|
+
if (y < 0) {
|
|
30
|
+
h += y
|
|
31
|
+
y = 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const actualW = Math.min(w, dst.width - x)
|
|
35
|
+
const actualH = Math.min(h, dst.height - y)
|
|
36
|
+
|
|
37
|
+
if (actualW <= 0 || actualH <= 0) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const dst32 = dst.data32
|
|
42
|
+
const dw = dst.width
|
|
43
|
+
|
|
44
|
+
// Optimization: If filling the entire buffer, use the native .fill()
|
|
45
|
+
if (actualW === dw && actualH === dst.height && x === 0 && y === 0) {
|
|
46
|
+
dst32.fill(color)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Row-by-row fill for partial rectangles
|
|
51
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
52
|
+
const start = (y + iy) * dw + x
|
|
53
|
+
const end = start + actualW
|
|
54
|
+
dst32.fill(color, start, end)
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/PixelData.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ImageDataLike } from './_types'
|
|
2
|
+
|
|
3
|
+
export class PixelData {
|
|
4
|
+
public readonly data32: Uint32Array
|
|
5
|
+
public readonly width: number
|
|
6
|
+
public readonly height: number
|
|
7
|
+
|
|
8
|
+
constructor(public readonly imageData: ImageDataLike) {
|
|
9
|
+
this.width = imageData.width
|
|
10
|
+
this.height = imageData.height
|
|
11
|
+
|
|
12
|
+
// Create the view once.
|
|
13
|
+
// Shift right by 2 is a fast bitwise division by 4.
|
|
14
|
+
this.data32 = new Uint32Array(
|
|
15
|
+
imageData.data.buffer,
|
|
16
|
+
imageData.data.byteOffset,
|
|
17
|
+
imageData.data.byteLength >> 2,
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/_types.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/** ALL values are 0-255 (including alpha which in CSS is 0-1) */
|
|
2
2
|
export type RGBA = { r: number, g: number, b: number, a: number }
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** Represents a 32-bit color in 0xAABBGGRR (Little endian) */
|
|
5
5
|
export type Color32 = number & { readonly __brandColor32: unique symbol }
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* A function that defines how to combine a source color with a destination color.
|
|
9
|
+
* @param src - The incoming color (source).
|
|
10
|
+
* @param dst - The existing color in the buffer (destination).
|
|
11
|
+
* @returns The resulting 32-bit color to be written to the buffer.
|
|
12
|
+
*/
|
|
7
13
|
export type BlendColor32 = (src: Color32, dst: Color32) => Color32
|
|
8
14
|
|
|
9
15
|
export type ImageDataLike = {
|
|
@@ -20,25 +26,127 @@ export type SerializedImageData = {
|
|
|
20
26
|
|
|
21
27
|
export type Base64EncodedUInt8Array = string & { readonly __brandBase64UInt8Array: unique symbol }
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
/** Rectangle definition */
|
|
30
|
+
export type Rect = {
|
|
31
|
+
x: number
|
|
32
|
+
y: number
|
|
33
|
+
w: number
|
|
34
|
+
h: number
|
|
35
|
+
}
|
|
24
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Defines how mask values should be interpreted during a draw operation.
|
|
39
|
+
*/
|
|
25
40
|
export enum MaskType {
|
|
41
|
+
/**
|
|
42
|
+
* Values are treated as alpha weights.
|
|
43
|
+
* 0 is skipped, values > 0 are processed.
|
|
44
|
+
*/
|
|
26
45
|
ALPHA,
|
|
46
|
+
/**
|
|
47
|
+
* Values are treated as on/off.
|
|
48
|
+
* 0 is fully transparent (skipped), any other value is fully opaque.
|
|
49
|
+
*/
|
|
27
50
|
BINARY
|
|
28
51
|
}
|
|
29
52
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
/** Strictly 0 or 1 */
|
|
54
|
+
export type BinaryMask = Uint8Array & { readonly __brand: 'Binary' }
|
|
55
|
+
/** Strictly 0-255 */
|
|
56
|
+
export type AlphaMask = Uint8Array & { readonly __brand: 'Alpha' }
|
|
57
|
+
|
|
58
|
+
export type AnyMask = BinaryMask | AlphaMask
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Configuration for pixel manipulation operations.
|
|
62
|
+
* Designed to be used by spreading a Rect object ({x, y, w, h}) directly.
|
|
63
|
+
*/
|
|
64
|
+
export interface PixelOptions {
|
|
65
|
+
/**
|
|
66
|
+
* The starting X coordinate in the destination buffer.
|
|
67
|
+
* @Defaults 0.
|
|
68
|
+
* */
|
|
69
|
+
x?: number
|
|
70
|
+
/**
|
|
71
|
+
* The starting Y coordinate in the destination buffer.
|
|
72
|
+
* @Default 0.
|
|
73
|
+
* */
|
|
74
|
+
y?: number
|
|
75
|
+
/**
|
|
76
|
+
* The width of the region to process.
|
|
77
|
+
* @Default Source width.
|
|
78
|
+
* */
|
|
79
|
+
w?: number
|
|
80
|
+
/**
|
|
81
|
+
* The height of the region to process.
|
|
82
|
+
* @Default Source height.
|
|
83
|
+
* */
|
|
84
|
+
h?: number
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Overall layer opacity 0-255.
|
|
88
|
+
* @default 255
|
|
89
|
+
*/
|
|
90
|
+
alpha?: number
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Mask width.
|
|
94
|
+
* @default w
|
|
95
|
+
* */
|
|
96
|
+
mw?: number
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* X offset into the mask buffer.
|
|
100
|
+
* @default 0
|
|
101
|
+
* */
|
|
102
|
+
mx?: number
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Y offset into the mask buffer.
|
|
106
|
+
* @default 0
|
|
107
|
+
* */
|
|
108
|
+
my?: number
|
|
109
|
+
|
|
110
|
+
/** An optional mask to restrict where pixels are written. */
|
|
111
|
+
mask?: AnyMask | null
|
|
112
|
+
|
|
113
|
+
/** The interpretation logic for the provided mask. Defaults to MaskType.Binary. */
|
|
114
|
+
maskType?: MaskType
|
|
115
|
+
|
|
116
|
+
/** If true the inverse of the mask will be applied */
|
|
117
|
+
invertMask?: boolean
|
|
34
118
|
}
|
|
35
119
|
|
|
36
|
-
|
|
37
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Configuration for blitting (copying/blending) one image into another.
|
|
122
|
+
*/
|
|
123
|
+
export interface PixelBlendOptions extends PixelOptions {
|
|
124
|
+
/**
|
|
125
|
+
* The source rectangle x-coordinate
|
|
126
|
+
* @default 0
|
|
127
|
+
*/
|
|
128
|
+
sx?: number
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The source rectangle y-coordinate
|
|
132
|
+
* @default 0
|
|
133
|
+
*/
|
|
134
|
+
sy?: number
|
|
135
|
+
|
|
136
|
+
/** The specific blending function/algorithm to use for pixel math. */
|
|
137
|
+
blendFn?: BlendColor32
|
|
38
138
|
}
|
|
39
139
|
|
|
40
|
-
|
|
41
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Configuration for operations that require color blending.
|
|
142
|
+
*/
|
|
143
|
+
export interface ColorBlendOptions extends PixelOptions {
|
|
144
|
+
/** The blending logic used to combine source and destination pixels. */
|
|
145
|
+
blendFn?: BlendColor32
|
|
42
146
|
}
|
|
43
147
|
|
|
44
|
-
export type
|
|
148
|
+
export type ApplyMaskOptions = Omit<PixelOptions, 'mask'>
|
|
149
|
+
|
|
150
|
+
// export function invertBinaryMask(dst: BinaryMask): void
|
|
151
|
+
// export function invertAlphaMask(dst: AlphaMask): void
|
|
152
|
+
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './ImageData/blend-modes'
|
|
2
|
-
export * from './ImageData/blit'
|
|
3
|
-
export * from './ImageData/mask'
|
|
4
|
-
export * from './ImageData/read-write-pixels'
|
|
5
|
-
export * from './ImageData/serialization'
|
|
6
1
|
export * from './_types'
|
|
2
|
+
export * from './blend-modes'
|
|
7
3
|
export * from './color'
|
|
4
|
+
export * from './ImageData/copyImageData'
|
|
5
|
+
export * from './ImageData/extractImageData'
|
|
6
|
+
export * from './ImageData/serialization'
|
|
7
|
+
export * from './PixelData/blendPixelData'
|