pixel-data-js 0.26.0 → 0.28.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.
Files changed (139) hide show
  1. package/README.md +12 -2
  2. package/dist/index.prod.cjs +2227 -1050
  3. package/dist/index.prod.cjs.map +1 -1
  4. package/dist/index.prod.d.ts +549 -424
  5. package/dist/index.prod.js +2171 -1028
  6. package/dist/index.prod.js.map +1 -1
  7. package/package.json +11 -11
  8. package/src/Algorithm/floodFillSelection.ts +8 -6
  9. package/src/Algorithm/forEachLinePoint.ts +6 -6
  10. package/src/{Internal/resample32.ts → Algorithm/resampleUint32Array.ts} +11 -21
  11. package/src/BlendModes/blend-modes-fast.ts +169 -0
  12. package/src/BlendModes/blend-modes-perfect.ts +207 -0
  13. package/src/BlendModes/blend-modes.ts +9 -0
  14. package/src/Canvas/CanvasFrameRenderer.ts +20 -28
  15. package/src/Canvas/CanvasPixelDataRenderer.ts +23 -0
  16. package/src/Canvas/PixelCanvas.ts +2 -7
  17. package/src/Canvas/ReusableCanvas.ts +4 -12
  18. package/src/Canvas/_canvas-types.ts +26 -0
  19. package/src/History/PixelAccumulator.ts +17 -17
  20. package/src/History/PixelEngineConfig.ts +3 -3
  21. package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +4 -3
  22. package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +4 -3
  23. package/src/History/PixelMutator/mutatorApplyMask.ts +4 -3
  24. package/src/History/PixelMutator/mutatorBlendAlphaMask.ts +6 -4
  25. package/src/History/PixelMutator/mutatorBlendBinaryMask.ts +6 -4
  26. package/src/History/PixelMutator/mutatorBlendColor.ts +2 -2
  27. package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +2 -1
  28. package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +2 -1
  29. package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +3 -1
  30. package/src/History/PixelMutator/{mutatorBlendPaintRect.ts → mutatorBlendColorPaintRect.ts} +5 -5
  31. package/src/History/PixelMutator/mutatorBlendMask.ts +6 -4
  32. package/src/History/PixelMutator/mutatorBlendPixelData.ts +5 -4
  33. package/src/History/PixelMutator/mutatorClear.ts +4 -3
  34. package/src/History/PixelMutator/mutatorFill.ts +5 -4
  35. package/src/History/PixelMutator/mutatorFillBinaryMask.ts +2 -1
  36. package/src/History/PixelMutator/mutatorInvert.ts +2 -2
  37. package/src/History/PixelMutator.ts +2 -2
  38. package/src/History/PixelPatchTiles.ts +7 -7
  39. package/src/History/PixelWriter.ts +12 -63
  40. package/src/ImageData/ImageDataLike.ts +1 -1
  41. package/src/ImageData/_ImageData-types.ts +13 -0
  42. package/src/ImageData/copyImageData.ts +1 -1
  43. package/src/ImageData/extractImageDataBuffer.ts +3 -2
  44. package/src/ImageData/imageDataToUint32Array.ts +18 -0
  45. package/src/ImageData/resampleImageData.ts +3 -3
  46. package/src/ImageData/resizeImageData.ts +1 -1
  47. package/src/ImageData/serialization.ts +1 -1
  48. package/src/ImageData/uInt32ArrayToImageData.ts +1 -1
  49. package/src/ImageData/writeImageData.ts +2 -2
  50. package/src/ImageData/writeImageDataBuffer.ts +2 -2
  51. package/src/IndexedImage/IndexedImage.ts +56 -98
  52. package/src/IndexedImage/_indexedImage-types.ts +18 -0
  53. package/src/IndexedImage/getIndexedImageColorCounts.ts +3 -3
  54. package/src/IndexedImage/indexedImageToAverageColor.ts +1 -1
  55. package/src/IndexedImage/indexedImageToImageData.ts +4 -6
  56. package/src/IndexedImage/resampleIndexedImage.ts +7 -15
  57. package/src/Input/fileToImageData.ts +1 -1
  58. package/src/Internal/_errors.ts +2 -0
  59. package/src/Internal/macros.ts +14 -0
  60. package/src/Mask/AlphaMask.ts +1 -1
  61. package/src/Mask/BinaryMask/makeBinaryMaskFromAlphaMask.ts +23 -0
  62. package/src/Mask/BinaryMask/makeBinaryMaskOutline.ts +88 -0
  63. package/src/Mask/BinaryMask/makeCircleBinaryMaskOutline.ts +104 -0
  64. package/src/Mask/BinaryMask/makeRectBinaryMaskOutline.ts +34 -0
  65. package/src/Mask/BinaryMask.ts +1 -1
  66. package/src/Mask/_mask-types.ts +73 -0
  67. package/src/Mask/applyBinaryMaskToAlphaMask.ts +2 -1
  68. package/src/Mask/copyMask.ts +1 -1
  69. package/src/Mask/extractMask.ts +2 -1
  70. package/src/Mask/extractMaskBuffer.ts +1 -1
  71. package/src/Mask/mergeAlphaMasks.ts +6 -3
  72. package/src/Mask/mergeBinaryMasks.ts +2 -1
  73. package/src/Mask/setMaskData.ts +1 -1
  74. package/src/MaskRect/merge2BinaryMaskRects.ts +2 -2
  75. package/src/MaskRect/mergeBinaryMaskRects.ts +1 -1
  76. package/src/MaskRect/subtractBinaryMaskRects.ts +1 -1
  77. package/src/Paint/AlphaMaskPaintBuffer.ts +339 -0
  78. package/src/Paint/AlphaMaskPaintBufferCanvasRenderer.ts +78 -0
  79. package/src/Paint/BinaryMaskPaintBuffer.ts +254 -0
  80. package/src/Paint/BinaryMaskPaintBufferCanvasRenderer.ts +67 -0
  81. package/src/Paint/{PaintBuffer.ts → ColorPaintBuffer.ts} +148 -77
  82. package/src/Paint/{PaintBufferCanvasRenderer.ts → ColorPaintBufferCanvasRenderer.ts} +6 -5
  83. package/src/Paint/PaintCursorRenderer.ts +117 -0
  84. package/src/Paint/_paint-types.ts +22 -0
  85. package/src/Paint/eachTileInBounds.ts +45 -0
  86. package/src/Paint/makeCirclePaintMask.ts +74 -0
  87. package/src/Paint/makePaintMask.ts +5 -2
  88. package/src/Paint/makeRectFalloffPaintAlphaMask.ts +4 -2
  89. package/src/PixelData/PixelData.ts +15 -19
  90. package/src/PixelData/ReusablePixelData.ts +36 -0
  91. package/src/PixelData/_pixelData-types.ts +17 -0
  92. package/src/PixelData/applyAlphaMaskToPixelData.ts +80 -43
  93. package/src/PixelData/applyBinaryMaskToPixelData.ts +10 -8
  94. package/src/PixelData/applyMaskToPixelData.ts +4 -9
  95. package/src/PixelData/blendColorPixelData.ts +9 -8
  96. package/src/PixelData/blendColorPixelDataAlphaMask.ts +9 -7
  97. package/src/PixelData/blendColorPixelDataBinaryMask.ts +9 -7
  98. package/src/PixelData/blendColorPixelDataMask.ts +4 -2
  99. package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +4 -2
  100. package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +4 -2
  101. package/src/PixelData/blendColorPixelDataPaintMask.ts +5 -2
  102. package/src/PixelData/blendPixel.ts +6 -5
  103. package/src/PixelData/blendPixelData.ts +14 -13
  104. package/src/PixelData/blendPixelDataAlphaMask.ts +15 -13
  105. package/src/PixelData/blendPixelDataBinaryMask.ts +15 -13
  106. package/src/PixelData/blendPixelDataMask.ts +5 -3
  107. package/src/PixelData/blendPixelDataPaintBuffer.ts +5 -4
  108. package/src/PixelData/clearPixelDataFast.ts +4 -2
  109. package/src/PixelData/copyPixelData.ts +14 -0
  110. package/src/PixelData/extractPixelData.ts +8 -7
  111. package/src/PixelData/extractPixelDataBuffer.ts +9 -8
  112. package/src/PixelData/fillPixelData.ts +16 -14
  113. package/src/PixelData/fillPixelDataBinaryMask.ts +10 -8
  114. package/src/PixelData/fillPixelDataFast.ts +16 -14
  115. package/src/PixelData/invertPixelData.ts +9 -8
  116. package/src/PixelData/pixelDataToAlphaMask.ts +9 -8
  117. package/src/PixelData/reflectPixelData.ts +9 -9
  118. package/src/PixelData/resamplePixelData.ts +20 -9
  119. package/src/PixelData/rotatePixelData.ts +8 -7
  120. package/src/PixelData/uInt32ArrayToPixelData.ts +15 -0
  121. package/src/PixelData/writePaintBufferToPixelData.ts +5 -5
  122. package/src/PixelData/writePixelDataBuffer.ts +10 -9
  123. package/src/Rect/_rect-types.ts +7 -0
  124. package/src/Rect/getRectsBounds.ts +1 -1
  125. package/src/Rect/trimMaskRectBounds.ts +2 -1
  126. package/src/Rect/trimRectBounds.ts +1 -1
  127. package/src/Tile/MaskTile.ts +40 -0
  128. package/src/Tile/PixelTile.ts +23 -0
  129. package/src/{PixelTile/PixelTilePool.ts → Tile/TilePool.ts} +9 -9
  130. package/src/Tile/_tile-types.ts +33 -0
  131. package/src/_errors.ts +1 -0
  132. package/src/_types.ts +2 -118
  133. package/src/index.ts +47 -22
  134. package/src/ImageData/imageDataToUInt32Array.ts +0 -13
  135. package/src/Internal/helpers.ts +0 -5
  136. package/src/Paint/makeCirclePaintAlphaMask.ts +0 -41
  137. package/src/Paint/makeCirclePaintBinaryMask.ts +0 -29
  138. package/src/PixelTile/PixelTile.ts +0 -21
  139. /package/src/{Internal → Rect}/resolveClipping.ts +0 -0
@@ -0,0 +1,78 @@
1
+ import type { Color32 } from '../_types'
2
+ import { CANVAS_CTX_FAILED } from '../Internal/_errors'
3
+ import { makePixelData } from '../PixelData/PixelData'
4
+ import type { AlphaMaskPaintBuffer } from './AlphaMaskPaintBuffer'
5
+
6
+ export type AlphaMaskPaintBufferCanvasRenderer = ReturnType<typeof makeAlphaMaskPaintBufferCanvasRenderer>
7
+
8
+ export function makeAlphaMaskPaintBufferCanvasRenderer(
9
+ paintBuffer: AlphaMaskPaintBuffer,
10
+ offscreenCanvasClass = OffscreenCanvas,
11
+ ) {
12
+ const config = paintBuffer.config
13
+ const tileSize = config.tileSize
14
+ const tileShift = config.tileShift
15
+ const tileArea = config.tileArea
16
+ const lookup = paintBuffer.lookup
17
+
18
+ const canvas = new offscreenCanvasClass(tileSize, tileSize)
19
+ const ctx = canvas.getContext('2d')
20
+
21
+ if (!ctx) throw new Error(CANVAS_CTX_FAILED)
22
+
23
+ ctx.imageSmoothingEnabled = false
24
+
25
+ const bridge = makePixelData(new ImageData(tileSize, tileSize))
26
+ const view32 = bridge.data
27
+
28
+ return function drawPaintBuffer(
29
+ targetCtx: CanvasRenderingContext2D,
30
+ color: Color32,
31
+ alpha = 255,
32
+ compOperation: GlobalCompositeOperation = 'source-over',
33
+ ): void {
34
+ if (alpha === 0) return
35
+
36
+ const baseSrcAlpha = (color >>> 24)
37
+ const colorRGB = color & 0x00ffffff
38
+
39
+ if (baseSrcAlpha === 0) return
40
+
41
+ targetCtx.globalAlpha = alpha / 255
42
+ targetCtx.globalCompositeOperation = compOperation
43
+
44
+ for (let i = 0; i < lookup.length; i++) {
45
+ const tile = lookup[i]
46
+
47
+ if (tile) {
48
+ const data8 = tile.data
49
+ view32.fill(0)
50
+
51
+ for (let p = 0; p < tileArea; p++) {
52
+ const maskA = data8[p]
53
+ if (maskA === 0) continue
54
+
55
+ // If mask is solid, the final pixel is just the unmodified color
56
+ if (maskA === 255) {
57
+ view32[p] = color
58
+ } else {
59
+ // Otherwise, blend the color's inherent alpha with the mask's alpha
60
+ const t = baseSrcAlpha * maskA + 128
61
+ const finalA = (t + (t >> 8)) >> 8
62
+
63
+ view32[p] = ((colorRGB | (finalA << 24)) >>> 0) as Color32
64
+ }
65
+ }
66
+
67
+ const dx = tile.tx << tileShift
68
+ const dy = tile.ty << tileShift
69
+
70
+ ctx.putImageData(bridge.imageData, 0, 0)
71
+ targetCtx.drawImage(canvas, dx, dy)
72
+ }
73
+ }
74
+
75
+ targetCtx.globalAlpha = 1
76
+ targetCtx.globalCompositeOperation = 'source-over'
77
+ }
78
+ }
@@ -0,0 +1,254 @@
1
+ import { type Color32 } from '../_types'
2
+ import { forEachLinePoint } from '../Algorithm/forEachLinePoint'
3
+ import { sourceOverPerfect } from '../BlendModes/blend-modes-perfect'
4
+ import type { PixelAccumulator } from '../History/PixelAccumulator'
5
+ import type { PixelEngineConfig } from '../History/PixelEngineConfig'
6
+ import { _macro_paintRectCenterOffset } from '../Internal/macros'
7
+ import { blendColorPixelDataBinaryMask } from '../PixelData/blendColorPixelDataBinaryMask'
8
+ import type { Rect } from '../Rect/_rect-types'
9
+ import { trimRectBounds } from '../Rect/trimRectBounds'
10
+ import type { BinaryMaskTile } from '../Tile/_tile-types'
11
+ import type { TilePool } from '../Tile/TilePool'
12
+ import type { PaintBinaryMask } from './_paint-types'
13
+ import { eachTileInBounds } from './eachTileInBounds'
14
+
15
+ export class BinaryMaskPaintBuffer {
16
+ readonly lookup: (BinaryMaskTile | undefined)[]
17
+ private readonly scratchBounds: Rect = { x: 0, y: 0, w: 0, h: 0 }
18
+
19
+ private blendColorPixelDataBinaryMaskFn = blendColorPixelDataBinaryMask
20
+ private forEachLinePointFn = forEachLinePoint
21
+ private trimRectBoundsFn = trimRectBounds
22
+ private eachTileInBoundsFn = eachTileInBounds
23
+
24
+ constructor(
25
+ readonly config: PixelEngineConfig,
26
+ readonly tilePool: TilePool<BinaryMaskTile>,
27
+ ) {
28
+ this.lookup = []
29
+ }
30
+
31
+ paintBinaryMask(
32
+ brush: PaintBinaryMask,
33
+ x: number,
34
+ y: number,
35
+ ): boolean
36
+ paintBinaryMask(
37
+ brush: PaintBinaryMask,
38
+ startX: number,
39
+ startY: number,
40
+ endX: number,
41
+ endY: number,
42
+ ): boolean
43
+ paintBinaryMask(
44
+ brush: PaintBinaryMask,
45
+ x0: number,
46
+ y0: number,
47
+ x1: number = x0,
48
+ y1: number = y0,
49
+ ): boolean {
50
+ const scratch = this.scratchBounds
51
+ const lookup = this.lookup
52
+ const tilePool = this.tilePool
53
+ const config = this.config
54
+ const tileShift = config.tileShift
55
+ const tileMask = config.tileMask
56
+ const target = config.target
57
+
58
+ const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
59
+ let changed = false
60
+
61
+ const trimRectBoundsFn = this.trimRectBoundsFn
62
+ const eachTileInBoundsFn = this.eachTileInBoundsFn
63
+
64
+ this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
65
+ const topLeftX = Math.floor(px + centerOffsetX)
66
+ const topLeftY = Math.floor(py + centerOffsetY)
67
+
68
+ trimRectBoundsFn(
69
+ topLeftX,
70
+ topLeftY,
71
+ bW,
72
+ bH,
73
+ target.w,
74
+ target.h,
75
+ scratch,
76
+ )
77
+
78
+ if (scratch.w <= 0 || scratch.h <= 0) return
79
+
80
+ eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
81
+ const data = tile.data
82
+ let tileChanged = false
83
+
84
+ for (let i = 0; i < bH_t; i++) {
85
+ const canvasY = bY + i
86
+ const bOff = (canvasY - topLeftY) * bW
87
+ const tOff = (canvasY & tileMask) << tileShift
88
+ const dS = tOff + (bX & tileMask)
89
+
90
+ for (let j = 0; j < bW_t; j++) {
91
+ const canvasX = bX + j
92
+
93
+ if (bD[bOff + (canvasX - topLeftX)]) {
94
+ const idx = dS + j
95
+
96
+ // Only write if it's not already "on"
97
+ if (data[idx] === 0) {
98
+ data[idx] = 1
99
+ tileChanged = true
100
+ }
101
+ }
102
+ }
103
+ }
104
+ if (tileChanged) changed = true
105
+ })
106
+ })
107
+
108
+ return changed
109
+ }
110
+
111
+ paintRect(
112
+ brushWidth: number,
113
+ brushHeight: number,
114
+ x: number,
115
+ y: number,
116
+ ): boolean
117
+ paintRect(
118
+ brushWidth: number,
119
+ brushHeight: number,
120
+ startX: number,
121
+ startY: number,
122
+ endX: number,
123
+ endY: number,
124
+ ): boolean
125
+ paintRect(
126
+ brushWidth: number,
127
+ brushHeight: number,
128
+ x0: number,
129
+ y0: number,
130
+ x1: number = x0,
131
+ y1: number = y0,
132
+ ): boolean {
133
+ const scratch = this.scratchBounds
134
+ const lookup = this.lookup
135
+ const tilePool = this.tilePool
136
+ const config = this.config
137
+ const tileShift = config.tileShift
138
+ const tileMask = config.tileMask
139
+ const target = config.target
140
+
141
+ const centerOffsetX = _macro_paintRectCenterOffset(brushWidth)
142
+ const centerOffsetY = _macro_paintRectCenterOffset(brushHeight)
143
+
144
+ const trimRectBoundsFn = this.trimRectBoundsFn
145
+ const eachTileInBoundsFn = this.eachTileInBoundsFn
146
+
147
+ let changed = false
148
+ this.forEachLinePointFn(
149
+ x0,
150
+ y0,
151
+ x1,
152
+ y1,
153
+ (px, py) => {
154
+ const topLeftX = Math.floor(px + centerOffsetX)
155
+ const topLeftY = Math.floor(py + centerOffsetY)
156
+
157
+ trimRectBoundsFn(
158
+ topLeftX,
159
+ topLeftY,
160
+ brushWidth,
161
+ brushHeight,
162
+ target.w,
163
+ target.h,
164
+ scratch,
165
+ )
166
+
167
+ if (scratch.w <= 0 || scratch.h <= 0) return
168
+
169
+ eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
170
+ const data = tile.data
171
+ let tileChanged = false
172
+
173
+ for (let i = 0; i < bH_t; i++) {
174
+ const canvasY = bY + i
175
+ const tOff = (canvasY & tileMask) << tileShift
176
+ const dS = tOff + (bX & tileMask)
177
+
178
+ for (let j = 0; j < bW_t; j++) {
179
+ const idx = dS + j
180
+
181
+ // Only write if it's not already "on"
182
+ if (data[idx] === 0) {
183
+ data[idx] = 1
184
+ tileChanged = true
185
+ }
186
+ }
187
+ }
188
+
189
+ if (tileChanged) {
190
+ changed = true
191
+ }
192
+ },
193
+ )
194
+ },
195
+ )
196
+
197
+ return changed
198
+ }
199
+
200
+ private opts = {
201
+ alpha: 255,
202
+ blendFn: sourceOverPerfect,
203
+ x: 0,
204
+ y: 0,
205
+ w: 0,
206
+ h: 0,
207
+ }
208
+
209
+ commit(
210
+ accumulator: PixelAccumulator,
211
+ color: Color32,
212
+ alpha = 255,
213
+ blendFn = sourceOverPerfect,
214
+ ) {
215
+ const blendColorPixelDataBinaryMaskFn = this.blendColorPixelDataBinaryMaskFn
216
+ const tileShift = this.config.tileShift
217
+ const lookup = this.lookup
218
+ const opts = this.opts
219
+
220
+ opts.alpha = alpha
221
+ opts.blendFn = blendFn
222
+
223
+ for (let i = 0; i < lookup.length; i++) {
224
+ const tile = lookup[i]
225
+
226
+ if (tile) {
227
+ const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty)
228
+
229
+ const dx = tile.tx << tileShift
230
+ const dy = tile.ty << tileShift
231
+
232
+ opts.x = dx
233
+ opts.y = dy
234
+ opts.w = tile.w
235
+ opts.h = tile.h
236
+
237
+ didChange(
238
+ blendColorPixelDataBinaryMaskFn(
239
+ this.config.target,
240
+ color,
241
+ tile,
242
+ opts,
243
+ ),
244
+ )
245
+ }
246
+ }
247
+
248
+ this.clear()
249
+ }
250
+
251
+ clear(): void {
252
+ this.tilePool.releaseTiles(this.lookup)
253
+ }
254
+ }
@@ -0,0 +1,67 @@
1
+ import type { Color32 } from '../_types'
2
+ import { CANVAS_CTX_FAILED } from '../Internal/_errors'
3
+ import { makePixelData } from '../PixelData/PixelData'
4
+ import type { BinaryMaskPaintBuffer } from './BinaryMaskPaintBuffer'
5
+
6
+ export type BinaryMaskPaintBufferCanvasRenderer = ReturnType<typeof makeBinaryMaskPaintBufferCanvasRenderer>
7
+
8
+ export function makeBinaryMaskPaintBufferCanvasRenderer(
9
+ paintBuffer: BinaryMaskPaintBuffer,
10
+ offscreenCanvasClass = OffscreenCanvas,
11
+ ) {
12
+ const config = paintBuffer.config
13
+ const tileSize = config.tileSize
14
+ const tileShift = config.tileShift
15
+ const tileArea = config.tileArea
16
+ const lookup = paintBuffer.lookup
17
+
18
+ const canvas = new offscreenCanvasClass(tileSize, tileSize)
19
+ const ctx = canvas.getContext('2d')
20
+
21
+ if (!ctx) throw new Error(CANVAS_CTX_FAILED)
22
+
23
+ ctx.imageSmoothingEnabled = false
24
+
25
+ const bridge = makePixelData(new ImageData(tileSize, tileSize))
26
+ const view32 = bridge.data
27
+
28
+ return function drawPaintBuffer(
29
+ targetCtx: CanvasRenderingContext2D,
30
+ color: Color32,
31
+ alpha = 255,
32
+ compOperation: GlobalCompositeOperation = 'source-over',
33
+ ): void {
34
+ if (alpha === 0) return
35
+
36
+ const baseSrcAlpha = (color >>> 24)
37
+ if (baseSrcAlpha === 0) return
38
+
39
+ targetCtx.globalAlpha = alpha / 255
40
+ targetCtx.globalCompositeOperation = compOperation
41
+
42
+ for (let i = 0; i < lookup.length; i++) {
43
+ const tile = lookup[i]
44
+
45
+ if (tile) {
46
+ const data8 = tile.data
47
+ view32.fill(0)
48
+
49
+ for (let p = 0; p < tileArea; p++) {
50
+ // If mask is solid, the final pixel is just the unmodified color
51
+ if (data8[p] === 1) {
52
+ view32[p] = color
53
+ }
54
+ }
55
+
56
+ const dx = tile.tx << tileShift
57
+ const dy = tile.ty << tileShift
58
+
59
+ ctx.putImageData(bridge.imageData, 0, 0)
60
+ targetCtx.drawImage(canvas, dx, dy)
61
+ }
62
+ }
63
+
64
+ targetCtx.globalAlpha = 1
65
+ targetCtx.globalCompositeOperation = 'source-over'
66
+ }
67
+ }