【发布时间】:2018-08-27 12:12:09
【问题描述】:
konva 中是否有过滤器可以用白色填充图像的封闭透明区域?
我目前正在为边框使用 konva 自定义过滤器。 https://konvajs.github.io/docs/filters/Custom_Filter.html
var canvas, tempCanvas
function initBorderCanvas () {
canvas = document.createElement('canvas')
tempCanvas = document.createElement('canvas')
}
// make all pixells opaque 100% (except pixels that 100% transparent)
function removeTransparency (canvas) {
var ctx = canvas.getContext('2d')
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
var nPixels = imageData.data.length
for (var i = 3; i < nPixels; i += 4) {
if (imageData.data[i] > 0) {
imageData.data[i] = 255
}
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.putImageData(imageData, 0, 0)
return canvas
}
function Border (imageData) {
var nPixels = imageData.data.length
var ratio = this._cache.canvas.scene.pixelRatio
var size = (this.getAttr('borderSize') || 0) * ratio
if (size === 0) {
return imageData
}
// - first set correct dimensions for canvases
canvas.width = imageData.width
canvas.height = imageData.height
tempCanvas.width = imageData.width
tempCanvas.height = imageData.height
// - the draw original shape into temp canvas
tempCanvas.getContext('2d').putImageData(imageData, 0, 0)
// - then we need to remove alpha chanel, because it will affect shadow (transparent shapes has smaller shadow)
removeTransparency(tempCanvas)
var ctx = canvas.getContext('2d')
var color = this.getAttr('borderColor') || 'black'
// 3. we will use shadow as border
// so we just need apply shadow on the original image
ctx.save()
ctx.shadowColor = color
ctx.shadowBlur = size
ctx.drawImage(tempCanvas, 0, 0)
ctx.restore()
// - Then we will dive in into image data of [original image + shadow]
// and remove transparency from shadow
var tempImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
var SMOOTH_MIN_THRESHOLD = 0
var SMOOTH_MAX_THRESHOLD = 0
let val, hasValue
var offset = 3
for (var i = 3; i < nPixels; i += 4) {
// skip opaque pixels
if (imageData.data[i] === 255) {
continue
}
val = tempImageData.data[i]
hasValue = val !== 0
if (!hasValue) {
continue
}
if (val > SMOOTH_MAX_THRESHOLD) {
val = 255
} else if (val < SMOOTH_MIN_THRESHOLD) {
val = 0
} else {
val =
((val - SMOOTH_MIN_THRESHOLD) /
(SMOOTH_MAX_THRESHOLD - SMOOTH_MIN_THRESHOLD)) *
255
}
tempImageData.data[i] = val
}
// draw resulted image (original + shadow without opacity) into canvas
ctx.putImageData(tempImageData, 0, 0)
// then fill whole image with color (after that shadow is colored)
ctx.save()
ctx.globalCompositeOperation = 'source-in'
ctx.fillStyle = color
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.restore()
// then we need to copy colored shadow into original imageData
var newImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
var indexesToProcess = []
for (var i = 3; i < nPixels; i += 4) {
var hasTransparentOnTop =
imageData.data[i - imageData.width * 4 * offset] === 0
var hasTransparentOnTopRight =
imageData.data[i - (imageData.width * 4 + 4) * offset] === 0
var hasTransparentOnTopLeft =
imageData.data[i - (imageData.width * 4 - 4) * offset] === 0
var hasTransparentOnRight = imageData.data[i + 4 * offset] === 0
var hasTransparentOnLeft = imageData.data[i - 4 * offset] === 0
var hasTransparentOnBottom =
imageData.data[i + imageData.width * 4 * offset] === 0
var hasTransparentOnBottomRight =
imageData.data[i + (imageData.width * 4 + 4) * offset] === 0
var hasTransparentOnBottomLeft =
imageData.data[i + (imageData.width * 4 - 4) * offset] === 0
var hasTransparentAround =
hasTransparentOnTop ||
hasTransparentOnRight ||
hasTransparentOnLeft ||
hasTransparentOnBottom ||
hasTransparentOnTopRight ||
hasTransparentOnTopLeft ||
hasTransparentOnBottomRight ||
hasTransparentOnBottomLeft
// if pixel presented in original image - skip it
// because we need to change only shadow area
if (
imageData.data[i] === 255 ||
(imageData.data[i] && !hasTransparentAround)
) {
continue
}
if (!newImageData.data[i]) {
// skip transparent pixels
continue
}
indexesToProcess.push(i)
}
for (var index = 0; index < indexesToProcess.length; index += 1) {
var i = indexesToProcess[index]
var alpha = imageData.data[i] / 255
imageData.data[i] = newImageData.data[i]
imageData.data[i - 1] =
newImageData.data[i - 1] * (1 - alpha) + imageData.data[i - 1] * alpha
imageData.data[i - 2] =
newImageData.data[i - 2] * (1 - alpha) + imageData.data[i - 2] * alpha
imageData.data[i - 3] =
newImageData.data[i - 3] * (1 - alpha) + imageData.data[i - 3] * alpha
}
}
export { initBorderCanvas, Border }
它可以很好地在图像周围绘制边框。
有没有办法像目标图像一样填充圆圈?
【问题讨论】:
标签: konvajs