pixel-data-js 0.24.0 → 0.25.2

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.
Files changed (72) hide show
  1. package/dist/index.dev.cjs +1476 -1834
  2. package/dist/index.dev.cjs.map +1 -1
  3. package/dist/index.dev.js +1465 -1816
  4. package/dist/index.dev.js.map +1 -1
  5. package/dist/index.prod.cjs +1475 -1833
  6. package/dist/index.prod.cjs.map +1 -1
  7. package/dist/index.prod.d.ts +233 -310
  8. package/dist/index.prod.js +1465 -1816
  9. package/dist/index.prod.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/Algorithm/floodFillSelection.ts +2 -2
  12. package/src/Canvas/canvas-blend-modes.ts +28 -0
  13. package/src/History/PixelAccumulator.ts +52 -29
  14. package/src/History/PixelEngineConfig.ts +7 -9
  15. package/src/History/PixelMutator/mutatorBlendPaintMask.ts +60 -0
  16. package/src/History/PixelMutator/mutatorBlendPixelData.ts +2 -2
  17. package/src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts +2 -2
  18. package/src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts +2 -2
  19. package/src/History/PixelMutator.ts +0 -20
  20. package/src/History/PixelPatchTiles.ts +2 -2
  21. package/src/History/PixelWriter.ts +132 -9
  22. package/src/Internal/helpers.ts +2 -0
  23. package/src/Paint/PaintBuffer.ts +269 -0
  24. package/src/{PixelTile/PaintBufferRenderer.ts → Paint/PaintBufferCanvasRenderer.ts} +13 -5
  25. package/src/Paint/makeCirclePaintAlphaMask.ts +41 -0
  26. package/src/{Mask/CircleBinaryMask.ts → Paint/makeCirclePaintBinaryMask.ts} +5 -6
  27. package/src/Paint/makePaintMask.ts +28 -0
  28. package/src/Paint/makeRectFalloffPaintAlphaMask.ts +47 -0
  29. package/src/PixelData/PixelBuffer32.ts +2 -2
  30. package/src/PixelData/PixelData.ts +1 -1
  31. package/src/PixelData/applyAlphaMaskToPixelData.ts +2 -2
  32. package/src/PixelData/applyBinaryMaskToPixelData.ts +2 -2
  33. package/src/PixelData/blendColorPixelData.ts +2 -2
  34. package/src/PixelData/blendColorPixelDataAlphaMask.ts +3 -3
  35. package/src/PixelData/blendColorPixelDataBinaryMask.ts +3 -3
  36. package/src/PixelData/blendPixel.ts +2 -2
  37. package/src/PixelData/blendPixelData.ts +3 -3
  38. package/src/PixelData/blendPixelDataAlphaMask.ts +3 -3
  39. package/src/PixelData/blendPixelDataBinaryMask.ts +3 -3
  40. package/src/PixelData/blendPixelDataPaintBuffer.ts +3 -3
  41. package/src/PixelData/clearPixelData.ts +2 -2
  42. package/src/PixelData/extractPixelData.ts +4 -4
  43. package/src/PixelData/extractPixelDataBuffer.ts +4 -4
  44. package/src/PixelData/fillPixelData.ts +5 -5
  45. package/src/PixelData/fillPixelDataBinaryMask.ts +3 -3
  46. package/src/PixelData/fillPixelDataFast.ts +5 -5
  47. package/src/PixelData/invertPixelData.ts +2 -2
  48. package/src/PixelData/pixelDataToAlphaMask.ts +2 -2
  49. package/src/PixelData/reflectPixelData.ts +3 -3
  50. package/src/PixelData/resamplePixelData.ts +2 -2
  51. package/src/PixelData/writePaintBufferToPixelData.ts +26 -0
  52. package/src/PixelData/writePixelDataBuffer.ts +5 -5
  53. package/src/Rect/trimMaskRectBounds.ts +121 -0
  54. package/src/Rect/trimRectBounds.ts +25 -116
  55. package/src/_types.ts +16 -15
  56. package/src/index.ts +11 -24
  57. package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +0 -182
  58. package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +0 -59
  59. package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +0 -172
  60. package/src/History/PixelMutator/mutatorApplyRectBrush.ts +0 -64
  61. package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +0 -184
  62. package/src/History/PixelMutator/mutatorApplyRectPencil.ts +0 -65
  63. package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +0 -166
  64. package/src/History/PixelMutator/mutatorBlendColorCircleMask.ts +0 -71
  65. package/src/Mask/CircleAlphaMask.ts +0 -32
  66. package/src/PixelData/applyRectBrushToPixelData.ts +0 -98
  67. package/src/PixelData/blendColorPixelDataCircleMask.ts +0 -92
  68. package/src/PixelTile/PaintBuffer.ts +0 -122
  69. package/src/Rect/getCircleBrushOrPencilBounds.ts +0 -43
  70. package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +0 -24
  71. package/src/Rect/getRectBrushOrPencilBounds.ts +0 -38
  72. package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +0 -26
@@ -1,4 +1,4 @@
1
- import type { IPixelData, Rect } from '../_types'
1
+ import type { IPixelData32, Rect } from '../_types'
2
2
  import { extractPixelDataBuffer } from './extractPixelDataBuffer'
3
3
  import { PixelData } from './PixelData'
4
4
 
@@ -6,10 +6,10 @@ import { PixelData } from './PixelData'
6
6
  * High-level extraction that returns a new PixelData instance.
7
7
  * Leverages extractPixelDataBuffer for optimized 32-bit memory moves.
8
8
  */
9
- export function extractPixelData(source: IPixelData, rect: Rect): PixelData
10
- export function extractPixelData(source: IPixelData, x: number, y: number, w: number, h: number): PixelData
9
+ export function extractPixelData(source: IPixelData32, rect: Rect): PixelData
10
+ export function extractPixelData(source: IPixelData32, x: number, y: number, w: number, h: number): PixelData
11
11
  export function extractPixelData(
12
- source: IPixelData,
12
+ source: IPixelData32,
13
13
  _x: Rect | number,
14
14
  _y?: number,
15
15
  _w?: number,
@@ -1,4 +1,4 @@
1
- import type { IPixelData, Rect } from '../_types'
1
+ import type { IPixelData32, Rect } from '../_types'
2
2
  import { makeClippedBlit, resolveBlitClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_BLIT = makeClippedBlit()
@@ -7,10 +7,10 @@ const SCRATCH_BLIT = makeClippedBlit()
7
7
  * Extracts a rectangular region of pixels from PixelData.
8
8
  * Returns a new Uint32Array containing the extracted pixels.
9
9
  */
10
- export function extractPixelDataBuffer(source: IPixelData, rect: Rect): Uint32Array
11
- export function extractPixelDataBuffer(source: IPixelData, x: number, y: number, w: number, h: number): Uint32Array
10
+ export function extractPixelDataBuffer(source: IPixelData32, rect: Rect): Uint32Array
11
+ export function extractPixelDataBuffer(source: IPixelData32, x: number, y: number, w: number, h: number): Uint32Array
12
12
  export function extractPixelDataBuffer(
13
- source: IPixelData,
13
+ source: IPixelData32,
14
14
  _x: Rect | number,
15
15
  _y?: number,
16
16
  _w?: number,
@@ -1,10 +1,10 @@
1
- import type { Color32, IPixelData, Rect } from '../_types'
1
+ import type { Color32, IPixelData32, Rect } from '../_types'
2
2
  import { makeClippedRect, resolveRectClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_RECT = makeClippedRect()
5
5
 
6
6
  /**
7
- * Fills a region or the {@link IPixelData} buffer with a solid color.
7
+ * Fills a region or the {@link IPixelData32} buffer with a solid color.
8
8
  *
9
9
  * @param dst - The target to modify.
10
10
  * @param color - The color to apply.
@@ -12,7 +12,7 @@ const SCRATCH_RECT = makeClippedRect()
12
12
  * @returns true if any pixels were actually modified.
13
13
  */
14
14
  export function fillPixelData(
15
- dst: IPixelData,
15
+ dst: IPixelData32,
16
16
  color: Color32,
17
17
  rect?: Partial<Rect>,
18
18
  ): boolean
@@ -25,7 +25,7 @@ export function fillPixelData(
25
25
  * @param h - Height of the fill area.
26
26
  */
27
27
  export function fillPixelData(
28
- dst: IPixelData,
28
+ dst: IPixelData32,
29
29
  color: Color32,
30
30
  x: number,
31
31
  y: number,
@@ -33,7 +33,7 @@ export function fillPixelData(
33
33
  h: number,
34
34
  ): boolean
35
35
  export function fillPixelData(
36
- dst: IPixelData,
36
+ dst: IPixelData32,
37
37
  color: Color32,
38
38
  _x?: Partial<Rect> | number,
39
39
  _y?: number,
@@ -1,10 +1,10 @@
1
- import type { BinaryMask, Color32, IPixelData } from '../_types'
1
+ import type { BinaryMask, Color32, IPixelData32 } from '../_types'
2
2
  import { makeClippedRect, resolveRectClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_RECT = makeClippedRect()
5
5
 
6
6
  /**
7
- * Fills a region of the {@link IPixelData} buffer with a solid color using a mask.
7
+ * Fills a region of the {@link IPixelData32} buffer with a solid color using a mask.
8
8
  * @param dst - The target to modify.
9
9
  * @param color - The color to apply.
10
10
  * @param mask - The mask defining the area to fill.
@@ -13,7 +13,7 @@ const SCRATCH_RECT = makeClippedRect()
13
13
  * @param y - Starting vertical coordinate for the mask placement.
14
14
  */
15
15
  export function fillPixelDataBinaryMask(
16
- dst: IPixelData,
16
+ dst: IPixelData32,
17
17
  color: Color32,
18
18
  mask: BinaryMask,
19
19
  alpha = 255,
@@ -1,10 +1,10 @@
1
- import type { Color32, IPixelData, Rect } from '../_types'
1
+ import type { Color32, IPixelData32, Rect } from '../_types'
2
2
  import { makeClippedRect, resolveRectClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_RECT = makeClippedRect()
5
5
 
6
6
  /**
7
- * Fills a region or the {@link IPixelData} buffer with a solid color.
7
+ * Fills a region or the {@link IPixelData32} buffer with a solid color.
8
8
  * This function is faster than {@link fillPixelData} but does not
9
9
  * return a boolean value indicating changes were made.
10
10
  *
@@ -14,7 +14,7 @@ const SCRATCH_RECT = makeClippedRect()
14
14
  * buffer is filled.
15
15
  */
16
16
  export function fillPixelDataFast(
17
- dst: IPixelData,
17
+ dst: IPixelData32,
18
18
  color: Color32,
19
19
  rect?: Partial<Rect>,
20
20
  ): void
@@ -27,7 +27,7 @@ export function fillPixelDataFast(
27
27
  * @param h - Height of the fill area.
28
28
  */
29
29
  export function fillPixelDataFast(
30
- dst: IPixelData,
30
+ dst: IPixelData32,
31
31
  color: Color32,
32
32
  x: number,
33
33
  y: number,
@@ -35,7 +35,7 @@ export function fillPixelDataFast(
35
35
  h: number,
36
36
  ): void
37
37
  export function fillPixelDataFast(
38
- dst: IPixelData,
38
+ dst: IPixelData32,
39
39
  color: Color32,
40
40
  _x?: Partial<Rect> | number,
41
41
  _y?: number,
@@ -1,10 +1,10 @@
1
- import { type IPixelData, type PixelMutateOptions } from '../_types'
1
+ import { type IPixelData32, type PixelMutateOptions } from '../_types'
2
2
  import { makeClippedRect, resolveRectClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_RECT = makeClippedRect()
5
5
 
6
6
  export function invertPixelData(
7
- pixelData: IPixelData,
7
+ pixelData: IPixelData32,
8
8
  opts: PixelMutateOptions = {},
9
9
  ): boolean {
10
10
  const dst = pixelData
@@ -1,4 +1,4 @@
1
- import type { AlphaMask, IPixelData } from '../_types'
1
+ import type { AlphaMask, IPixelData32 } from '../_types'
2
2
  import { makeAlphaMask } from '../Mask/AlphaMask'
3
3
 
4
4
  /**
@@ -6,7 +6,7 @@ import { makeAlphaMask } from '../Mask/AlphaMask'
6
6
  * Returns a Uint8Array branded as AlphaMask.
7
7
  */
8
8
  export function pixelDataToAlphaMask(
9
- pixelData: IPixelData,
9
+ pixelData: IPixelData32,
10
10
  ): AlphaMask {
11
11
  const {
12
12
  data32,
@@ -1,6 +1,6 @@
1
- import type { IPixelData } from '../_types'
1
+ import type { IPixelData32 } from '../_types'
2
2
 
3
- export function reflectPixelDataHorizontal(pixelData: IPixelData): void {
3
+ export function reflectPixelDataHorizontal(pixelData: IPixelData32): void {
4
4
  const width = pixelData.width
5
5
  const height = pixelData.height
6
6
  const data = pixelData.data32
@@ -20,7 +20,7 @@ export function reflectPixelDataHorizontal(pixelData: IPixelData): void {
20
20
  }
21
21
  }
22
22
 
23
- export function reflectPixelDataVertical(pixelData: IPixelData): void {
23
+ export function reflectPixelDataVertical(pixelData: IPixelData32): void {
24
24
  const width = pixelData.width
25
25
  const height = pixelData.height
26
26
  const data = pixelData.data32
@@ -1,4 +1,4 @@
1
- import { type IPixelData, PixelData } from '../index'
1
+ import { type IPixelData32, PixelData } from '../index'
2
2
  import { resample32 } from '../Internal/resample32'
3
3
 
4
4
  /**
@@ -6,7 +6,7 @@ import { resample32 } from '../Internal/resample32'
6
6
  * Factor > 1 upscales, Factor < 1 downscales.
7
7
  */
8
8
  export function resamplePixelData(
9
- pixelData: IPixelData,
9
+ pixelData: IPixelData32,
10
10
  factor: number,
11
11
  ): PixelData {
12
12
  const { data, width, height } = resample32(pixelData.data32, pixelData.width, pixelData.height, factor)
@@ -0,0 +1,26 @@
1
+ import type { IPixelData } from '../_types'
2
+ import type { PaintBuffer } from '../Paint/PaintBuffer'
3
+ import { writePixelDataBuffer } from './writePixelDataBuffer'
4
+
5
+ /**
6
+ * @param writePixelDataBufferFn - @hidden
7
+ */
8
+ export function writePaintBufferToPixelData(
9
+ target: IPixelData,
10
+ paintBuffer: PaintBuffer,
11
+ writePixelDataBufferFn = writePixelDataBuffer,
12
+ ) {
13
+ const tileShift = paintBuffer.config.tileShift
14
+ const lookup = paintBuffer.lookup
15
+
16
+ for (let i = 0; i < lookup.length; i++) {
17
+ const tile = lookup[i]
18
+
19
+ if (tile) {
20
+ const dx = tile.tx << tileShift
21
+ const dy = tile.ty << tileShift
22
+
23
+ writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height)
24
+ }
25
+ }
26
+ }
@@ -1,21 +1,21 @@
1
- import { type IPixelData, type Rect } from '../_types'
1
+ import { type IPixelData32, type Rect } from '../_types'
2
2
  import { makeClippedBlit, resolveBlitClipping } from '../Internal/resolveClipping'
3
3
 
4
4
  const SCRATCH_BLIT = makeClippedBlit()
5
5
 
6
6
  /**
7
- * Copies a pixel buffer into a specific region of a {@link IPixelData} object.
7
+ * Copies a pixel buffer into a specific region of a {@link IPixelData32} object.
8
8
  *
9
9
  * This function performs a direct memory copy from a {@link Uint32Array}
10
10
  * into the target buffer.
11
11
  */
12
12
  export function writePixelDataBuffer(
13
- target: IPixelData,
13
+ target: IPixelData32,
14
14
  data: Uint32Array,
15
15
  rect: Rect,
16
16
  ): void
17
17
  export function writePixelDataBuffer(
18
- target: IPixelData,
18
+ target: IPixelData32,
19
19
  data: Uint32Array,
20
20
  x: number,
21
21
  y: number,
@@ -23,7 +23,7 @@ export function writePixelDataBuffer(
23
23
  h: number,
24
24
  ): void
25
25
  export function writePixelDataBuffer(
26
- target: IPixelData,
26
+ target: IPixelData32,
27
27
  data: Uint32Array,
28
28
  _x: Rect | number,
29
29
  _y?: number,
@@ -0,0 +1,121 @@
1
+ import type { NullableMaskRect, Rect } from '../_types'
2
+ import { extractMaskBuffer } from '../Mask/extractMaskBuffer'
3
+
4
+ /**
5
+ * Intersects a target rectangle with a boundary, trimming dimensions and masks in-place.
6
+ * This utility calculates the axis-aligned intersection between the `target` and `bounds`.
7
+ * If the `target` includes a `mask` (as in a {@link NullableMaskRect}), the mask is physically
8
+ * cropped and re-aligned using `extractMaskBuffer` to match the new dimensions.
9
+ * @param target - The rectangle or selection object to be trimmed. **Note:** This object is mutated in-place.
10
+ * @param bounds - The boundary rectangle defining the maximum allowable area (e.g., canvas dimensions).
11
+ * @example
12
+ * const selection = { x: -10, y: -10, w: 50, h: 50, mask: new Uint8Array(2500) };
13
+ * const canvas = { x: 0, y: 0, w: 100, h: 100 };
14
+ * // Selection will be moved to (0,0) and resized to 40x40.
15
+ * // The mask is cropped by 10 px on the top and left.
16
+ * trimRectBounds(selection, canvas);
17
+ */
18
+ export function trimMaskRectBounds<T extends NullableMaskRect>(
19
+ target: T,
20
+ bounds: Rect,
21
+ ): void {
22
+ const originalX = target.x
23
+ const originalY = target.y
24
+ const originalW = target.w
25
+
26
+ const intersectedX = Math.max(target.x, bounds.x)
27
+ const intersectedY = Math.max(target.y, bounds.y)
28
+
29
+ const intersectedMaxX = Math.min(
30
+ target.x + target.w,
31
+ bounds.x + bounds.w,
32
+ )
33
+ const intersectedMaxY = Math.min(
34
+ target.y + target.h,
35
+ bounds.y + bounds.h,
36
+ )
37
+
38
+ // Intersection check
39
+ if (intersectedMaxX <= intersectedX || intersectedMaxY <= intersectedY) {
40
+ target.w = 0
41
+ target.h = 0
42
+
43
+ if ('data' in target && target.data) {
44
+ target.data = new Uint8Array(0)
45
+ }
46
+
47
+ return
48
+ }
49
+
50
+ const intersectedW = intersectedMaxX - intersectedX
51
+ const intersectedH = intersectedMaxY - intersectedY
52
+ const offsetX = intersectedX - originalX
53
+ const offsetY = intersectedY - originalY
54
+
55
+ target.x = intersectedX
56
+ target.y = intersectedY
57
+ target.w = intersectedW
58
+ target.h = intersectedH
59
+
60
+ if ('data' in target && target.data) {
61
+ const currentMaskBuffer = extractMaskBuffer(
62
+ target.data,
63
+ originalW,
64
+ offsetX,
65
+ offsetY,
66
+ intersectedW,
67
+ intersectedH,
68
+ )
69
+
70
+ let minX = intersectedW
71
+ let maxX = -1
72
+ let minY = intersectedH
73
+ let maxY = -1
74
+
75
+ // Scan for content
76
+ for (let y = 0; y < intersectedH; y++) {
77
+ for (let x = 0; x < intersectedW; x++) {
78
+ if (currentMaskBuffer[y * intersectedW + x] !== 0) {
79
+ if (x < minX) minX = x
80
+ if (x > maxX) maxX = x
81
+ if (y < minY) minY = y
82
+ if (y > maxY) maxY = y
83
+ }
84
+ }
85
+ }
86
+
87
+ // If no content is found (all zeros)
88
+ if (maxX === -1) {
89
+ target.w = 0
90
+ target.h = 0
91
+ target.data = new Uint8Array(0)
92
+
93
+ return
94
+ }
95
+
96
+ const finalW = maxX - minX + 1
97
+ const finalH = maxY - minY + 1
98
+
99
+ // Only shift and crop if the content is smaller than the intersection
100
+ if (finalW !== intersectedW || finalH !== intersectedH) {
101
+ const newMaskBuffer = extractMaskBuffer(
102
+ currentMaskBuffer,
103
+ intersectedW,
104
+ minX,
105
+ minY,
106
+ finalW,
107
+ finalH,
108
+ )
109
+
110
+ target.x += minX
111
+ target.y += minY
112
+ target.w = finalW
113
+ target.h = finalH
114
+ target.data = newMaskBuffer
115
+ } else {
116
+ target.w = finalW
117
+ target.h = finalH
118
+ target.data = currentMaskBuffer
119
+ }
120
+ }
121
+ }
@@ -1,121 +1,30 @@
1
- import type { NullableMaskRect, Rect } from '../_types'
2
- import { extractMaskBuffer } from '../Mask/extractMaskBuffer'
3
-
4
- /**
5
- * Intersects a target rectangle with a boundary, trimming dimensions and masks in-place.
6
- * This utility calculates the axis-aligned intersection between the `target` and `bounds`.
7
- * If the `target` includes a `mask` (as in a {@link NullableMaskRect}), the mask is physically
8
- * cropped and re-aligned using `extractMaskBuffer` to match the new dimensions.
9
- * @param target - The rectangle or selection object to be trimmed. **Note:** This object is mutated in-place.
10
- * @param bounds - The boundary rectangle defining the maximum allowable area (e.g., canvas dimensions).
11
- * @example
12
- * const selection = { x: -10, y: -10, w: 50, h: 50, mask: new Uint8Array(2500) };
13
- * const canvas = { x: 0, y: 0, w: 100, h: 100 };
14
- * // Selection will be moved to (0,0) and resized to 40x40.
15
- * // The mask is cropped by 10 px on the top and left.
16
- * trimRectBounds(selection, canvas);
17
- */
18
- export function trimRectBounds<T extends NullableMaskRect>(
19
- target: T,
20
- bounds: Rect,
21
- ): void {
22
- const originalX = target.x
23
- const originalY = target.y
24
- const originalW = target.w
25
-
26
- const intersectedX = Math.max(target.x, bounds.x)
27
- const intersectedY = Math.max(target.y, bounds.y)
28
-
29
- const intersectedMaxX = Math.min(
30
- target.x + target.w,
31
- bounds.x + bounds.w,
32
- )
33
- const intersectedMaxY = Math.min(
34
- target.y + target.h,
35
- bounds.y + bounds.h,
36
- )
37
-
38
- // Intersection check
39
- if (intersectedMaxX <= intersectedX || intersectedMaxY <= intersectedY) {
40
- target.w = 0
41
- target.h = 0
42
-
43
- if ('data' in target && target.data) {
44
- target.data = new Uint8Array(0)
45
- }
46
-
47
- return
1
+ import { type Rect } from '../_types'
2
+
3
+ export function trimRectBounds(
4
+ x: number,
5
+ y: number,
6
+ w: number,
7
+ h: number,
8
+ targetWidth: number,
9
+ targetHeight: number,
10
+ out?: Rect,
11
+ ): Rect {
12
+ const res = out ?? {
13
+ x: 0,
14
+ y: 0,
15
+ w: 0,
16
+ h: 0,
48
17
  }
49
18
 
50
- const intersectedW = intersectedMaxX - intersectedX
51
- const intersectedH = intersectedMaxY - intersectedY
52
- const offsetX = intersectedX - originalX
53
- const offsetY = intersectedY - originalY
54
-
55
- target.x = intersectedX
56
- target.y = intersectedY
57
- target.w = intersectedW
58
- target.h = intersectedH
19
+ const left = Math.max(0, x)
20
+ const top = Math.max(0, y)
21
+ const right = Math.min(targetWidth, x + w)
22
+ const bottom = Math.min(targetHeight, y + h)
59
23
 
60
- if ('data' in target && target.data) {
61
- const currentMaskBuffer = extractMaskBuffer(
62
- target.data,
63
- originalW,
64
- offsetX,
65
- offsetY,
66
- intersectedW,
67
- intersectedH,
68
- )
24
+ res.x = left
25
+ res.y = top
26
+ res.w = Math.max(0, right - left)
27
+ res.h = Math.max(0, bottom - top)
69
28
 
70
- let minX = intersectedW
71
- let maxX = -1
72
- let minY = intersectedH
73
- let maxY = -1
74
-
75
- // Scan for content
76
- for (let y = 0; y < intersectedH; y++) {
77
- for (let x = 0; x < intersectedW; x++) {
78
- if (currentMaskBuffer[y * intersectedW + x] !== 0) {
79
- if (x < minX) minX = x
80
- if (x > maxX) maxX = x
81
- if (y < minY) minY = y
82
- if (y > maxY) maxY = y
83
- }
84
- }
85
- }
86
-
87
- // If no content is found (all zeros)
88
- if (maxX === -1) {
89
- target.w = 0
90
- target.h = 0
91
- target.data = new Uint8Array(0)
92
-
93
- return
94
- }
95
-
96
- const finalW = maxX - minX + 1
97
- const finalH = maxY - minY + 1
98
-
99
- // Only shift and crop if the content is smaller than the intersection
100
- if (finalW !== intersectedW || finalH !== intersectedH) {
101
- const newMaskBuffer = extractMaskBuffer(
102
- currentMaskBuffer,
103
- intersectedW,
104
- minX,
105
- minY,
106
- finalW,
107
- finalH,
108
- )
109
-
110
- target.x += minX
111
- target.y += minY
112
- target.w = finalW
113
- target.h = finalH
114
- target.data = newMaskBuffer
115
- } else {
116
- target.w = finalW
117
- target.h = finalH
118
- target.data = currentMaskBuffer
119
- }
120
- }
29
+ return res
121
30
  }
package/src/_types.ts CHANGED
@@ -80,19 +80,18 @@ export interface AlphaMask extends Mask {
80
80
  readonly type: MaskType.ALPHA
81
81
  }
82
82
 
83
- interface BaseCircleMask {
84
- readonly size: number
85
- readonly radius: number
86
- readonly minOffset: number
83
+ interface BasePaintMask {
84
+ readonly centerOffsetX: number
85
+ readonly centerOffsetY: number
87
86
  }
88
87
 
89
- export interface CircleAlphaMask extends BaseCircleMask, AlphaMask {
88
+ export interface PaintAlphaMask extends BasePaintMask, AlphaMask {
90
89
  }
91
90
 
92
- export interface CircleBinaryMask extends BaseCircleMask, BinaryMask {
91
+ export interface PaintBinaryMask extends BasePaintMask, BinaryMask {
93
92
  }
94
93
 
95
- export type CircleMask = CircleAlphaMask | CircleBinaryMask
94
+ export type PaintMask = PaintAlphaMask | PaintBinaryMask
96
95
 
97
96
  /**
98
97
  * Configuration for pixel manipulation operations.
@@ -192,7 +191,6 @@ export interface BasePixelBlendOptions {
192
191
  }
193
192
 
194
193
  export interface PixelBlendOptions extends PixelRect, Alpha, BasePixelBlendOptions {
195
-
196
194
  }
197
195
 
198
196
  export interface PixelBlendMaskOptions extends PixelRect, Alpha, MaskOffset, InvertMask, BasePixelBlendOptions {
@@ -212,15 +210,14 @@ export interface ColorBlendOptions extends PixelRect, Alpha {
212
210
  export interface ColorBlendMaskOptions extends ColorBlendOptions, MaskOffset, InvertMask {
213
211
  }
214
212
 
215
- export type BinaryMaskRect = Rect & {
216
- type: MaskType.BINARY
213
+ export type MaskRect<T extends MaskType> = Rect & {
214
+ type: T
217
215
  data: Uint8Array
218
216
  }
219
217
 
220
- export type AlphaMaskRect = Rect & {
221
- type: MaskType.ALPHA
222
- data: Uint8Array
223
- }
218
+ export type BinaryMaskRect = MaskRect<MaskType.BINARY>
219
+
220
+ export type AlphaMaskRect = MaskRect<MaskType.ALPHA>
224
221
 
225
222
  export type NullableBinaryMaskRect = Rect & ({
226
223
  type: MaskType.BINARY
@@ -240,8 +237,12 @@ export type NullableMaskRect = Rect & ({
240
237
 
241
238
  export type HistoryMutator<T extends {}, D extends {}> = (writer: PixelWriter<any>, deps?: Partial<D>) => T
242
239
 
243
- export interface IPixelData {
240
+ export interface IPixelData32 {
244
241
  readonly data32: Uint32Array
245
242
  readonly width: number
246
243
  readonly height: number
247
244
  }
245
+
246
+ export interface IPixelData<T extends ImageDataLike = ImageData> extends IPixelData32 {
247
+ readonly imageData: T
248
+ }