Maison  >  Article  >  interface Web  >  Comment implémenter des captures d'écran locales avec le canevas HTML5 et JavaScript

Comment implémenter des captures d'écran locales avec le canevas HTML5 et JavaScript

不言
不言original
2018-06-22 15:38:124931parcourir

Cet article présente principalement l'implémentation du canevas JavaScript+html5 du didacticiel de capture d'écran locale. Les amis intéressés par la fonction de capture d'écran peuvent s'y référer

J'ai récemment eu le temps de découvrir les différentes API de HTML5 et j'ai trouvé. que les paramètres de l'avatar de Sina Weibo Bo sont pris à l'aide de Canvas pour réaliser des captures d'écran. Il y a quelque temps, j'ai découvert l'API File de html5 et j'ai utilisé FileReader de l'API File pour implémenter les téléchargements de fichiers "Aperçu du téléchargement de fichiers de l'API de fichier JavaScript Je pense que html5 est encore plus amusant. J'ai pensé à essayer d'écrire cette fonction pour apprendre le canevas. Ce qui suit est une démo que j'ai écrite moi-même. Le code est relativement petit et je ne sais pas comment gérer de nombreux détails. S'il y a quelque chose d'inapproprié, veuillez nous en informer, merci ^_^ ^_^
Étapes de mise en œuvre de la fonction :

  • 1. Obtenez le fichier , lisez le fichier et générez l'url

  • 2. Utilisez la toile pour dessiner des images en fonction de la taille du conteneur

  • 3. Utilisez la toile pour dessiner le calque du masque

  • 4. Utilisez la toile pour dessiner l'image recadrée

  • 5. Faites glisser la zone de recadrage et re- Recadrez l'image

PS : Parce que j'ai d'abord écrit la démo, puis écrit cet article, le code est affiché en sections est directement à partir du code Copiez-le morceau par morceau, faites attention à cet objet


Étape 1 : Récupérez le fichier, lisez le fichier et générez l'URLIci j'utilise le fichier api en html5 pour gérer les téléchargements de fichiers locaux, car cela élimine le besoin de télécharger l'image sur le serveur, puis le serveur renvoie l'adresse de l'image pour un aperçu. Pour plus de détails, veuillez consulter : Utilisation de FileReader de l'API de fichier pour implémenter le téléchargement de fichiers

document.getElementById('post_file').onchange = function() {
  var fileList = this.files[0];
  var oFReader = new FileReader();
  oFReader.readAsDataURL(fileList);
  oFReader.onload = function (oFREvent) { //当读取操作成功完成时调用.
    postFile.paintImage(oFREvent.target.result);//把预览图片url传给函数
  };
}  

Étape 2 : Utilisez la toile pour dessiner des images en fonction de la taille du conteneur

À l'étape précédente , le FileReader utilisant l'API File a déjà obtenu l'adresse de l'image qui doit être téléchargée. Ensuite, vous devez utiliser Canvas pour dessiner cette image. Pourquoi ne pas insérer directement l'image ici et la redessiner avec du canevas ? Pas vraiment. Si vous utilisez img pour l'insérer directement dans la page, vous ne pourrez pas centrer de manière adaptative. Si vous utilisez canevas pour dessiner l'image, cela permettra non seulement à l'image d'être centrée et mise à l'échelle de manière adaptative, mais cela la rendra également. plus facile de transmettre les coordonnées et la taille de l'image au calque de masque suivant. Cela permet de dessiner le calque de masque en fonction des coordonnées de l'image et de la taille de l'image.

Une petite attention doit être accordée à la méthode drawImage du canevas ici.



paintImage: function(url) {
  var t = this;
  var createCanvas = t.getImage.getContext("2d");
  var img = new Image();
  img.src = url;
  img.onload = function(){
 
    //等比例缩放图片(如果图片宽高都比容器小,则绘制的图片宽高 = 原图片的宽高。)
    //如果图片的宽度或者高度比容器大,则宽度或者高度 = 容器的宽度或者高度,另一高度或者宽度则等比例缩放
    //t.imgWidth:绘制后图片的宽度;t.imgHeight:绘制后图片的高度;t.px:绘制后图片的X轴;t.py:绘制后图片的Y轴
    if ( img.width < t.regional.offsetWidth && img.height < t.regional.offsetHeight) {
      t.imgWidth = img.width;
      t.imgHeight = img.height;
 
    } else {
      var pWidth = img.width / (img.height / t.regional.offsetHeight);
      var pHeight = img.height / (img.width / t.regional.offsetWidth);
      t.imgWidth = img.width > img.height ? t.regional.offsetWidth : pWidth;
      t.imgHeight = img.height > img.width ? t.regional.offsetHeight : pHeight;
    }
    //图片的坐标
    t.px = (t.regional.offsetWidth - t.imgWidth) / 2 + &#39;px&#39;;
    t.py = (t.regional.offsetHeight - t.imgHeight) / 2 + &#39;px&#39;;
     
    t.getImage.height = t.imgHeight;
    t.getImage.width = t.imgWidth;
    t.getImage.style.left = t.px;
    t.getImage.style.top = t.py;
 
    createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight);//没用直接插入背景图片而用canvas绘制图片,是为了调整所需框内图片的大小
    t.imgUrl = t.getImage.toDataURL();//储存canvas绘制的图片地址
    t.cutImage();
    t.drag();
  };
},
 

L'effet est comme ceci :


Étape 3 : Utilisez le canevas pour dessiner le calque de masque

À l'étape précédente, vous avez dessiné l'image d'arrière-plan qui doit être recadrée. Vous devez maintenant dessiner le calque de masque pour couvrir l'arrière-plan en fonction des coordonnées. et la taille de l'image d'arrière-plan ci-dessus, et utilisez la méthode clearRect du canevas pour effacer une zone recadrée afin qu'elle puisse être contrastée avec la zone non recadrée.
(Le calque de masque ici est uniquement utilisé pour l'effet d'affichage et ne fait pas le travail de recadrage de l'image. Je ne sais pas si cette étape peut être supprimée directement ? Si quelqu'un le sait, dites-le-moi.)


//绘制遮罩层:
t.editBox.height = t.imgHeight;
t.editBox.width = t.imgWidth;
t.editBox.style.display = &#39;block&#39;;
t.editBox.style.left = t.px;
t.editBox.style.top = t.py;
 
var cover = t.editBox.getContext("2d");
cover.fillStyle = "rgba(0, 0, 0, 0.5)";
cover.fillRect (0,0, t.imgWidth, t.imgHeight);
cover.clearRect(t.sx, t.sy, t.sHeight, t.sWidth);
 

Étape 4 : Utilisez le canevas pour dessiner l'image recadrée

Dans la troisième étape, dessinez le calque de masque, mais le calque de masque n'a pas la capacité de recadrer. Il sert uniquement à afficher la comparaison entre la zone recadrée et la zone non recadrée, voici donc la fonction de recadrage de l'image. Utilisez également la méthode drawImage de canvas.

//绘制剪切图片:
t.editPic.height = t.sHeight;
t.editPic.width = t.sWidth;
var ctx = t.editPic.getContext(&#39;2d&#39;);
var images = new Image();
images.src = t.imgUrl;
images.onload = function(){
  ctx.drawImage(images,t.sx, t.sy, t.sHeight, t.sWidth, 0, 0, t.sHeight, t.sWidth); //裁剪图片
  document.getElementById(&#39;show_edit&#39;).getElementsByTagName(&#39;img&#39;)[0].src = t.editPic.toDataURL(); //把裁剪后的图片使用img标签显示出来
}

Étape 5 : faites glisser la zone de recadrage et recadrez l'image

Utilisez le téléchargement de capture d'écran fonction avatar Parfois, nous espérons recadrer une image satisfaisante, le cadre de recadrage doit donc être constamment modifié pour recadrer une image parfaite. La fonction de base de recadrage des images a été complétée dans les étapes précédentes, il ne reste donc plus qu'à suivre le mouvement de la souris pour recadrer l'image en temps réel.

drag: function() {
  var t = this;
  var draging = false;
  var startX = 0;
  var startY = 0;
 
  document.getElementById(&#39;cover_box&#39;).onmousemove = function(e) {
    //获取鼠标到背景图片的距离
    var pageX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
    var pageY = e.pageY - ( t.regional.offsetTop + this.offsetTop );
    //判断鼠标是否在裁剪区域里面:
    if ( pageX > t.sx && pageX < t.sx + t.sWidth && pageY > t.sy && pageY < t.sy + t.sHeight ) {
      this.style.cursor = &#39;move&#39;;
       
      this.onmousedown = function(){
        draging = true;
        //记录上一次截图的坐标
        t.ex = t.sx;
        t.ey = t.sy;
        //记录鼠标按下时候的坐标
        startX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
        startY = e.pageY - ( t.regional.offsetTop + this.offsetTop );
      }
      window.onmouseup = function() {
        draging = false;
      }
       
      if (draging) {
        //移动时裁剪区域的坐标 = 上次记录的定位 + (当前鼠标的位置 - 按下鼠标的位置),裁剪区域不能超出遮罩层的区域;
        if ( t.ex + (pageX - startX) < 0 ) {
          t.sx = 0;
        } else if ( t.ex + (pageX - startX) + t.sWidth > t.imgWidth) {
          t.sx = t.imgWidth - t.sWidth;
        } else {
          t.sx = t.ex + (pageX - startX);
        };
 
        if (t.ey + (pageY - startY) < 0) {
          t.sy = 0;
        } else if ( t.ey + (pageY - startY) + t.sHeight > t.imgHeight ) {
          t.sy = t.imgHeight - t.sHeight;
        } else {
          t.sy = t.ey + (pageY - startY);
        }
 
        t.cutImage();
      }
    } else{
      this.style.cursor = &#39;auto&#39;;
    }
  };
}  

Vous avez terminé, la photo est la suivante :


Certaines chaussures pour enfants l'ont souligné, ne serait-il pas très gourmand en performances de recadrer une image à chaque fois que vous déplacez la souris ? Pourquoi ne pas utiliser la position d'arrière-plan pour créer l'effet d'aperçu, puis utiliser le canevas pour la recadrer lors de l'enregistrement ? Quand je l'ai entendu, j'ai pensé que cette suggestion avait du sens, j'ai donc légèrement modifié le code à la quatrième étape. L'effet d'aperçu lorsque la souris bouge consiste à modifier la position d'arrière-plan de l'image. L'image est recadrée lorsque vous cliquez sur le bouton Enregistrer. Générez une nouvelle URL pour l'image recadrée, puis envoyez-la au serveur ~~

Le. le code suivant est corrigé, si vous avez d'autres bonnes suggestions, merci de les signaler ^_^ ^_^

Le code complet de la démo est le suivant :
Remarque : Parce qu'il est écrit en seajs, alors payez une petite attention au chargement du fichier
css:

body{text-align:center;}
#label{border:1px solid #ccc;background-color:#fff;text-align:center;height:300px; width:300px;margin:20px auto;position:relative;}
#get_image{position:absolute;}
#edit_pic{position:absolute;display:none;background:#000;}
#cover_box{position: absolute;z-index: 9999;display:none;top:0px;left:0px;}
#show_edit{margin: 0 auto;display:inline-block;}
#show_pic{height:100px;width:100px;border:2px solid #000;overflow:hidden;margin:0 auto;display:inline-block; }

html: 

<input type="file" name="file" id="post_file">
<button id="save_button">保存</button>
<p id="label">
  <canvas id="get_image"></canvas>
  <p>
    <canvas id="cover_box"></canvas>
    <canvas id="edit_pic"></canvas>
  </p>
</p>
<p>
  <span id="show_edit"></span>
  <span id="show_pic"><img src=""></span>
</p>


<script type="text/javascript" src="../../lib/seajs/sea.js"></script>
<script type="text/javascript">
seajs.use([&#39;_example/fileAPI/index_v2.js&#39;], function(clipFile) {
  clipFile.init({
    clipPos: {    //裁剪框的默认尺寸与定位
      x: 15,
      y: 15,
      height: 100,
      width: 100,
    },
  });
});

</script> 

js:

define(function(require, exports, module) {

  &#39;use strict&#39;;

  var postFile = {
    init: function(options) {
      var t = this;
      t.regional = document.getElementById(&#39;label&#39;);
      t.getImage = document.getElementById(&#39;get_image&#39;);
      t.clipPic = document.getElementById(&#39;edit_pic&#39;);
      t.coverBox = document.getElementById(&#39;cover_box&#39;);
      t.achieve = document.getElementById(&#39;show_edit&#39;);

      t.clipPos = options.clipPos;

      //初始化图片基本参数
      t.bgPagePos = {     
        x: 0,
        y: 0,
        height: 0,
        width: 0
      };

      //传进图片
      document.getElementById(&#39;post_file&#39;).addEventListener("change", t.handleFiles, false);

      //点击保存按钮后再裁剪图片
      document.getElementById(&#39;save_button&#39;).onclick = function() {

        //绘制剪切后的图片:
        t.clipPic.height = t.clipPos.height;
        t.clipPic.width = t.clipPos.width;

        var ctx = t.clipPic.getContext(&#39;2d&#39;);
        var images = new Image();
        images.src = t.imgUrl;
        images.onload = function(){

          //drawImage(images,相对于裁剪图片的X, 相对于裁剪图片的Y, 裁剪的高度, 裁剪的宽度, 显示在画布的X, 显示在画布的Y, 显示在画布多高, 显示在画布多宽);
          ctx.drawImage(images,t.clipPos.x, t.clipPos.y, t.clipPos.height, t.clipPos.width, 0, 0, t.clipPos.height, t.clipPos.width); //裁剪图片
          
          document.getElementById(&#39;show_pic&#39;).getElementsByTagName(&#39;img&#39;)[0].src = t.clipPic.toDataURL();
        }
      };

      t.drag();
    },
    handleFiles: function() {

      var fileList = this.files[0];
      var oFReader = new FileReader();

      //读取文件内容
      oFReader.readAsDataURL(fileList);

      //当读取操作成功完成时调用.
      oFReader.onload = function (oFREvent) { 

        //把预览图片URL传给函数
        postFile.paintImage(oFREvent.target.result);
      };
    },
    paintImage: function(url) {
      var t = this;
      var createCanvas = t.getImage.getContext("2d");

      var img = new Image();
      img.src = url;

      //把传进来的图片进行等比例缩放
      img.onload = function(){
        //等比例缩放图片(如果图片宽高都比容器小,则绘制的图片宽高 = 原图片的宽高。)
        //如果图片的宽度或者高度比容器大,则宽度或者高度 = 容器的宽度或者高度,另一高度或者宽度则等比例缩放

        //t.bgPagePos.width:绘制后图片的宽度;
        //t.bgPagePos.height:绘制后图片的高度;
        //t.bgPagePos.x:绘制后图片的X轴;
        //t.bgPagePos.y:绘制后图片的Y轴
        if ( img.width < t.regional.offsetWidth && img.height < t.regional.offsetHeight) {
          t.bgPagePos.width = img.width;
          t.bgPagePos.height = img.height;

        } else {
          var pWidth = img.width / (img.height / t.regional.offsetHeight);
          var pHeight = img.height / (img.width / t.regional.offsetWidth);

          t.bgPagePos.width = img.width > img.height ? t.regional.offsetWidth : pWidth;
          t.bgPagePos.height = img.height > img.width ? t.regional.offsetHeight : pHeight;
        }

        //图片的坐标
        t.bgPagePos.x = (t.regional.offsetWidth - t.bgPagePos.width) / 2 + &#39;px&#39;;
        t.bgPagePos.y = (t.regional.offsetHeight - t.bgPagePos.height) / 2 + &#39;px&#39;;
        
        t.getImage.height = t.bgPagePos.height;
        t.getImage.width = t.bgPagePos.width;
        t.getImage.style.left = t.bgPagePos.x;
        t.getImage.style.top = t.bgPagePos.y;

        createCanvas.drawImage(img,0,0,t.bgPagePos.width,t.bgPagePos.height);//没用直接插入背景图片而用canvas绘制图片,是为了调整所需框内图片的大小
        
        t.imgUrl = t.getImage.toDataURL();//储存canvas绘制的图片地址

        t.clipImg();
      };
    },
    clipImg: function() {
      var t = this;

      //绘制遮罩层:
      t.coverBox.height = t.bgPagePos.height;
      t.coverBox.width = t.bgPagePos.width;
      t.coverBox.style.display = &#39;block&#39;;
      t.coverBox.style.left = t.bgPagePos.x;
      t.coverBox.style.top = t.bgPagePos.y;

      var cover = t.coverBox.getContext("2d");
      cover.fillStyle = "rgba(0, 0, 0, 0.5)";
      cover.fillRect (0,0, t.bgPagePos.width, t.bgPagePos.height);
      cover.clearRect(t.clipPos.x, t.clipPos.y, t.clipPos.height, t.clipPos.width);

      t.achieve.style.background = &#39;url(&#39; + t.imgUrl + &#39;)&#39; + -t.clipPos.x + &#39;px &#39; + -t.clipPos.y + &#39;px no-repeat&#39;;
      t.achieve.style.height = t.clipPos.height + &#39;px&#39;;
      t.achieve.style.width = t.clipPos.width + &#39;px&#39;;
    },
    drag: function() {
      var t = this;
      var draging = false;
      var _startPos = null;

      t.coverBox.onmousemove = function(e) {
        e = e || window.event;

        if ( e.pageX == null && e.clientX != null ) {

          var doc = document.documentElement, body = document.body;

          e.pageX = e.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
          e.pageY = e.clientY + (doc && doc.scrollTop || body && body.scrollTop);
        }

        //获取鼠标到背景图片的距离
        var _mousePos = {
          left: e.pageX - ( t.regional.offsetLeft + this.offsetLeft ),
          top: e.pageY - ( t.regional.offsetTop + this.offsetTop )
        }

        //判断鼠标是否在裁剪区域里面:
        if ( _mousePos.left > t.clipPos.x && _mousePos.left < t.clipPos.x + t.clipPos.width && _mousePos.top > t.clipPos.y && _mousePos.top < t.clipPos.y + t.clipPos.height ) {
          this.style.cursor = &#39;move&#39;;
          
          this.onmousedown = function(){
            draging = true;
            //记录上一次截图的坐标
            t.ex = t.clipPos.x; 
            t.ey = t.clipPos.y;

            //记录鼠标按下时候的坐标
            _startPos = {
              left: e.pageX - ( t.regional.offsetLeft + this.offsetLeft ),
              top: e.pageY - ( t.regional.offsetTop + this.offsetTop )
            }
          }

          if (draging) {
            //移动时裁剪区域的坐标 = 上次记录的定位 + (当前鼠标的位置 - 按下鼠标的位置),裁剪区域不能超出遮罩层的区域;
            if ( t.ex + ( _mousePos.left - _startPos.left ) < 0 ) {
              t.clipPos.x = 0;
            } else if ( t.ex + ( _mousePos.left - _startPos.left ) + t.clipPos.width > t.bgPagePos.width ) {
              t.clipPos.x = t.bgPagePos.width - t.clipPos.width;
            } else {
              t.clipPos.x = t.ex + ( _mousePos.left - _startPos.left );
            };

            if (t.ey + ( _mousePos.top - _startPos.top ) < 0) {
              t.clipPos.y = 0;
            } else if ( t.ey + ( _mousePos.top - _startPos.top ) + t.clipPos.height > t.bgPagePos.height ) {
              t.clipPos.y = t.bgPagePos.height - t.clipPos.height;
            } else {
              t.clipPos.y = t.ey + ( _mousePos.top - _startPos.top );
            }

            t.clipImg();
          }

          document.body.onmouseup = function() {
            draging = false;
            document.onmousemove = null;
            document.onmouseup = null;
          }
        } else{
          this.style.cursor = &#39;auto&#39;;
        }
      };
    }
  }
  return postFile;
});

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

如何在canvas里面基于随机点绘制一个多边形

H5实现图片压缩与上传

在HTML5 Canvas中放入图片和保存为图片的方法

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn