您的位置:首页 > Web前端 > JavaScript

原生JavaScript + Canvas实现图片局部放大器

2020-04-05 07:15 399 查看

类似操作像素的博主还写过一篇文章:使用canvas给图片增加滤镜

文章目录

  • 3. 代码
  • 1. 效果图

    有两种放大模式,分别为拖拽放大以及单纯的hover放大,已下是效果图:

    2. 原理

    两种局部放大效果主要使用的均为canvas的getImageData以及putImageData
    (以上两个api详细介绍可以点击蓝色链接,跳转到MDN查看)

    操纵

    getImageData
    函数返回的ImageData来进行放大效果, 以下是详细实现方法:

    2.1. 拖拽放大

    当鼠标在canvas中触发mousedown事件时,通过

    getImageData
    函数获取当前画布的
    ImageData
    信息,并且复制一份当前画布信息,对其每个像素点的alpha设置为原来的一半,形成半透明效果 (
    imageData
    为连续的
    Uint8ClampedArray
    (8位无符号整形固定数组), 每4个项表示一个像素点,r红,g绿,b蓝,a透明度)。

    当鼠标触发mousemove事件时,通过

    putImageData
    函数将上一步复制的半透明画布信息,动态放到canvas中。

    最后当鼠标触发moveup时,将该部分像素信息铺满整个画布即可。

    这里有个问题需要注意,

    putImageData
    函数同时使用了设备像素以及css像素两种计量单位,当指定了canvas偏移量时需要以CSS像素为单位,然而在指定图像数据中的位置时则需要以设备像素为单位。

    /**
    * 生成矩形框内部半透明图像
    */
    
    function restoreRubberbandPixels() {
    // imageData中的width和height指的是canvas所含设备像素数量,例如有一个200*200像素的canvas
    // 那么就总共含有4w个css像素点,若是浏览器在横竖两个方向都有两个设备像素来表示每个css像素的话就有
    // 16w个(400*400)个像素点
    
    // 获取像素比
    const deviceWidth = imageData.width / canvas.width;
    const deviceHeight = imageData.height / canvas.height;
    
    context.putImageData(imageData, 0, 0);
    
    context.putImageData(imageDataCopy, 0, 0,
    rubberbandRectangle.left + context.lineWidth,
    rubberbandRectangle.top + context.lineWidth,
    (rubberbandRectangle.width - 2 * context.lineWidth) * deviceWidth,
    (rubberbandRectangle.height - 2 * context.lineWidth) * deviceHeight
    );
    }

    2.2. hover放大

    该部分实现原理较上一小节来说比较简单,只需监听鼠标mousemove事件,首先获取当前鼠标位置自定义大小矩形框的

    ImageData
    信息用于下一次鼠标移动恢复原始图像使用,然后就可以通过
    drawImage
    函数的9个参数来进行放大图像

    function drawMagnifyGlass(mouse) {
    let scaledMagnifyRectangle = null;
    magnifyRectangle.x = mouse.x;
    magnifyRectangle.y = mouse.y;
    imageData = context.getImageData(
    magnifyRectangle.x - magnifyGlassRadius,
    magnifyRectangle.y - magnifyGlassRadius,
    magnifyRectangle.width,
    magnifyRectangle.height,
    )
    
    context.save();
    scaledMagnifyRectangle = {
    width: magnifyRectangle.width * magnifycationScale,
    height: magnifyRectangle.height * magnifycationScale,
    }
    
    // 画圆形形状
    setClip();
    
    // 放大图像
    context.drawImage(canvas,
    magnifyRectangle.x - magnifyGlassRadius, magnifyRectangle.y - magnifyGlassRadius,
    magnifyRectangle.width, magnifyRectangle.height,
    magnifyRectangle.x - 2 * magnifyGlassRadius, magnifyRectangle.y - 2 * magnifyGlassRadius,
    scaledMagnifyRectangle.width,
    scaledMagnifyRectangle.height
    )
    
    context.restore();
    }

    3. 代码

    代码地址: https://github.com/TheKiteRunners/-JavaScript-Canvas-/tree/master
    注意该代码要放到服务器中运行,否则会触发canvas的安全问题:

    基于安全考量,canvas规范允许绘制不属于自己的(也就是其他域中的)图像,然而你不能通过canvas API保存或修改其他域中的图像
    canvas安全机制如下:
    每个canvas都有一个名为origin-clean的标志位,它的初始值为true,如果使用drawImage绘制了一幅其他域中的图像,那么origin-clean的值就会被设置为false。与此类似,如果用drawImage将一个origin-clean标志位false的canvas绘制到当前的canvas中,那么它的origin-clean标志也会被设置为false。
    就其本身而言,将canvas的origin-clean设置为false,并不会立刻导致诸如抛出异常这样的反应来,不过如果在origin-clean标志位false的canvas上调用toDataURL或getImageData方法,那么此时浏览器就会抛出SECURITY_ERR异常

    因此最简单的方法可以npm一个全局的http-server静态服务器即可运行该代码。

    1. npm install http-server -g
    2. 项目路径下打开控制台输入:http-server -p 8081
    3. 打开浏览器输入地址即可

    参考链接: David Geary著 HTML5 Canvas核心技术 189-223页

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    刘翾 博客专家 发布了167 篇原创文章 · 获赞 275 · 访问量 59万+ 他的留言板 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: