最近写的小 demo,使用的是h5的 canvas来对图片进行放大,移动,剪裁等等
这是最原始的代码,比较接近我的思路,后续会再对格式和结构进行优化

html:

  1. <pre name="code" class="brush: html;" rows="15" cols="300">
  2. <input type="file" name="" accept="image/gif, image/jpeg" id="upload">
  3. <canvas id="showimg" style="border:1px solid #aaa;"></canvas>
  4. <p>移动:</p>
  5. <input type="range" min="0" max="2" id="move" step="0.01" value="1" class="range-control" oninput="translateall()"/><br/>
  6. <button id="crop">剪裁输出</button>
  7. <img id="img" src="" style="border:1px solid #aaa;">

js:初始代码

  1. var img = new Image();
  2. var can = document.getElementById('showimg');
  3. var ctx = can.getContext("2d");
  4. can.width = 500;
  5. can.height = 400;
  6. var fictitious_imgwidth,fictitious_imgheight,flag;
  7. var distance_x = 0;
  8. var distance_y = 0;
  9. var orign_x,orign_y//鼠标点击时的坐标
  10. var present_x,present_y//记录图片做上角的坐标
  11. var substitute_x,substitute_y//暂时记录图片左上角坐标
  12. ctx.fillStyle = "#aaa";
  13. ctx.fillRect(0,0,500,400);
  14. ctx.beginPath();
  15. ctx.moveTo(100,100);
  16. ctx.lineTo(400,100);
  17. ctx.lineTo(400,300);
  18. ctx.lineTo(100,300);
  19. ctx.lineTo(100,100);
  20. ctx.lineWidth = 3;
  21. ctx.strokeStyle = '#333'
  22. ctx.stroke();
  23. ctx.clip();
  24. ctx.closePath();
  25. ctx.clearRect(0, 0, can.width, can.height);
  26. $('#upload').change(function(){
  27. console.log('this is runing')
  28. ctx.clearRect(0, 0, can.width, can.height);
  29.  
  30. img.onload = function(){
  31. fictitious_imgwidth = img.width;
  32. fictitious_imgheight = img.height;
  33. present_x = can.width*0.5-img.width*0.5;
  34. present_y = can.height*0.5-img.height*0.5;
  35. ctx.drawImage(img,present_x,present_y,img.width,img.height);
  36. }
  37. img.src = getFileUrl('upload');
  38.  
  39. })
  40. function translateall(){
  41. var val = document.getElementById("move").value;
  42. reprint(val)
  43. }
  44. function reprint(scale){
  45. ctx.clearRect(0, 0, can.width, can.height);
  46. fictitious_imgwidth = img.width*scale;
  47. fictitious_imgheight = img.height*scale;
  48. check_present();
  49. ctx.drawImage(img,present_x,present_y,fictitious_imgwidth,fictitious_imgheight)
  50. }
  51. function getFileUrl(sourceId) {
  52. var url;
  53. if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
  54. url = document.getElementById(sourceId).value;
  55. } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
  56. url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
  57. } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
  58. url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
  59. }
  60. return url;
  61. }
  62. $('#showimg').mousedown(function(e){
  63. console.log('mousedown is running')
  64. orign_x = e.offsetX;
  65. orign_y = e.offsetY;
  66. judgment_isinimg(e);
  67.  
  68. }).mousemove(function(e){
  69. if(flag){
  70. distance_x = e.offsetX - orign_x;
  71. distance_y = e.offsetY - orign_y;
  72. ctx.clearRect(0, 0, can.width, can.height);
  73. substitute_x = present_x + distance_x;
  74. substitute_y = present_y + distance_y;
  75. ctx.drawImage(img,substitute_x,substitute_y,fictitious_imgwidth,fictitious_imgheight);
  76.  
  77. }
  78. }).mouseleave(function(){
  79. flag = false
  80. present_x = substitute_x;
  81. present_y =substitute_y;
  82. }).mouseup(function(){
  83. flag = false
  84. present_x = substitute_x;
  85. present_y =substitute_y;
  86. })
  87.  
  88. function judgment_isinimg(e){
  89. var ll = present_x
  90. var lt = present_y
  91. var rl = present_x+fictitious_imgwidth
  92. var rt = present_y+fictitious_imgheight
  93.  
  94. var x=event.clientX-can.getBoundingClientRect().left;
  95. var y=event.clientY-can.getBoundingClientRect().top;
  96.  
  97. if(ll < x && x < rl && lt < y && y < rt){
  98. flag = true;
  99. }else{
  100. flag = false;
  101. }
  102. }
  103.  
  104. function check_present(){
  105. if(typeof present_x == 'undefined' || typeof present_y == 'undefined'){
  106. present_x = can.width*0.5-fictitious_imgwidth*0.5;
  107. present_y = can.height*0.5-fictitious_imgheight*0.5;
  108. }
  109. }
  110.  
  111. $('#crop').click(function(){
  112. crop_canvas = document.createElement('canvas');
  113. crop_canvas.width = 300;
  114. crop_canvas.height = 200;
  115. crop_ctx =crop_canvas.getContext('2d')
  116. crop_ctx.fillStyle = "#fff";
  117. crop_ctx.fillRect(0,0,300,200);
  118. check_present();
  119. crop_ctx.drawImage(img,Number(present_x)-100,Number(present_y)-100,fictitious_imgwidth,fictitious_imgheight);
  120. var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
  121. $('#img').attr('src',fullQuality);
  122. })

修改后:

  1. -(function($){
  2. var crop = {
  3. init:function(){
  4. this.img = new Image();
  5. this.can = document.getElementById('showimg');
  6. var ctx = this.ctx = this.can.getContext("2d");
  7. this.width = this.can.width = 500;
  8. this.height = this.can.height = 400;
  9. ctx.fillStyle = "#aaa";
  10. ctx.fillRect(0,0,500,400);
  11. ctx.beginPath();
  12. ctx.moveTo(100,100);
  13. ctx.lineTo(400,100);
  14. ctx.lineTo(400,300);
  15. ctx.lineTo(100,300);
  16. ctx.lineTo(100,100);
  17. ctx.lineWidth = 3;
  18. ctx.strokeStyle = '#333'
  19. ctx.stroke();
  20. ctx.clip();
  21. ctx.closePath();
  22. this.clear();
  23. this.addListen();
  24. },
  25. change:function(){
  26. this.clear();
  27. this.img.onload = function(){
  28. var $this = crop;
  29. $this.img_width = $this.img.width;
  30. $this.img_height = $this.img.height;
  31. $this.fictitious_imgwidth = $this.img_width;
  32. $this.fictitious_imgheight = $this.img_height;
  33. $this.present_x = $this.width*0.5-$this.img_width*0.5;
  34. $this.present_y = $this.height*0.5-$this.img_height*0.5;
  35. $this.ctx.drawImage($this.img,$this.present_x,$this.present_y,$this.img_width,$this.img_height);
  36. }
  37. this.img.src = this.getFileUrl('upload');
  38. },
  39. translate:function(){
  40. var val = document.getElementById("move").value;
  41. this.clear();
  42. this.fictitious_imgwidth = this.img_width*val;
  43. this.fictitious_imgheight = this.img_height*val;
  44. this.ctx.drawImage(this.img,this.present_x,this.present_y,this.fictitious_imgwidth,this.fictitious_imgheight);
  45. },
  46. mouseDown:function(e){
  47. this.orign_x = e.offsetX;
  48. this.orign_y = e.offsetY;
  49. this.judgmentIsInImg(e);
  50. },
  51. mouseMove:function(e){
  52. var e = e || event;
  53. if(this.flag){
  54. this.distance_x = e.offsetX - this.orign_x;
  55. this.distance_y = e.offsetY - this.orign_y;
  56. this.clear();
  57. this.substitute_x = this.present_x + this.distance_x;
  58. this.substitute_y = this.present_y + this.distance_y;
  59. this.ctx.drawImage(this.img,this.substitute_x,this.substitute_y,this.fictitious_imgwidth,this.fictitious_imgheight);
  60. }
  61. },
  62. mouseLeave:function(){
  63. if(this.flag){
  64. this.present_x = this.substitute_x;
  65. this.present_y = this.substitute_y;
  66. this.flag = false;
  67. }
  68.  
  69. },
  70. out:function(){
  71. var crop_canvas = document.createElement('canvas');
  72. crop_canvas.width = 300;
  73. crop_canvas.height = 200;
  74. crop_ctx = crop_canvas.getContext('2d');
  75. crop_ctx.fillStyle = "#fff";
  76. crop_ctx.fillRect(0,0,300,200);
  77. crop_ctx.drawImage(this.img,Number(this.present_x)-100,Number(this.present_y)-100,this.fictitious_imgwidth,this.fictitious_imgheight);
  78. var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
  79. $('#img').attr('src',fullQuality);
  80. },
  81. judgmentIsInImg:function(e){
  82. var e = e || event;
  83. var ll = this.present_x;
  84. var lt = this.present_y;
  85. var rl = this.present_x+this.fictitious_imgwidth;
  86. var rt = this.present_y+this.fictitious_imgheight;
  87.  
  88. var x=e.clientX-this.can.getBoundingClientRect().left;
  89. var y=e.clientY-this.can.getBoundingClientRect().top;
  90.  
  91. if(ll < x && x < rl && lt < y && y < rt){
  92. this.flag = true;
  93. }else{
  94. this.flag = false;
  95. }
  96.  
  97. },
  98. clear:function(){
  99. this.ctx.clearRect(0, 0, this.width, this.height);
  100. },
  101. getFileUrl:function(id){
  102. var url;
  103. try{
  104. if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
  105. url = document.getElementById(id).value;
  106. } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
  107. url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
  108. } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
  109. url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
  110. }
  111. }catch(e){
  112. throw new Error('you can ignore it')
  113. }
  114. return url;
  115. },
  116. addListen:function(){
  117. $('#upload').on('change',this.change.bind(this));
  118. $('#move').on('input',this.translate.bind(this));
  119. $('#showimg').on('mousedown',this.mouseDown.bind(this))
  120. .on('mousemove',this.mouseMove.bind(this))
  121. .on('mouseleave mouseup',this.mouseLeave.bind(this));
  122. $('#crop').on('click',this.out.bind(this));
  123. }
  124. }
  125. return crop.init();
  126. })(jQuery)

如果还有何不足,请多多指正

12.16日修改 因为最近讨论到了头像上传,剪裁的问题,我又对此进行了回顾,发现该 demo 也有不足之处,所以我花了点时间重新修改一下再添加了注释:

最新代码:

  1. -(function($) {
  2. var crop = {
  3. init: function() {
  4. this.img = new Image();
  5. this.can = document.getElementById('showimg');
  6. var ctx = this.ctx = this.can.getContext("2d");
  7. this.width = this.can.width = 500;
  8. this.height = this.can.height = 400;
  9. ctx.fillStyle = "#aaa";
  10. ctx.fillRect(0, 0, 500, 400);
  11. ctx.beginPath();
  12. ctx.moveTo(100, 100);
  13. ctx.lineTo(400, 100);
  14. ctx.lineTo(400, 300);
  15. ctx.lineTo(100, 300);
  16. ctx.lineTo(100, 100);
  17. ctx.lineWidth = 3;
  18. ctx.strokeStyle = '#333'
  19. ctx.stroke();
  20. ctx.clip();
  21. ctx.closePath();
  22. this.clear();
  23. this.addListen();
  24. },
  25. render(src) {
  26. this.img = new Image();
  27. this.img.onload = function() {
  28. var $this = crop;
  29. $this.img_width = $this.img.width; //原图像横坐标
  30. $this.img_height = $this.img.height; //原图像纵坐标
  31. $this.fictitious_imgwidth = $this.img_width; //被缩放的图像横坐标
  32. $this.fictitious_imgheight = $this.img_height; //被缩放的图像纵坐标
  33. //因为后面图像的变化后长度都不是原长度了,后面使用图像长度是就使用fictitious属性
  34. $this.init_x = $this.width * 0.5; //图片中心点横坐标
  35. $this.init_y = $this.height * 0.5; //图片中心点纵坐标
  36. //绘图时同过中心点减去fictitious/2长度来确定图像左上角的坐标
  37. $this.ctx.drawImage($this.img, $this.init_x - $this.img_width / 2, $this.init_y - $this.img_height / 2, $this.img_width, $this.img_height);
  38. };
  39. this.img.src = src;
  40. },
  41. change: function() {
  42. this.clear();
  43. $('#move').val(1) //根据实际需要进行初始化
  44. var reader = new FileReader();
  45. var img = $('#upload').get(0).files[0];
  46.  
  47. reader.onload = function(e) {
  48. crop.render(e.target.result);
  49. };
  50.  
  51. reader.readAsDataURL(img);
  52. },
  53. translate: function() {
  54. var val = document.getElementById("move").value;
  55. this.clear();
  56. this.fictitious_imgwidth = this.img_width * val;
  57. this.fictitious_imgheight = this.img_height * val;
  58. this.ctx.drawImage(this.img, this.init_x - this.fictitious_imgwidth / 2, this.init_y - this.fictitious_imgheight / 2, this.fictitious_imgwidth, this.fictitious_imgheight);
  59. },
  60. mouseDown: function(e) {
  61. this.orign_x = e.offsetX;
  62. this.orign_y = e.offsetY;
  63. this.judgmentIsInImg(e); //判断点击是否在图像内
  64. },
  65. mouseMove: function(e) {
  66. var e = e || event;
  67. if (this.flag) {
  68. this.distance_x = e.offsetX - this.orign_x; //鼠标移动的长度
  69. this.distance_y = e.offsetY - this.orign_y;
  70. this.clear();
  71. this.substitute_x = this.init_x + this.distance_x;
  72. this.substitute_y = this.init_y + this.distance_y;
  73. this.ctx.drawImage(this.img, this.substitute_x - this.fictitious_imgwidth / 2, this.substitute_y - this.fictitious_imgheight / 2, this.fictitious_imgwidth, this.fictitious_imgheight);
  74. }
  75. },
  76. mouseLeave: function() {
  77. if (this.flag) {
  78. this.init_x = this.substitute_x;
  79. this.init_y = this.substitute_y;
  80. this.flag = false;
  81. }
  82.  
  83. },
  84. out: function() {
  85. //输出图像
  86. var crop_canvas = document.createElement('canvas');
  87. crop_canvas.width = 300;
  88. crop_canvas.height = 200;
  89. crop_ctx = crop_canvas.getContext('2d');
  90. crop_ctx.fillStyle = "#fff";
  91. crop_ctx.fillRect(0, 0, 300, 200);
  92. crop_ctx.drawImage(this.img, this.init_x - this.fictitious_imgwidth / 2 - 100, this.init_y - this.fictitious_imgheight / 2 - 100, this.fictitious_imgwidth, this.fictitious_imgheight);
  93. //这边的减去100 是原 canvas 阴影边框的长度
  94. var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
  95. $('#img').attr('src', fullQuality);
  96. },
  97. judgmentIsInImg: function(e) {
  98. var e = e || event;
  99.  
  100. var ll = this.init_x - this.fictitious_imgwidth / 2;
  101. var lt = this.init_y - this.fictitious_imgheight / 2;
  102. var rl = this.init_x + this.fictitious_imgwidth / 2;
  103. var rt = this.init_y + this.fictitious_imgheight / 2;
  104. //图像四个角的坐标
  105.  
  106. var x = e.clientX - this.can.getBoundingClientRect().left;
  107. var y = e.clientY - this.can.getBoundingClientRect().top;
  108.  
  109. if (ll < x && x < rl && lt < y && y < rt) {
  110. this.flag = true;
  111. } else {
  112. this.flag = false;
  113. }
  114.  
  115. },
  116. clear: function() {
  117. this.ctx.clearRect(0, 0, this.width, this.height);
  118. },
  119. addListen: function() {
  120. $('#upload').on('change', this.change.bind(this));
  121. $('#move').on('input', this.translate.bind(this));
  122. $('#showimg').on('mousedown', this.mouseDown.bind(this))
  123. .on('mousemove', this.mouseMove.bind(this))
  124. .on('mouseleave mouseup', this.mouseLeave.bind(this));
  125. $('#crop').on('click', this.out.bind(this));
  126. }
  127. }
  128. return crop.init();
  129. })(jQuery)

修改之后,进行缩放时不是原来的按左上角坐标缩放,而是按图像中心缩放,因为这样的缩放方式,所以不能靠记录图像左上角坐标进行绘制,而是记录图像中心点位置,还解决了手机端的图片获取兼容问题,原来的获取图片 url 方法只能在 PC端有效;

gitHub:https://github.com/Grewer/JsDemo/tree/master/crop

demo:https://grewer.github.io/JsDemo/crop/crop.html

如果这篇文章帮助到了你,请给我一个 star

h5 canvas 图片上传操作的更多相关文章

  1. 移动端H5实现图片上传

    移动端H5实现图片上传 https://segmentfault.com/a/1190000010034177

  2. canvas图片上传相关学习

    今天主要是研究了canvas的关于图片上传的相关知识, context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);  

  3. thinkphp3.2.3 ueditor1.4.3 图片上传操作,在线删除上传图片功能。

    最近弄一个图片 上传,可是用ueditor 自带的上传,如果不配置的话,上传的目录不在自己的项目中. 在网上找了好多,可是都是底版本的,新版本的还真是找到了一个,ueditor-thinkphp 这个 ...

  4. H5 实现图片上传预览

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. ThinkPHP之中的图片上传操作

    直接上个例子,其中包括有单图片文件上传.多图片文件上传.以及删除文件的一些操作.放置删除数据库的时候,仅仅删除掉了数据库之中的文件路径.而不是一并删除服务器之中的文件.放置服务器爆炸... TP里面c ...

  6. h5 端图片上传-模拟多张上传

    1.由于后端的限制,上传图片到服务器只能的一张一张传2.显示图片预览是本地的图片3.根据服务器返回的结果拿到相应的路径保存到提交评论的接口中4.删除的时候,需要删除对应的路径,不要把删除的提交到评论的 ...

  7. h5 端图片上传

    1.upload.js (function($) { $.extend($.fn, { images : new Array(), initImages:function (images) { $.e ...

  8. H5 选择图片上传及预览

    <div class="sctp"> <img src="img/sczp.png" id="photo" alt=&qu ...

  9. vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理

    一.前言 三年.net开发转前端已经四个月了,前端主要用webpack+vue,由于后端转过来的,前端不够系统,希望分享下开发心得与园友一起学习. 图片的上传之前都是用的插件(ajaxupload), ...

随机推荐

  1. CSS滤镜效果

    使用 filter: blur() 生成毛玻璃效果 使用 filter: drop-shadow() 生成整体阴影效果 使用 filter: opacity() 生成透明度 blur生成阴影 通常我们 ...

  2. 2017-03-02学习心得之Java代码

    package com.lovo.classes;import java.util.Random;import java.util.TreeSet;import java.util.Scanner;p ...

  3. CentOS 6.5 中安装 Mysql 5.6,并远程连接Mysql

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.在安装CentOS时,若选择的是Basic Server(可支持J2EE开发),则新安装好的CentOS系统中默认是已经安装了一个mysq ...

  4. Appium python自动化测试系列之Android UIAutomator终极定位(七)

    android uiautomator text定位 可能有人不知道为什么说android uiautomator是终极定位,而且android uiautomator和appium有什么关系呢?如果 ...

  5. maven的java web项目启动找不到Spring ContextLoaderListener的解决办法

    用maven搭建的java web项目,上传到git仓库后,当同事clone下来项目,部署到tomcat运行时,就报了如下错误,即启动web项目时,加载web.xml文件,找不到spring的监听器, ...

  6. Hi Java!!!---来自十八岁的程序员随笔

    9月23日我正式加入了程序员的行列,在哪以前我都不知道程序员到底是干嘛的,电脑对于我来说也不过是打打游戏,玩玩QQ.转眼间一个月了,我真正的喜欢上了这门行业,当自己写出一个程序的时候特别有成就感,哪怕 ...

  7. Hadoop(十一)Hadoop IO之序列化与比较功能实现详解

    前言 上一篇给大家介绍了Hadoop是怎么样保证数据的完整性的,并且使用Java程序来验证了会产生.crc的校验文件.这一篇给大家分享的是Hadoop的序列化! 一.序列化和反序列化概述 1.1.序列 ...

  8. LeetCode 548. Split Array with Equal Sum (分割数组使得子数组的和都相同)$

    Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies fol ...

  9. MySql数据库的基本原理及指令

    1.什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加,修改,删除及查询操作. 2.简介 MySQL是一个开放源 ...

  10. bug:记最近出现的非功能bug

    1.android 4.1.2 的兼容bug 一直以为Android 测试 4 5 6就可以了,结果发现Android4.1.2 和Android4.3之间还是有差距的. 处理办法:验证版本兼容的时候 ...