【实例】canvas之图片区域性选择并下载

1,333 阅读1分钟

实现样式 选择拉动框.gif

主要是通过鼠标来对图片进行区域选择,然后将图片进行下载和灰度处理

实现代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加水印</title>
    <style>
    .container{
        margin-top: 50px;
    }
    .edit{
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .edit-item{
        position: relative;
        width: 100px;
        height: 34px;
        background-color: salmon;
        color: #fff;
        line-height: 34px;
        text-align: center;
        border-radius: 5px;
        cursor: pointer;
        margin-right: 20px;
    }
    .edit-item input{
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        top: 0;
        width: 100%;
        height: 100%;
        opacity: 0
    }
    .previwe{
        display: flex;
        align-items: center;
        margin-top: 100px;
    }

    canvas{
        width: 800px;
        display: block;
        background-color: #eee;
    }
    img{
        object-fit: contain;
        margin-left: 100px;
    }
    </style>
</head>
<body>
    <div class="container">
        <div class="edit">
            <div class="edit-item">
                <span>上传背景图片</span>
                <input type="file" id="bgImage">
            </div>
            <div class="edit-item" id="selected">
                <span>下载选中区域</span>
            </div>
            <div class="edit-item" id="gray">
                <span>灰度处理</span>
            </div>
        </div>
        <div class="previwe">
            <canvas id="myCanvas" width="800" height="600"></canvas>
            <img src="" alt="" id="showImage">
        </div>
    </div>
<script src="./utils.js"></script>
<script>
    let bgImage = document.getElementById('bgImage')
    let selected = document.getElementById('selected')
    let showImage = document.getElementById('showImage')
    let gray = document.getElementById('gray')
    let canvas = document.getElementById('myCanvas')
    let ctx = canvas.getContext('2d')
    let bgImageData = {},selectData = {}
    bgImage.addEventListener('change',waterMarkChange,false)
    
    function waterMarkChange(){
        const file = bgImage.files[0]
        let type = file.type
        if(type.indexOf('image') == -1){
            alert('仅支持图片,请重新上传')
        }
        getImageData(file)
    }

function getImageData(file){
    let image = new Image()
        image.src = window.URL.createObjectURL(file)
        image.onload = function(){
        bgImageData.data = image
        bgImageData.width = image.width
        bgImageData.height = image.height
        let x = canvas.width / 2 - bgImageData.width / 2
        let y = canvas.height / 2 - bgImageData.height / 2
        bgImageData.x = x , bgImageData.y = y
        putImageData()
    }
}

function putImageData(){
  ctx.clearRect(0,0,canvas.width,canvas.height)
  ctx.drawImage(bgImageData.data,bgImageData.x,bgImageData.y,bgImageData.width,bgImageData.height)
}

selected.addEventListener('click',function(){
    // 获取canvas中的数据
    if(selectData.data){
        let bas64 = returnImageUrl(selectData.data)
        let blobData = C.dataURLToBlob(bas64)
        C.download(blobData)
    }
})

gray.addEventListener('click',function(){
    if(selectData.data){
        selectData.data = C.grey_processing(selectData.data)
        showImage.src = returnImageUrl(selectData.data)
    }
})
canvas.addEventListener('mousedown',mousedown,false)
canvas.addEventListener('mousemove',mousemove,false)
canvas.addEventListener('mouseup',mouseup,false)
let mouse = C.getMousePosition(canvas)
let isMoving = false
let initX = 0,initY = 0
function mousedown(){
    isMoving = true
    initY = mouse.y
    initX = mouse.x
}

function mousemove(){
   if(isMoving){
    putImageData()
    ctx.save()
    ctx.strokeStyle = '#fff'
    selectData.width = Math.abs(mouse.x - initX)
    selectData.height = Math.abs(mouse.y - initY)
    if(selectData.width && selectData.height){
        selectData.data = ctx.getImageData(initX,initY,selectData.width,selectData.height)
        showImage.width = selectData.width,showImage.height = selectData.height
        showImage.src = returnImageUrl(selectData.data)
    }
    ctx.strokeRect(initX,initY,selectData.width,selectData.height)
    ctx.restore()
  }

}

function mouseup(){
    isMoving = false
    initY = initX = 0
}

// 重新生成一个canvas用来下载图片
function returnImageUrl(data){
    let canvasElm = document.createElement('canvas')
    let ctxElm = canvasElm.getContext('2d')
    canvasElm.width = showImage.width , canvasElm.height = showImage.height
    ctxElm.putImageData(data,0,0)
    return canvasElm.toDataURL('image/png',1)

}

</script>
</body>

</html>

utils.js

// 转换坐标
C.getMousePosition = (el) =>{
        let mouse = {x:0,y:0}
        el.addEventListener('mousemove',(e)=>{
        let {x,y} = C.eventWrapper(e)
        mouse.x = x
        mouse.y = y
    })
    return mouse
}
C.eventWrapper = function(e){
    let {pageX, pageY, target} = e
    let {left,top} = target.getBoundingClientRect() // 获取元素相对于视口位置距离
    return {x : pageX - left ,y: pageY - top}
}
//下载blob对象数据
C.download = (blob) =>{
    // 创建一个blob链接
    let url = URL.createObjectURL(blob)
    let a = document.createElement('a')
    a.setAttribute('download', url)
    a.href=url ;
    a.style.display = 'none'
    a.click()
    // 每次调用URL.createObjectURL,都会创建一个新的URL对象,浏览器内存中会保持对该对象的引用
    // 只有在document销毁时,才会释放此部分内存
    // 在考虑性能的情况下,在url使用结束后,最好释放此部分内存
    URL.revokeObjectURL(url)
}

// 将base64转换成blob对象
C.dataURLToBlob = (code)=> {
    let parts = code.split(';base64,')
    let contentType = parts[0].split(':')[1]
    let raw = window.atob(parts[1])
    let rawLength = raw.length
    let uInt8Array = new Uint8Array(rawLength)
    for(let i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i)
    }
    return new Blob([uInt8Array], {
        type: contentType
    })
}

// 对图片数据进行灰度处理
C.grey_processing = (imageData) =>{
    let data = imageData.data
    for(let i = 0; i < data.length ; i+=4){
    let avg = 0
    avg = (data[i]+data[i+1]+data[i+2]) / 3
        data[i] = data[i+1] = data[i+2] = avg
    }
    return imageData
}

步骤

  • 图片上传现在到canvas上,显示图片
    • drawImage来将获取到的图片绘制到canvas上
  • 在利用鼠标和canvas进行交互区域选择,获取到图片数据
    • 主要是利用mouseup|mousemove|mousedown事件来进行事件交互
    • 利用putImageData|getImageData来实现获取区域性的图像数据