美文网首页
实现 Canvas 图片编辑的解决过程

实现 Canvas 图片编辑的解决过程

作者: 赵团结 | 来源:发表于2016-09-29 18:26 被阅读2211次

    本文记录了在手机上实现图片编辑、画画并保存导出的实现过程和解决办法。前端实现图片编辑主流的办法就是基于 Canvas 来做,我实现了一个类,封装了比较完整的 Canvas 方法,实现初始化画布、设置画笔颜色、旋转画布和异步传入图片等。

    背景

    客户想要的样子

    我有收到一个客户需求,他们是类似做保险公司取证的App,他们发现业务员在拍摄的现场图片找不到重点。所以希望能在拍照后,在图片上“画画圈,打打横线”来标注再上传。

    后来又希望能在加上旋转、缩放等功能。

    问题

    下面主要举两个例子来引出细节:

    • 图片自适应
    • 旋转

    图片自适应

    拿 iPhone 6的设备宽度375 * 667举例,手机拍照后需要对图片进行缩放才可以放到画布中。

    如果要等比缩放:
    1.需要将图片的宽度缩小到375px
    2.再同比缩小高度
    3.高度仍可能过长,所以要再次重复以上步骤。

    其实文字已经描述出递归的意味了,就用它来实现吧!

    // 递归大法好
    function scale(w, h, maxW, maxH) {
        if (w > maxW) {
            return scale(maxW, h / (w / maxW), maxW, maxH);
        }
        if (h > maxH) {
            return scale(w / (h / maxH), maxH, maxW, maxH);
        }
        return [w, h];
    }
    

    坐标纠正与真实缩放

    但是你不能真正缩放这个图片的。
    如果你真的用了ctx.scale来达到真实缩小,那导出时候无法保证原图尺寸和无损。

    DPR

    这里考虑了 DevicePixelRatio 的思路,就是分为 ** 真实比例 ** 和 ** 你看到的比例 **。
    <canvas/> 的 attribute 长宽与 CSS 的长宽做“倍数”设置,来达到 ** 视觉缩放 **。

    var img, ctx;
    ctx.width = img.width;
    ctx.height = img.height;
    
    var scaled = scale(img.width, img.height, 375, 667);
    ctx.style.width = scaled[0];
    ctx.style.height = scaled[1];
    

    虽然视觉上缩小了,但是坐标还是原来的,需要得到缩放比例。

    var ratio = img.width / scaled[0];
    

    必须对 Touch 事件返回的坐标进行纠正,不然画笔歪掉了。

    
    var preventEvent = function(e) {
      e.preventDefault();
    
      var ratio; // 上面提到的 ratio
      var touch = isTouch ? e.touches[0] : e;
             
      e.moveX = (touch.clientX - e.target.offsetLeft) * ratio;
      e.moveY = (touch.clientY - e.target.offsetTop) * ratio;
      return e;
    }
    
    $canvas.addEventListener('touchmove', function(e) {
      e = preventEvent(e);
    });
    

    这里我直接在 Touch 事件中的坐标加入 ratio 增量,这样在后面 lineTo(x, y) 的时候纠正因缩放造成的偏移影响。

    旋转功能

    在设计旋转函数时,采取的是直接将当前 canvas toDataURL,然后作为新的图层旋转。

    这样做可以很完美的达到画笔、图片一起旋转,但是缺点就是每次旋转操作都是一次“截图”,造成性能浪费和图片失真。

    旋转10次后

    如图,这是做出来的 Demo,实际测试发现手机拍摄的高清图片在旋转10次后已经丢失细节。

    那么如何解决旋转问题?

    这里我发现了一个新的思路:

    1. 不直接使用 Canvas 操作图片,图片导入到 <img/> 上。
    2. 旋转、放大缩小等用 CSS 的 transform
    3. 每个操作记录都要保留,放大了多少倍,X轴移动多少像素,图片旋转多少度。
    4. 最后在保存时候,再在 canvas 绘制一遍即可。

    同时满足无损操作,和撤销到上一步的功能。更为完善。

    hidpi

    在实现过程中我并没有对 DPR > 1 的 hidpi 屏幕做特殊处理,不过缩放功能已经实现。
    这里可以引入一个 hidpi-canvas-polyfill来处理。

    总结

    1.对hidpi和图片自适应,利用 CSS 的 w, h 与<canvas/> 的 w, h 来达到视觉缩放。
    2.不直接用 Canvas 操作图片,而导入为<img/>用 CSS transform,然后记录操作记录。
    3.写文章要图文并茂,尽量用美女,不然没人仔细看。

    相关文章

      网友评论

          本文标题:实现 Canvas 图片编辑的解决过程

          本文链接:https://www.haomeiwen.com/subject/fgtlyttx.html