Reputation: 8756
Based on the documentation of drawImage()
, I'm trying to draw to a specific part of a canvas. However, areas outside of the destination box are being affected, namly having their alpha values zeroed.
I've created a JSFiddle demonstrating the issue.
I copied the canvas on the left (full yellow) to the canvas on the right and the drew the middle canvas to the center of that same canvas using "destination-atop". You can see that it applied properly but at the same time cleared everything outside the draw area. Same happens with "copy". See the Fiddle for details.
Why does drawImage()
affect pixels outside its destination?
Upvotes: -1
Views: 38
Reputation: 8756
For reasons unknown to me, the "destination box" (dx
, dy
, dWidth
, dHeight
) isn't actually a destination box. It's more like a "center" and "scale" because drawing extends out of this box as though there were transparent source pixels being applied to that outside area.
The fix is to add a clipping rectangle before doing the drawing, as such:
ctx.beginPath()
ctx.rect(dx, dy, dWidth, dHeight)
ctx.clip()
ctx.drawImage(img, dx, dy, dWidth, dHeight)
The resulting Fiddle now does what I expected, applying the mask in the middle to the center of the solid-color image on the left to get the image on the right:
Upvotes: 0
Reputation: 44172
The definition of destination-atop
is:
The existing canvas is only kept where it overlaps the new shape. The new shape is drawn behind the canvas content.
You want to keep everything, use source-over
:
This is the default setting and draws new shapes on top of the existing canvas content.
const SIZE = 150
const G = 63
let c1 = document.getElementById("c1")
c1.height = c1.width = SIZE
let ctx1 = c1.getContext("2d")
ctx1.fillStyle = "yellow"
ctx1.fillRect(0, 0, SIZE, SIZE)
let c2 = document.getElementById("c2")
c2.height = c2.width = SIZE
let ctx2 = c2.getContext("2d")
let g2= ctx2.createRadialGradient(
SIZE / 2, SIZE / 2,
SIZE / 10,
SIZE / 2, SIZE / 2,
SIZE / 2 - 1)
g2.addColorStop(0.00, `rgba(${G},${G},${G},0.000)`)
g2.addColorStop(0.25, `rgba(${G},${G},${G},0.500)`)
g2.addColorStop(0.50, `rgba(${G},${G},${G},0.750)`)
g2.addColorStop(0.75, `rgba(${G},${G},${G},0.875)`)
g2.addColorStop(1.00, `rgba(${G},${G},${G},1.000)`)
ctx2.fillStyle = g2
ctx2.globalCompositeOperation = "copy"
ctx2.fillRect(0, 0, SIZE, SIZE)
let c3 = document.getElementById("c3")
c3.height = c3.width = SIZE
let ctx3 = c3.getContext("2d")
ctx3.globalCompositeOperation = "source-over";
ctx3.drawImage(c1, 0, 0, SIZE, SIZE)
ctx3.drawImage(c2, SIZE/4, SIZE/4, SIZE/2, SIZE/2)
canvas {
border: 2px solid red;
}
<canvas id="c1"></canvas>
<canvas id="c2"></canvas>
<canvas id="c3"></canvas>
Upvotes: -1