资讯专栏INFORMATION COLUMN

关于前端上传文件全面基础扫盲贴(六) ----- 图片上传,旋转,重绘,预览等实战(附DEMO)

lmxdawn / 1334人阅读

摘要:二编辑合成照片使用编辑压缩重设尺寸比例转成输出预览。三保存并上传照片提交数据到服务器需要服务器支持我跳过了。数据主要来自拍摄的照片,多用于移动端开发,端也会用到,此插件兼容主流浏览器,以下不支持。

系列文章

关于前端上传文件全面基础扫盲贴(零)
关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(三) ----- FormData
关于前端上传文件全面基础扫盲贴(四) ----- FileReader
关于前端上传文件全面基础扫盲贴(五) ----- H5拖拽事件
关于前端上传文件全面基础扫盲贴(六) ----- 图片上传,旋转,重绘,预览等实战(附DEMO)

图片上传,旋转,重绘,预览等实战

距离我上次写的系列文章好像都过了半年了,废话不多说,先来展示一下技术思路

一、获取用户照片数据

获取用户摄像头图片,不是所有手机支持,并且部分手机会有旋转角度的问题;

Input控件获取照片文件。

二、编辑合成照片

使用canvas编辑压缩,重设尺寸比例;

转成base64输出预览。

三、保存并上传照片
提交base64数据到服务器需要服务器支持,我跳过了。

基本结构

因为一般手机像素都很高,所以把原始图片尺寸限制在300里;




  
    
    
    
    
    
    
    
    
    
    
    
  

  
    

原始图片

修改图片

想要上传图片,就要用type="file"获得文件信息,其中下面几个重要属性,(在pc浏览器打开文件要很久,所以可以选择性屏蔽)

属性 描述
accept 表示可以选择的文件MIME类型,多个MIME类型用英文逗号分开
multiple 是否可以选择多个文件,多个文件时其value值为第一个文件的虚拟路径
capture 表示,可以捕获到系统默认的设备,比如:camera--照相机;camcorder--摄像机;microphone--录音

通过监听input变化触发方法

window.onload = function () {
  var dom = document.getElementById("file");
  dom.addEventListener("change", function (e) {});
}
Exif.js

Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。
EXIF 数据主要来自拍摄的照片,多用于移动端开发,PC 端也会用到,此插件兼容主流浏览器,IE10 以下不支持。

为了不让用户等待太久,我们可以在一系列操作之前先展示获取的图片,可以直接从本地先读取出原始数据,然后在页面上展示出来,下面用到的知识点之前已经写过就不再重复了,可以前往浏览文章
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(四) ----- FileReader

var file = e.target.files[0],
  //旋转角度
  orientation = null,
  fReader = new FileReader();

//限制大小格式
if (!filtration(file)) {
  return false;
}

上面的filtration(file)是我抽离出去的过滤函数

filtration: function(file, extend) {
  var extend = extend || {},
    settings = {
      size: extend.size || 5 * 1024 * 1024,
      reg: extend.reg || /image/w+/
    };

  if (file.size > settings.size || !settings.reg.test(file.type)) {
    alert(extend.msg || ("上传格式非图片类型或上传图片超过" + settings.size / 1024 / 1024 + "M"))
    return false;
  }
  return true;
},

接下来要获取图片信息了,解决部分手机会有旋转角度的问题的前提(可能链接格式问题,生成文章之后没带链接,只能自己复制粘贴访问地址了)
中文文档: http://code.ciaoca.com/javasc...
Demo: http://code.ciaoca.com/javasc...

EXIF.getData(file, function () {
  orientation = EXIF.getTag(this, "Orientation");
  console.log("旋转角度: ", orientation);
});

我们已经拿到原始数据,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.然后新建img对象加载资源

//转码完成
fReader.onload = function (e) {
  //加载图片
  var img = new Image();
  img.src = e.target.result;
  img.onload = function () { }
}

//执行
fReader.readAsDataURL(file);

接着我们使用canvas画布重新设定尺寸重绘达到压缩的功能,我只用到基础使用方法,详情(Canvas API)

var canvas = document.createElement("canvas"),
  ctx = canvas.getContext("2d"),
  nSize = resetSize(this, 300, 300, 1, 600);

canvas.width = nSize.width;
canvas.height = nSize.height;
ctx.drawImage(this, 0, 0, nSize.width, nSize.height);

上面的resetSize是我自定义的一个方法,可以设置高宽比例最大范围值,可能有点繁琐,因为我想控制的功能比较多,中间容易发生冲突,我暂时是后面设置能覆盖前面设置(注意:这里的this是上文的data: URL格式)

resetSize: function(img, width, height, ratio, max) {
  var w = img.naturalWidth,
    h = img.naturalHeight,
    width = width || w,
    height = height || h;

  console.log("图片宽高: ", w, h, "入参: ", width, height, ratio, max);

  if (w != width) w = width;
  if (h != height) h = height;
  if (ratio && w / h != ratio) w = h * ratio;

  //限制最大值范围
  if (max) {
    if (w > max && w >= h) {
      h = Math.ceil(h * max / w);
      w = max;
    } else if (h > max && h >= w) {
      w = Math.ceil(w * max / h);
      h = max;
    }
  }
  console.log("重设宽高: ", w, h);
  return { width: w, height: h }
},

接下来就是比较复杂的图形操作了,只要掌握了中心点位置就还好理解,详情(HTML 5 Canvas 参考手册)
上面拿到的orientation不是真的旋转角度,只是给一个值代表拍摄方向,
最后返回新图片展示的 data URI,这里水比较深,我测试了jpg和png是没问题,但是gif什么的就输出一个静态图,详情(toDataURL)

var canvas = document.createElement("canvas"),
  ctx = canvas.getContext("2d"),
  nSize = picProcess.resetSize(this, 600, 400);

switch (+ orientation) {
  case 3:
    canvas.width = nSize.width;
    canvas.height = nSize.height;
    ctx.rotate(180 * Math.PI / 180);
    ctx.drawImage(this, -nSize.width, -nSize.height, nSize.width, nSize.height);
    break;
  case 6:
    canvas.width = nSize.height;
    canvas.height = nSize.width;
    ctx.rotate(90 * Math.PI / 180);
    ctx.drawImage(this, 0, -nSize.height, nSize.width, nSize.height);
    break;
  case 8:
    canvas.width = nSize.height;
    canvas.height = nSize.width;
    ctx.rotate(270 * Math.PI / 180);
    ctx.drawImage(this, -nSize.width, 0, nSize.width, nSize.height);
    break;
  default:
    canvas.width = nSize.width;
    canvas.height = nSize.height;
    ctx.drawImage(this, 0, 0, nSize.width, nSize.height);
    break;
}

return canvas.toDataURL(file.type, 0.8);

现在回看上面,我们已经实现了获取图片,重绘图片,读取本地图片,剩下就是预览了,我简单实现一个支持id和class的方法,也能判断出img和div智能设置展示方式

preview: function(selector, url) {
  var isId = /^#w+/ig.test(selector),
    isClass = /^.w+/ig.test(selector),
    name = selector.slice(1),
    dom = null;

  //选择器类型
  if (isId) {
    dom = document.getElementById(name);
  } else if (isClass) {
    dom = document.getElementsByClassName(name)[0];
  } else {
    alert("选择器传参不支持!");
    return false;
  }

  //判断类型
  if (dom.nodeName == "IMG") {
    dom.src = url;
  } else {
    dom.style.backgroundImage = "url(" + url + ")";
  };
}

然后我们在监听方法里调用就好了.为了更加直观的看到代码效果,我简单写了一个demo版本,可以直接下载本地运行,不依赖任何环境实战Demo

大家且看且珍惜吧,我可能后续还会研究手势旋转处理之类更加复杂的东西,但也说不好,毕竟还是太懒散了.
循例还是得加上一句,因为都没有很深入测试过,所以肯定会有些隐藏的问题,欢迎大家指出最好还有答案咯

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106300.html

相关文章

  • 关于前端上传文件全面基础扫盲(五) ----- H5拖拽事件

    摘要:在中,拖放是标准的一部分,任何元素都能够拖放。如果需要设置允许放置,我们必须阻止对元素的默认处理方式方法。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(二) ----- File关于前端上传文件全面基础扫盲贴(三) ----- FormData关于前端上传文件全面基础扫盲贴(...

    iKcamp 评论0 收藏0
  • 关于前端上传文件全面基础扫盲(二) ----- File

    摘要:为了解救上面说到的问题是向提交的一个草案,旨在推出一套标准的,其基本功能是实现用对本地文件进行操作。出于安全性的考虑,该只对本地文件提供有限的访问。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(二) ----- File关于前端上传文件全面基础扫盲贴(三) ----- For...

    scola666 评论0 收藏0
  • 关于前端上传文件全面基础扫盲(四) ----- FileReader

    摘要:没有浏览器测试,所以不知道是不是有效,其实里面看起来比我写的那个复杂,实际上多了个检验格式上兼容写法所以不要怕,如果我错了记得提醒下我啊。目前为止其实已经该说的都差不多覆盖到了吧,动手能力强的话已经可以根据教程写一个实例出来的了。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(...

    Tony 评论0 收藏0
  • 关于前端上传文件全面基础扫盲(三) ----- FormData

    摘要:如果是传入三个参数的方式,那么该值将是一个布尔值,文件,或者一个,如果不是,将被转成一个字符串可选传给服务器的文件名称一个。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(二) ----- File关于前端上传文件全面基础扫盲贴(三) ----- FormData关于前端上传文...

    developerworks 评论0 收藏0
  • 关于前端上传文件全面基础扫盲(零)

    摘要:表单用于向服务器传输数据。属性对象的属性指定了一个事件句柄函数。标签的属性应当与相关元素的属性相同。详情查阅请狠狠地点击关于对象代表表单中的一个提交按钮在表单提交之前,触发事件句柄,并且一个句柄可以通过返回来取消表单提交。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(二) -...

    SnaiLiu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<