pixel-data-js 0.35.0 → 0.36.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 +157 -31
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +24 -12
- package/dist/index.prod.js +153 -30
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/History/PixelAccumulator.ts +27 -6
- 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 +2 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +2 -0
- package/src/History/PixelMutator/mutatorBlendMask.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +1 -0
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +1 -0
- package/src/History/PixelMutator/mutatorClear.ts +2 -1
- package/src/History/PixelMutator/mutatorFill.ts +53 -37
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +2 -1
- package/src/History/PixelMutator/mutatorInvert.ts +3 -2
- package/src/History/PixelMutator.ts +1 -2
- package/src/Paint/Render/PaintCursorRenderer.ts +9 -0
- package/src/PixelData/_pixelData-types.ts +7 -0
- package/src/PixelData/cropPixelData.ts +36 -0
- package/src/PixelData/fillPixelData.ts +6 -6
- package/src/PixelData/trimPixelData.ts +49 -0
- package/src/index.ts +2 -0
package/package.json
CHANGED
|
@@ -26,9 +26,17 @@ export class PixelAccumulator {
|
|
|
26
26
|
* @param x pixel x coordinate
|
|
27
27
|
* @param y pixel y coordinate
|
|
28
28
|
*/
|
|
29
|
-
storePixelBeforeState(x: number, y: number): DidChangeFn {
|
|
29
|
+
storePixelBeforeState(x: number, y: number): DidChangeFn | null {
|
|
30
30
|
const shift = this.config.tileShift
|
|
31
31
|
const columns = this.config.targetColumns
|
|
32
|
+
const targetWidth = this.config.target.w
|
|
33
|
+
const targetHeight = this.config.target.h
|
|
34
|
+
|
|
35
|
+
// Return a no-op if the pixel is outside the target boundaries
|
|
36
|
+
if (x < 0 || x >= targetWidth || y < 0 || y >= targetHeight) {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
const tx = x >> shift
|
|
33
41
|
const ty = y >> shift
|
|
34
42
|
const id = ty * columns + tx
|
|
@@ -66,14 +74,27 @@ export class PixelAccumulator {
|
|
|
66
74
|
y: number,
|
|
67
75
|
w: number,
|
|
68
76
|
h: number,
|
|
69
|
-
): DidChangeFn {
|
|
77
|
+
): DidChangeFn | null {
|
|
70
78
|
const shift = this.config.tileShift
|
|
71
79
|
const columns = this.config.targetColumns
|
|
80
|
+
const targetWidth = this.config.target.w
|
|
81
|
+
const targetHeight = this.config.target.h
|
|
82
|
+
|
|
83
|
+
// Clamp the bounding box to the actual canvas dimensions
|
|
84
|
+
const clipX1 = Math.max(0, x)
|
|
85
|
+
const clipY1 = Math.max(0, y)
|
|
86
|
+
const clipX2 = Math.min(targetWidth - 1, x + w - 1)
|
|
87
|
+
const clipY2 = Math.min(targetHeight - 1, y + h - 1)
|
|
88
|
+
|
|
89
|
+
// If the region is entirely off-canvas, return a no-op
|
|
90
|
+
if (clipX2 < clipX1 || clipY2 < clipY1) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
72
93
|
|
|
73
|
-
const startX =
|
|
74
|
-
const startY =
|
|
75
|
-
const endX =
|
|
76
|
-
const endY =
|
|
94
|
+
const startX = clipX1 >> shift
|
|
95
|
+
const startY = clipY1 >> shift
|
|
96
|
+
const endX = clipX2 >> shift
|
|
97
|
+
const endY = clipY2 >> shift
|
|
77
98
|
|
|
78
99
|
const startIndex = this.beforeTiles.length
|
|
79
100
|
|
|
@@ -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),
|
|
@@ -25,6 +25,8 @@ export const mutatorBlendColor = ((writer: PixelWriter<any>, deps: Deps = defaul
|
|
|
25
25
|
const h = opts?.h ?? target.h
|
|
26
26
|
|
|
27
27
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
28
|
+
if (!didChange) return false
|
|
29
|
+
|
|
28
30
|
return didChange(
|
|
29
31
|
blendColorPixelData(target, color, opts),
|
|
30
32
|
)
|
|
@@ -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
|
|
@@ -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
|
|
@@ -41,6 +41,7 @@ export const mutatorBlendColorPaintMask = ((writer: PixelWriter<any>, deps: Part
|
|
|
41
41
|
const ty = y + mask.centerOffsetY
|
|
42
42
|
|
|
43
43
|
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h)
|
|
44
|
+
if (!didChange) return false
|
|
44
45
|
|
|
45
46
|
OPTS.x = tx
|
|
46
47
|
OPTS.y = ty
|
|
@@ -43,6 +43,8 @@ export const mutatorBlendColorPaintRect = ((writer: PixelWriter<any>, deps: Deps
|
|
|
43
43
|
OPTS.alpha = alpha
|
|
44
44
|
|
|
45
45
|
const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight)
|
|
46
|
+
if (!didChange) return false
|
|
47
|
+
|
|
46
48
|
return didChange(
|
|
47
49
|
blendColorPixelData(
|
|
48
50
|
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(
|
|
@@ -23,6 +23,7 @@ export const mutatorBlendPixel = ((writer: PixelWriter<any>, deps: Partial<Deps>
|
|
|
23
23
|
): boolean {
|
|
24
24
|
|
|
25
25
|
const didChange = writer.accumulator.storePixelBeforeState(x, y)
|
|
26
|
+
if (!didChange) return false
|
|
26
27
|
|
|
27
28
|
return didChange(
|
|
28
29
|
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),
|
|
@@ -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
|
)
|
|
@@ -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>
|
|
@@ -20,8 +20,9 @@ export const mutatorFillBinaryMask = ((writer: PixelWriter<any>, deps: Deps = de
|
|
|
20
20
|
mask: BinaryMask,
|
|
21
21
|
x = 0,
|
|
22
22
|
y = 0,
|
|
23
|
-
) {
|
|
23
|
+
): boolean {
|
|
24
24
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h)
|
|
25
|
+
if (!didChange) return false
|
|
25
26
|
return didChange(
|
|
26
27
|
fillPixelDataBinaryMask(writer.config.target, color, mask, x, y),
|
|
27
28
|
)
|
|
@@ -14,7 +14,7 @@ export const mutatorInvert = ((writer: PixelWriter<any>, deps: Deps = defaults)
|
|
|
14
14
|
} = deps
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
|
-
invert(opts?: PixelMutateOptions) {
|
|
17
|
+
invert(opts?: PixelMutateOptions): boolean {
|
|
18
18
|
const target = writer.config.target
|
|
19
19
|
const x = opts?.x ?? 0
|
|
20
20
|
const y = opts?.y ?? 0
|
|
@@ -22,8 +22,9 @@ export const mutatorInvert = ((writer: PixelWriter<any>, deps: Deps = defaults)
|
|
|
22
22
|
const h = opts?.h ?? target.h
|
|
23
23
|
|
|
24
24
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h)
|
|
25
|
+
if (!didChange) return false
|
|
25
26
|
|
|
26
|
-
return didChange(
|
|
27
|
+
return didChange?.(
|
|
27
28
|
invertPixelData(target, opts),
|
|
28
29
|
)
|
|
29
30
|
},
|
|
@@ -12,7 +12,7 @@ import { mutatorBlendMask } from './PixelMutator/mutatorBlendMask'
|
|
|
12
12
|
import { mutatorBlendPixel } from './PixelMutator/mutatorBlendPixel'
|
|
13
13
|
import { mutatorBlendPixelData } from './PixelMutator/mutatorBlendPixelData'
|
|
14
14
|
import { mutatorClear } from './PixelMutator/mutatorClear'
|
|
15
|
-
import { mutatorFill
|
|
15
|
+
import { mutatorFill } from './PixelMutator/mutatorFill'
|
|
16
16
|
import { mutatorFillBinaryMask } from './PixelMutator/mutatorFillBinaryMask'
|
|
17
17
|
import { mutatorInvert } from './PixelMutator/mutatorInvert'
|
|
18
18
|
import type { PixelWriter } from './PixelWriter'
|
|
@@ -36,7 +36,6 @@ export function makeFullPixelMutator(writer: PixelWriter<any>) {
|
|
|
36
36
|
...mutatorClear(writer),
|
|
37
37
|
...mutatorFill(writer),
|
|
38
38
|
...mutatorFillBinaryMask(writer),
|
|
39
|
-
...mutatorFillRect(writer),
|
|
40
39
|
...mutatorInvert(writer),
|
|
41
40
|
}
|
|
42
41
|
}
|
|
@@ -103,6 +103,14 @@ export function makePaintCursorRenderer<T extends HTMLCanvasElement | OffscreenC
|
|
|
103
103
|
drawCtx.drawImage(canvas, Math.floor(dx), Math.floor(dy))
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
function drawRaw(
|
|
107
|
+
drawCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
|
108
|
+
x: number,
|
|
109
|
+
y: number,
|
|
110
|
+
) {
|
|
111
|
+
drawCtx.drawImage(canvas, Math.floor(x * _scale), Math.floor(y * _scale))
|
|
112
|
+
}
|
|
113
|
+
|
|
106
114
|
function getSettings() {
|
|
107
115
|
return {
|
|
108
116
|
color: _color,
|
|
@@ -116,6 +124,7 @@ export function makePaintCursorRenderer<T extends HTMLCanvasElement | OffscreenC
|
|
|
116
124
|
getBounds,
|
|
117
125
|
getBoundsScaled: getOutlineBoundsScaled,
|
|
118
126
|
draw,
|
|
127
|
+
drawRaw,
|
|
119
128
|
getSettings,
|
|
120
129
|
}
|
|
121
130
|
}
|
|
@@ -15,3 +15,10 @@ export interface MutablePixelData32 {
|
|
|
15
15
|
export interface PixelData<T extends ImageDataLike = ImageData> extends PixelData32 {
|
|
16
16
|
readonly imageData: T
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
export interface MutablePixelData<T extends ImageDataLike = ImageData> extends PixelData32 {
|
|
20
|
+
imageData: T
|
|
21
|
+
data: Uint32Array
|
|
22
|
+
w: number
|
|
23
|
+
h: number
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MutablePixelData, PixelData, PixelData32 } from './_pixelData-types'
|
|
2
|
+
import { setPixelData } from './PixelData'
|
|
3
|
+
|
|
4
|
+
export function cropPixelData(src: PixelData32, x: number, y: number, w: number, h: number, out?: MutablePixelData): PixelData {
|
|
5
|
+
const cx = Math.max(x, 0)
|
|
6
|
+
const cy = Math.max(y, 0)
|
|
7
|
+
const cw = Math.min(x + w, src.w) - cx
|
|
8
|
+
const ch = Math.min(y + h, src.h) - cy
|
|
9
|
+
|
|
10
|
+
if (cw <= 0 || ch <= 0) {
|
|
11
|
+
throw new Error(`Crop [${x},${y} ${w}x${h}] does not overlap PixelData [${src.w}x${src.h}]`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const cropped = new ImageData(cw, ch)
|
|
15
|
+
|
|
16
|
+
let dst32: Uint32Array
|
|
17
|
+
if (out) {
|
|
18
|
+
setPixelData(out, cropped)
|
|
19
|
+
dst32 = out.data
|
|
20
|
+
} else {
|
|
21
|
+
dst32 = new Uint32Array(cropped.data.buffer)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (let row = 0; row < ch; row++) {
|
|
25
|
+
const srcOffset = ((cy + row) * src.w) + cx
|
|
26
|
+
const dstOffset = row * cw
|
|
27
|
+
dst32.set(src.data.subarray(srcOffset, srcOffset + cw), dstOffset)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return out ?? {
|
|
31
|
+
data: dst32,
|
|
32
|
+
imageData: cropped,
|
|
33
|
+
w: cw,
|
|
34
|
+
h: ch,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -47,16 +47,16 @@ export function fillPixelData(
|
|
|
47
47
|
let w: number
|
|
48
48
|
let h: number
|
|
49
49
|
|
|
50
|
-
if (typeof _x === '
|
|
51
|
-
x = _x.x ?? 0
|
|
52
|
-
y = _x.y ?? 0
|
|
53
|
-
w = _x.w ?? dstW
|
|
54
|
-
h = _x.h ?? dstH
|
|
55
|
-
} else if (typeof _x === 'number') {
|
|
50
|
+
if (typeof _x === 'number') {
|
|
56
51
|
x = _x
|
|
57
52
|
y = _y!
|
|
58
53
|
w = _w!
|
|
59
54
|
h = _h!
|
|
55
|
+
} else if (typeof _x === 'object') {
|
|
56
|
+
x = _x.x ?? 0
|
|
57
|
+
y = _x.y ?? 0
|
|
58
|
+
w = _x.w ?? dstW
|
|
59
|
+
h = _x.h ?? dstH
|
|
60
60
|
} else {
|
|
61
61
|
x = 0
|
|
62
62
|
y = 0
|
|
@@ -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
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -152,6 +152,7 @@ export * from './PixelData/blendPixelDataMask'
|
|
|
152
152
|
export * from './PixelData/blendPixelDataPaintBuffer'
|
|
153
153
|
export * from './PixelData/clearPixelDataFast'
|
|
154
154
|
export * from './PixelData/copyPixelData'
|
|
155
|
+
export * from './PixelData/cropPixelData'
|
|
155
156
|
export * from './PixelData/extractPixelData'
|
|
156
157
|
export * from './PixelData/extractPixelDataBuffer'
|
|
157
158
|
export * from './PixelData/fillPixelData'
|
|
@@ -165,6 +166,7 @@ export * from './PixelData/resamplePixelData'
|
|
|
165
166
|
export * from './PixelData/resizePixelData'
|
|
166
167
|
export * from './PixelData/ReusablePixelData'
|
|
167
168
|
export * from './PixelData/rotatePixelData'
|
|
169
|
+
export * from './PixelData/trimPixelData'
|
|
168
170
|
export * from './PixelData/uInt32ArrayToPixelData'
|
|
169
171
|
export * from './PixelData/writePaintBufferToPixelData'
|
|
170
172
|
export * from './PixelData/writePixelData'
|