从web图片裁剪出发:了解H5中的canvas

本篇内容不针对canvas文档对每个api进行逐个的详解!

  本篇内容不针对canvas文档对每个api进行逐个的详解!

  本篇内容不针对canvas文档对每个api进行逐个的详解!

  重说三,好了,现在进入正文。在上一回《从web图片裁剪出发:了解H5中的blob》中我解释了图片在浏览器中以怎样的形式留存,并且在最后一个example中演示了选择图片、预览最后提交的过程。然而这个预览并没有起到什么卵用,因为只能预览不能处理,原图片还是原图片,预览变得可有可无。这一篇我们就在预览这一步里做点手脚,加入处理图片的功能。

  我们先修改之前的example,既然要处理图片,肯定要引入canvas,所以我们把原来img这个标签去掉,取而代之的是canvas,并在js中加入对应的修改。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <form name=‘test‘>
    <input type="file" name=‘file‘>
    <input type="submit" value="提交">
  </form>
  <canvas width="0" height="0"></canvas>
  <script>
    var canvas = document.querySelector(‘canvas‘),
        ctx = canvas.getContext(‘2d‘),
        preview = new Image();
    document.test.file.addEventListener(‘change‘, function() {
      var fr = new FileReader();
      fr.onload = function() {
        preview.src = this.result;
        canvas.width = preview.width;
        canvas.height = preview.height;
        drawImage();
      };
      fr.readAsDataURL(this.files[0]);
    })
    function drawImage() {
      ctx.drawImage(preview, 0, 0); //把图片绘制到canvas上
    }
    document.test.addEventListener(‘submit‘, function(e) {
      e.preventDefault();
      var formData = new FormData(),
          xhr = new XMLHttpRequest(),
          mime = ‘image/jpeg‘,
          dataUrl = canvas.toDataURL(mime, 0.8),  //取出base64
          data = atob(dataUrl.split(‘,‘)[1]),
          n = data.length,
          uInt8 = new Uint8Array(n),
          blob;
      while(n--) {
        uInt8[n] = data.charCodeAt(n);
      }
      blob = new Blob([uInt8.buffer], {type: mime});
      formData.append(‘file‘, blob, ‘test.jpg‘);
      xhr.open(‘post‘, ‘/upload‘);
      xhr.send(formData);
    })
  </script>
</body>
</html>

  之前example的canvas版实现了,现在我们加入处理图片的功能。首先我们加入裁剪的功能,裁剪的引入必须先引入橡皮筋功能,就是一个选取框。一般我们见过的选取框是这样的。

预览的样子

选取一部分的样子

  我们来分析下实现这样一个功能需要做什么。首先选取框有个开始点和结束点,在鼠标按下去的时候确定开始点,在松开的时候确定结束点,在移动的时候还要不停的绘制。那么绘制一个有选取框的内容分几步呢?第一步是绘制底图,第二步是绘制阴影,第三部还是绘制底图,但是只作用于选取框内部。最后想取消选取框怎么办,我们还要有个方法重置开始点和结束点,并且只绘制底图。

  我们一步一步来,首先确定开始点和结束点。

var sPoint = {},
        ePoint = {};
    canvas.addEventListener(‘mousedown‘, function(e) {
      if(e.button === 0) {
        sPoint.x = e.offsetX;
        sPoint.y = e.offsetY;
        sPoint.drag = true;
      }
    });

  然后我们确定绘制阴影的的方法,并且在鼠标按下去移动的时候不停的绘制。

function drawCover() {
      ctx.save();
      ctx.fillStyle = ‘rgba(0, 0, 0, 0.3)‘;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.restore();
    }
    canvas.addEventListener(‘mousemove‘, function(e) {
      if(e.button === 0 && sPoint.drag) {var nPoint = {
          x: e.offsetX,
          y: e.offsetY
        };
        ctx.save();    //clip要通过restore回复
        ctx.clearRect(0, 0, canvas.width, canvas.height);    //画布全清
        drawImage();    //绘制底图
        drawCover();    //绘制阴影
        ctx.beginPath();    //开始路径
        ctx.rect(sPoint.x, sPoint.y, nPoint.x - sPoint.x, nPoint.y - sPoint.y);    //设置路径为选取框
        ctx.clip();    //截取路径内为新的作用区域
        drawImage();    //在选取框内绘制底图
        ctx.restore();    //恢复clip截取的作用范围
      }
    });

  最后我们添加松开鼠标的事件监听,松开左键为拖动结束,松开右键为复原

canvas.addEventListener(‘mouseup‘, function(e) {
      if(e.button === 0) {
        sPoint.drag = false;
        ePoint.x = e.offsetX;
        ePoint.y = e.offsetY;
      }else if(e.button === 2) {
        restore();
      }
    });
    function restore() {
      sPoint = {};
      ePoint = {};
      drawImage();
    }

  由于右键会出现恶心的浏览器自带菜单栏,影响体验,我们屏蔽它。

document.addEventListener(‘contextmenu‘, function(e) {
      e.preventDefault();
      e.stopPropagation();
    });

  现在选取框有了,我们要开始截取了。新添加一个按钮,然后添加点击监听。

html代码

<form name=‘test‘>
    <input type="file" name=‘file‘>
    <button id="clip">裁剪</button>
    <input type="submit" value="提交">
  </form>

js代码

var clip = document.querySelector(‘#clip‘);
    clip.addEventListener(‘click‘, function(e) {
  e.preventDefault();    //阻止默认事件,不然会触发form的submit
      if(sPoint.x !== undefined && ePoint.x !== undefined) {
        var imgData = ctx.getImageData(sPoint.x, sPoint.y, ePoint.x - sPoint.x, ePoint.y - sPoint.y);    //把裁剪区域的图片信息提取出来
        ctx.clearRect(0, 0, canvas.width, canvas.height);    //清空画布
        canvas.width = Math.abs(ePoint.x - sPoint.x);    //重置canvas的大小为新图的大小
        canvas.height = Math.abs(ePoint.y - sPoint.y);
        ctx.putImageData(imgData, 0, 0);    //把提取出来的图片信息放进canvas中
        preview.src = canvas.toDataURL();    //裁剪后我们用新图替换底图,方便继续处理
      }else {
        alert(‘没有选择区域‘);
      }
    });

  现在我们裁剪后选择提交,会发现服务器生成的是裁剪后的图片

  裁剪的功能完成了,我们在来实现第二个功能:灰度。如果说裁剪的功能在于clip的用法,那么灰度的实现是基于getImageData返回的对象的认识。这个对象中有一个属性叫data,这是一个数组,以4个为一组,分别存储了一个像素red、green、blue、opacity四个数据。也就是当你的canvas尺寸为1*1时,它的ImageData.data元素为4个。

  废话不多说,直接给出实现的代码。

html代码

<form name=‘test‘>
    <input type="file" name=‘file‘>
    <button id="clip">裁剪</button>
    <button id="grey">灰度</button>
    <input type="submit" value="提交">
  </form>

js代码

var grey = document.querySelector(‘#grey‘);
    grey.addEventListener(‘click‘, function(e) {
  e.preventDefault();
      var startX = 0, startY = 0, width = canvas.width, height = canvas.height;
      ctx.clearRect(0, 0, canvas.width, canvas.height);    //一如既往的先清空画布,不然会处理含有选取框的图片内容
      drawImage();    //绘制底图
      var imgData = ctx.getImageData(startX, startY, width, height);   //把整个底图的图片内容取出来
      for(var i = 0; i < imgData.data.length;) {
        var red = imgData.data[i],
            green = imgData.data[i+1],
            blue = imgData.data[i+2],
            opacity = imgData.data[i+3],    //不处理,可以省去这一行,占位说明这一位是透明度
            average = (red + green + blue) / 3;    //所谓灰度其实是取三种颜色的平均值
        imgData.data[i] = imgData.data[i+1] = imgData.data[i+2] = average;    //三个颜色设为一样即是对应的灰色
        i += 4;
      }
      ctx.putImageData(imgData, startX, startY, 0, 0, width, height);    //把处理过的imagedata放回canvas中
      preview.src = canvas.toDataURL();    //保存图片信息方便再进行处理
    });

  选择灰度并提交,我们看服务器上生成的图片

  最后我们结合裁剪和灰度,一起处理一张图片再提交。

  好了,简单的两个图片处理的方式就介绍到这,至于复杂的,你可以拿到每一个像素的信息,还担心实现不了其他的功能么。

时间: 2024-10-15 14:33:14

从web图片裁剪出发:了解H5中的canvas的相关文章

用H5中的Canvas等技术制作海报

在去年的时候也实现过合成海报的功能,不过当时时间仓促,实现的比较简单. 就一个旋转功能,图片也不能拖动放大,也不能裁剪. 去年的实现可以参考<移动图片操作--上传>和<移动图片操作--预览旋转合成> 这次有时间就实现一个功能稍微多点的海报. 一.概要 第一屏 第二屏 第三屏 总共有三屏,第一屏是选择图片,第二屏是合成图片,第三屏是显示结果图,可保存分享朋友圈. 页面内容不是很多,分析起来也比较简单. 1)每一屏的左右边距相同,上边距各不相同. 2)屏幕内的元素,大部分是居中,有些特

用h5中的canvas 绘制八卦图

1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>canvas绘制八卦图</title> 6 </head> 7 8 <body> 9 <canvas id="canvas" width="600" height="500"><

使用canvas进行图片裁剪简单功能

1.html部分 使用一个input[type="file"]进行图片上传: canvas进行图片的裁剪展示 <div> <input type="file" id="imgFile"> </div> <div id="demoBox" style="width: 300px;height: 300px;position: absolute;left: 300px;top:

JavaScript图片裁剪

1.jquery 图片裁剪库选择 Jcrop:http://deepliquid.com/content/Jcrop.html imgareaselect:http://odyniec.net/projects/imgareaselect/ CropZoom:https://github.com/cropzoom/cropzoom 可供选择的jQuery插件非常多,这里选择 imgareaselect 进行详细演示 2.综合演示效果 2.1 左侧区域是 div + img 标签,用来展示原图,具

从相机相册获取图片裁剪后用于评论晒图或更换背景图

这是我人生中写的第一篇博客,是否要纪念一下这一刻(2016.09.01 16:52).其实关于写博客,老早就有这种写法,首先觉得他能够帮我总结我学到的和用过的技术,其次还能帮助那些和我有一样需求的人,我也是很开心啊,但是至于为什么现在才写第一篇,首先没有想好写什么,然后前段时间也确实比较忙.是不是那些来观技术的人已经想骂人了啊...啊哦!原谅我第一次写博客的激动心情吧! 废话不多说,开始我们的问题吧,首先因为我做了两次关于调用相机和相册获取图片的功能,觉得很有必要总结一下,下面我将从这两个功能出

ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制

我曾经试过使用JSAjaxFileUploader插件来把文件.照片以异步的方式上传,就像"MVC文件图片ajax上传轻量级解决方案,使用客户端JSAjaxFileUploader插件01-单文件上传"中说的,这种方法足够轻.足够好.但今天,要在前面的基础上再增加2个需求: 1.异步判断上传的图片是否超过最大限制2.把上传的图片裁剪成大中小3张图片,分别保存,删除的时候一块被删除 上传图片如果超出最大尺寸限制,终止上传,并报错误信息. 前台上传图片,显示缩略图. 在项目根目录下的指定文

Jcrop图片裁剪

一.引入js和css 二.实现 1.jsp页面 <%-- Created by IntelliJ IDEA. User: a Date: 2019/8/19 Time: 9:36 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %>

Java实现图片裁剪预览功能

Java实现图片裁剪预览功能 在项目中,我们需要做些类似头像上传,图片裁剪的功能,ok看下面文章! 需要插件:jQuery Jcrop 后端代码: package org.csg.upload; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import 

cropper.js图片裁剪

最近做电子名片的项目,可是个人照片展示上出现了 用户上传的图片尺寸严重失调,所以要求进行图片裁剪,再此我对图片裁剪进行调研 还不太成熟 以后再改 这个实现的原理是 前台获取到 坐标 图片的尺寸 原图文件 传给后台进行裁剪 这个是我在网上找的一个插件 cropper功能很强大 这里是官方文档 首先使用cropper必须引入对应得css和js,还有jquery <script src="jquery.js"></script> <link href="