Heim > Web-Frontend > js-Tutorial > Hauptteil

Wie verwende ich die Komprimierungs- und Upload-Funktion für mobile Frontend-Bilder?

亚连
Freigeben: 2018-06-22 15:51:59
Original
1180 Leute haben es durchsucht

Der unten stehende Redakteur zeigt Ihnen ein Beispiel für die Komprimierung und das Hochladen von Bildern im mobilen Frontend. Es hat einen sehr guten Referenzwert und ich hoffe, dass es für alle hilfreich sein wird. Lassen Sie den Redakteur kommen und gemeinsam einen Blick darauf werfen

Zusammenfassung: Ich habe zuvor an einem kleinen Spieleplattformprojekt gearbeitet und es gab ein „User Center“-Modul. Dazu gehörte auch die Funktion zum Hochladen von Avataren. Beim Hochladen von Bildern auf das mobile Endgerät handelt es sich bei allen hochgeladenen Bildern um lokale Bilder des Mobiltelefons. Bei aktuellen Smartphones sind viele Bilder normalerweise zwei bis drei Megabyte groß Wenn der Benutzer mobile Daten verwendet, ist es offensichtlich keine gute Idee, das Bild vollständig hochzuladen. Daher ist es notwendig, vor dem Hochladen eine Komprimierung durchzuführen. Ich habe viele Methoden ausprobiert und bin auf viele Fallstricke gestoßen. Android kann beispielsweise Bilder erfolgreich komprimieren und hochladen Es hat lange gedauert, bis ich etwas über iOS Pit herausgefunden habe. Dies hat sich in der Praxis als machbar erwiesen. Bilder von mehreren Megabyte können innerhalb der von unserem Backend geforderten 200 KB komprimiert werden! Solch eine praktikable Methode muss jedem gezeigt werden [ps: Sie werden alle durch das Zusammenfügen der Methoden anderer Leute erstellt, hehe~].

Derzeit wurden verschiedene neue APIs von HTML5 gut im mobilen Webkit implementiert. Laut caniuse wurden die in dieser Demo verwendeten FileReader-, Blob- und Formdata-Objekte in den meisten Browsern für mobile Geräte (Safari 6.0+, Android 3.0+) implementiert, sodass das Komprimieren von Bildern direkt im Frontend zu einem wesentlichen Bestandteil geworden ist Funktionen zum Hochladen von Bildern auf mobile Geräte.

Das Komprimieren und Hochladen von Bildern auf dem mobilen Endgerät nutzt hauptsächlich die drei h5-APIs Filereader, Canvas und Formdata. Die Logik ist nicht schwierig. Der gesamte Prozess ist:

(1) Wenn der Benutzer die Eingabedatei zum Hochladen eines Bildes verwendet, verwenden Sie den Dateireader, um die vom Benutzer hochgeladenen Bilddaten zu lesen (Base64-Format)

(2) Bestanden die Bilddaten in ein img-Objekt, dann img auf die Leinwand zeichnen und dann canvas.toDataURL aufrufen, um das Bild zu komprimieren

(3) Erhalten Sie die komprimierten Bilddaten im Base64-Format, konvertieren Sie sie in eine Binärdatei und fügen Sie sie in formdata ein. und übermitteln Sie dann die Formulardaten über XmlHttpRequest.

In diesen drei Schritten sind die Bildkomprimierung und das Hochladen abgeschlossen.

Es klingt einfach, aber tatsächlich gibt es dennoch einige Fallstricke. Als nächstes verwenden Sie den Code zur direkten Analyse:

[1] Holen Sie sich die Bilddaten

Rufen Sie zuerst die Bilddaten ab, die überwacht werden sollen Führen Sie das Änderungsereignis der Eingabedatei durch, rufen Sie dann die hochgeladenen Dateiobjektdateien ab, konvertieren Sie die arrayähnlichen Dateien in ein Array und führen Sie dann eine forEach-Durchquerung durch.

Bestimmen Sie dann den Dateityp. Wenn es sich nicht um ein Bild handelt, wird es nicht verarbeitet. Wenn es sich um ein Bild handelt, instanziieren Sie einen Dateileser, lesen Sie die hochgeladenen Dateidaten im Base64-Format und bestimmen Sie die Datenlänge. Wenn das Bild größer als 200 KB ist, rufen Sie die Komprimierungsmethode auf, um es zu komprimieren, andernfalls rufen Sie die Upload-Methode zum Hochladen auf.

filechooser.onchange = function() {
 if (!this.files.length) return;
 var files = Array.prototype.slice.call(this.files);
 if (files.length > 9) {
  alert("最多同时只可上传9张图片");
  return;
 }
 files.forEach(function(file, i) {
  if (!/\/(?:jpeg|png|gif)/i.test(file.type)) return;
  var reader = new FileReader();
  var li = document.createElement("li");
  li.innerHTML = &#39;<p class="progress"><span></span></p>&#39;;
  $(".img-list").append($(li));
  reader.onload = function() {
   var result = this.result;
   var img = new Image();
   img.src = result;
   //如果图片大小小于200kb,则直接上传
   if (result.length <= maxsize) {
    $(li).css("background-image", "url(" + result + ")");
    img = null;
    upload(result, file.type, $(li));
    return;
   }
   //图片加载完毕之后进行压缩,然后上传
   if (img.complete) {
    callback();
   } else {
    img.onload = callback;
   }
   function callback() {
    var data = compress(img);
    $(li).css("background-image", "url(" + data + ")");
    upload(data, file.type, $(li));
    img = null;
   }
  };
  reader.readAsDataURL(file);
 })
};
Nach dem Login kopieren

【2】Bilder komprimieren

Nachdem Sie die oben genannten Bilddaten erhalten haben, können Sie die Methode zum Komprimieren von Bildern verwenden. Beim Komprimieren von Bildern ist es nicht erforderlich, das Bild direkt auf die Leinwand zu zeichnen und dann toDataURL aufzurufen.

In IOS gibt es zwei Einschränkungen für das Zeichnen von Bildern auf Leinwand:

Die erste ist die Größe des Bildes. Wenn die Größe des Bildes zwei Millionen Pixel überschreitet, kann das Bild nicht gezeichnet werden Auf der Leinwand wird beim Aufruf von drawImage kein Fehler gemeldet. Wenn Sie jedoch toDataURL zum Abrufen von Bilddaten verwenden, erhalten Sie leere Bilddaten.

Außerdem ist die Größe der Leinwand begrenzt, wenn die Größe der Leinwand größer als etwa fünf Millionen Pixel (also das Produkt aus Breite und Höhe) ist, kann nicht nur das Bild, sondern auch nicht gezeichnet werden andere Dinge können nicht gezeichnet werden.

Um die erste Einschränkung zu umgehen, besteht die Lösung darin, Kacheln zu zeichnen. Beim Kachelzeichnen wird das Bild in mehrere Teile geteilt und auf die Leinwand gezeichnet. Die Methode in meinem Code besteht darin, das Bild in 1 Million Pixel zu unterteilen und es dann auf die Leinwand zu zeichnen.

Um die zweite Einschränkung zu umgehen, besteht meine Lösung darin, die Breite und Höhe des Bildes entsprechend zu komprimieren. Die in meinem Code festgelegte Obergrenze liegt bei vier Millionen Pixeln Größer als vier Millionen Pixel. Komprimieren Sie es einfach auf weniger als vier Millionen Pixel. Ein Bild mit vier Megapixeln sollte ausreichen, daher betragen Breite und Höhe 2000 x 2000.

Dies löst die beiden Einschränkungen auf IOS.

Zusätzlich zu den oben genannten Einschränkungen gibt es zwei Fallstricke: Erstens kann die toDataURL von Canvas nur JPG komprimieren Das heißt, es kann einheitlich verwendet werden: canvas.toDataURL('image/jpeg', 0.1), der Typ ist einheitlich auf jpeg eingestellt und das Komprimierungsverhältnis wird von selbst gesteuert.

Das andere ist, dass, wenn Sie PNG in JPG konvertieren, wenn Sie es auf die Leinwand zeichnen und die Leinwand einen transparenten Bereich hat, der transparente Bereich schwarz wird, wenn Sie ihn in JPG konvertieren, weil die transparenten Pixel Der Standardwert der Leinwand ist rgba( 0,0,0,0). Bei der Konvertierung in jpg wird er also zu rgba(0,0,0,1), d. h. der transparente Hintergrund wird schwarz. Die Lösung besteht darin, vor dem Zeichnen einen weißen Hintergrund auf die Leinwand zu legen.

function compress(img) {
 var initSize = img.src.length;
 var width = img.width;
 var height = img.height;
 //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
 var ratio;
 if ((ratio = width * height / 4000000) > 1) {
  ratio = Math.sqrt(ratio);
  width /= ratio;
  height /= ratio;
 } else {
  ratio = 1;
 }
 canvas.width = width;
 canvas.height = height;
 //铺底色
 ctx.fillStyle = "#fff";
 ctx.fillRect(0, 0, canvas.width, canvas.height);
 //如果图片像素大于100万则使用瓦片绘制
 var count;
 if ((count = width * height / 1000000) > 1) {
  count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
  //计算每块瓦片的宽和高
  var nw = ~~(width / count);
  var nh = ~~(height / count);
  tCanvas.width = nw;
  tCanvas.height = nh;
  for (var i = 0; i < count; i++) {
   for (var j = 0; j < count; j++) {
    tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
    ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
   }
  }
 } else {
  ctx.drawImage(img, 0, 0, width, height);
 }
 //进行最小压缩
 var ndata = canvas.toDataURL(&#39;image/jpeg&#39;, 0.1);
 console.log(&#39;压缩前:&#39; + initSize);
 console.log(&#39;压缩后:&#39; + ndata.length);
 console.log(&#39;压缩率:&#39; + ~~(100 * (initSize - ndata.length) / initSize) + "%");
 tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
 return ndata;
}
Nach dem Login kopieren

【3】Bild hochladen

完成图片压缩后,就可以塞进formdata里进行上传了,先将base64数据转成字符串,再实例化一个ArrayBuffer,然后将字符串以8位整型的格式传入ArrayBuffer,再通过BlobBuilder或者Blob对象,将8位整型的ArrayBuffer转成二进制对象blob,然后把blob对象append到formdata里,再通过ajax发送给后台即可。

XmlHttpRequest2中不仅可以发送大数据,还多出了比如获取发送进度的API,我代码里也进行了简单的实现。

//图片上传,将base64的图片转成二进制对象,塞进formdata上传
function upload(basestr, type, $li) {
 var text = window.atob(basestr.split(",")[1]);
 var buffer = new ArrayBuffer(text.length);
 var ubuffer = new Uint8Array(buffer);
 var pecent = 0,
  loop = null;
 for (var i = 0; i < text.length; i++) {
  ubuffer[i] = text.charCodeAt(i);
 }
 var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;
 var blob;
 if (Builder) {
  var builder = new Builder();
  builder.append(buffer);
  blob = builder.getBlob(type);
 } else {
  blob = new window.Blob([buffer], {
   type: type
  });
 }
 var xhr = new XMLHttpRequest();
 var formdata = new FormData();
 formdata.append(&#39;imagefile&#39;, blob);
 xhr.open(&#39;post&#39;, &#39;/cupload&#39;);
 xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
   console.log(&#39;上传成功:&#39; + xhr.responseText);
   clearInterval(loop);
   //当收到该消息时上传完毕
   $li.find(".progress span").animate({
    &#39;width&#39;: "100%"
   }, pecent < 95 ? 200 : 0, function() {
    $(this).html("上传成功");
   });
   $(".pic-list").append(&#39;<a href="&#39; + xhr.responseText + &#39;">&#39; + xhr.responseText + &#39;<img src="&#39; + xhr.responseText + &#39;" /></a>&#39;)
  }
 };
 //数据发送进度,前50%展示该进度
 xhr.upload.addEventListener(&#39;progress&#39;, function(e) {
  if (loop) return;
  pecent = ~~(100 * e.loaded / e.total) / 2;
  $li.find(".progress span").css(&#39;width&#39;, pecent + "%");
  if (pecent == 50) {
   mockProgress();
  }
 }, false);
 //数据后50%用模拟进度
 function mockProgress() {
  if (loop) return;
  loop = setInterval(function() {
   pecent++;
   $li.find(".progress span").css(&#39;width&#39;, pecent + "%");
   if (pecent == 99) {
    clearInterval(loop);
   }
  }, 100)
 }
 xhr.send(formdata);
}
Nach dem Login kopieren

至此,整个上传的前端图片压缩就完成了,因为是用了formdata提交,所以后台接数据的时候就跟普通form表单提交数据一样处理即可。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在Webpack中如何加载SVG

在vue-cli中如何实现移动端自适应

在Vue 组件Toast中如何实现显示框效果

有关webpack中rules参数处理

Das obige ist der detaillierte Inhalt vonWie verwende ich die Komprimierungs- und Upload-Funktion für mobile Frontend-Bilder?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!