Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie lokale Screenshots mit HTML5-Canvas und JavaScript

So implementieren Sie lokale Screenshots mit HTML5-Canvas und JavaScript

不言
不言Original
2018-06-22 15:38:124984Durchsuche

In diesem Artikel wird hauptsächlich die JavaScript + HTML5-Canvas-Implementierung des lokalen Screenshot-Tutorials vorgestellt. Freunde, die sich für die Screenshot-Funktion interessieren, können darauf zurückgreifen.

Ich hatte kürzlich Zeit, mich über die verschiedenen APIs von HTML5 zu informieren und habe sie gefunden Vor einiger Zeit habe ich die Datei-API von HTML5 kennengelernt und den FileReader der Datei-API verwendet, um Datei-Uploads zu implementieren „JavaScript File API File Upload Preview“. > Ich finde, dass HTML5 noch mehr Spaß macht. Ich habe darüber nachgedacht, diese Funktion zu schreiben, um Canvas zu lernen. Das Folgende ist eine Demo, die ich selbst geschrieben habe. Der Code ist relativ klein und ich weiß nicht, wie ich mit vielen Details umgehen soll. Wenn etwas unangemessen ist, teilen Sie uns dies bitte mit. Vielen Dank^_^ ^_^
Funktionsimplementierungsschritte:

  • 1. Holen Sie sich die Datei , lesen Sie die Datei und generieren Sie die URL

  • 2. Verwenden Sie die Leinwand, um Bilder entsprechend der Größe des Containers zu zeichnen

  • 3. Verwenden Sie die Leinwand, um die Maskenebene zu zeichnen

  • 4. Zeichnen Sie das zugeschnittene Bild auf Leinwand

  • 5. Ziehen Sie das Zuschneidefeld und schneiden Sie das Bild erneut zu

PS: Da ich zuerst die Demo und dann diesen Artikel geschrieben habe, wurde der Code in Abschnitten veröffentlicht ist direkt aus dem Code. Kopieren Sie es Stück für Stück, achten Sie auf dieses Objekt


Schritt 1: Holen Sie sich die Datei, lesen Sie die Datei und generieren Sie die URLHier verwende ich die Datei-API in HTML5 um lokale Datei-Uploads zu verarbeiten, da dadurch das Hochladen des Bildes auf den Server entfällt und der Server dann die Bildadresse zur Vorschau zurückgibt. Weitere Informationen finden Sie unter: Verwenden des FileReader der Datei-API zum Implementieren des Datei-Uploads

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传给函数
  };
}  

Schritt 2: Verwenden Sie die Leinwand, um Bilder entsprechend der Größe des Behälters zu zeichnen

Im vorherigen Schritt wurde das FileReader der Datei-API wurde verwendet, um die Adresse des Bildes abzurufen, das hochgeladen werden muss. Als Nächstes müssen Sie Canvas verwenden, um dieses Bild zu zeichnen. Warum das Bild nicht direkt hier einfügen und mit Canvas neu zeichnen? Ist das nicht unnötig? Nicht wirklich. Wenn Sie „img“ verwenden, um es direkt in die Seite einzufügen, wird es nicht adaptiv zentriert. Wenn Sie Canvas zum Zeichnen des Bildes verwenden, ermöglicht dies nicht nur die adaptive Zentrierung und Skalierung des Bildes, sondern erleichtert auch die Anpassung Übergeben Sie die Koordinaten und die Größe des Bildes an die nachfolgende Maskenebene. Dadurch kann die Maskenebene basierend auf den Koordinaten des Bildes und der Größe des Bildes gezeichnet werden.

Ein wenig Aufmerksamkeit sollte hier der drawImage-Methode von Canvas gewidmet werden.

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();
  };
},
 

Der Effekt ist so:


Schritt 3: Verwenden Sie die Leinwand, um die Maskenebene zu zeichnen
Im vorherigen Schritt haben Sie das Hintergrundbild gezeichnet, das zugeschnitten werden muss. Jetzt müssen Sie die Maskenebene basierend auf den Koordinaten und der Größe des Hintergrundbilds zeichnen um den Hintergrund abzudecken. Und verwenden Sie die Methode „clearRect“ der Leinwand, um einen zugeschnittenen Bereich zu löschen, damit er mit dem nicht zugeschnittenen Bereich kontrastiert werden kann.
(Die Maskenebene dient hier nur dem Anzeigeeffekt und übernimmt nicht die Aufgabe, das Bild zuzuschneiden. Ich weiß nicht, ob dieser Schritt direkt entfernt werden kann? Wenn jemand es weiß, sagen Sie es mir bitte.)

//绘制遮罩层:
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);
 

Schritt 4: Zeichnen Sie das zugeschnittene Bild mit der Leinwand Zeichnen Sie im dritten Schritt jedoch die Maskenebene. Die Maskenebene verfügt nicht über die Möglichkeit zum Zuschneiden. Sie dient nur zur Anzeige des Vergleichs zwischen dem zugeschnittenen Bereich und dem nicht zugeschnittenen Bereich. Hier handelt es sich also um die Funktion zum Zuschneiden des Bildes. Verwenden Sie auch die drawImage-Methode von 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标签显示出来
}

Schritt 5: Ziehen Sie das Zuschneidefeld und schneiden Sie das Bild erneut zu
Bei Verwendung des Screenshots laden Sie den Avatar hoch Ich hoffe, dass wir mit dieser Funktion ein zufriedenstellendes Bild zuschneiden können, daher muss der Zuschneiderahmen ständig geändert werden, um ein perfektes Bild zuzuschneiden. Die Grundfunktion zum Zuschneiden von Bildern wurde in den vorherigen Schritten abgeschlossen. Jetzt müssen Sie nur noch der Bewegung der Maus folgen, um das Bild in Echtzeit zuzuschneiden.

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;;
    }
  };
}  

Fertig, das Bild sieht wie folgt aus:


Einige Kinderschuhe wiesen darauf hin, dass es nicht sehr leistungsintensiv ist, ein Bild einfach durch Bewegen der Maus zuzuschneiden. Warum nicht die Hintergrundposition verwenden, um den Vorschaueffekt zu erzielen, und es dann beim Speichern mit der Leinwand zuschneiden? Als ich davon hörte, hielt ich diesen Vorschlag für sinnvoll und änderte daher im vierten Schritt den Code leicht. Der Vorschaueffekt beim Bewegen der Maus besteht darin, die Hintergrundposition des Bildes zu ändern, wenn auf die Schaltfläche „Speichern“ geklickt wird. Erstellen Sie eine neue URL für das zugeschnittene Bild und senden Sie es an den Server Der folgende Code wurde korrigiert. Wenn Sie weitere gute Vorschläge haben, weisen Sie diese bitte darauf hin ^_^ ^_^

Der vollständige Code der Demo lautet wie folgt:
Hinweis: Da er in Seajs geschrieben ist, zahlen Sie also eine kleine Aufmerksamkeit zum Laden der Datei
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中放入图片和保存为图片的方法

Das obige ist der detaillierte Inhalt vonSo implementieren Sie lokale Screenshots mit HTML5-Canvas und JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn