Alamat asli: github.com/whinc/blog/…
Baru-baru ini saya menerima permintaan untuk mengirim komentar: pengguna memasukkan komentar dan dapat mengambil foto atau memilih gambar dari album untuk diunggah, yang berarti komentar teks dan gambar didukung. Ini perlu diimplementasikan pada H5 dan mini-program secara bersamaan. Persyaratan ini memerlukan banyak tempat untuk memproses gambar. Artikel ini membuat ringkasan praktik pemrosesan gambar di H5. Kode proyek didasarkan pada kerangka Vue. Untuk menghindari terpengaruh oleh kerangka tersebut, saya mengubah semua kode ke implementasi API asli untuk penjelasan , memotong, mengunggah kemajuan, dll.) dalam kode proyek di sini. Abaikan saja dan hanya perkenalkan ide dan kode utama yang terkait dengan pemrosesan gambar. Implementasi mini program mirip dengan H5 dan tidak akan terulang kembali. Kode implementasi mini program terlampir di akhir artikel.
FotoGunakan tag <input>, setel tipe ke file untuk memilih file, setel terima ke gambar/* untuk memilih jenis file dan kamera, dan setel banyak untuk mendukung banyak pilihan. Dengarkan peristiwa perubahan untuk mendapatkan daftar file yang dipilih, setiap file adalah tipe Blob.
<tipe input=file diterima=gambar/* kelipatan /> <img class=preivew /> <tipe skrip=teks/javascript> fungsi onFileChange (acara) { const files = Array.prototype.slice.call(event.target.files ) files.forEach(file => console.log('nama file:', nama file)) } document.querySelector('input').addEventListener('change', onFileChange) </skrip>Pratinjau gambar
Metode URL.createObjectURL dapat membuat jalur URL lokal yang menunjuk ke objek sumber daya lokal. Antarmuka ini digunakan di bawah ini untuk membuat alamat gambar yang dipilih dan menampilkannya.
fungsi onFileChange (acara) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] document.querySelector('img').src = window.URL.createObjectURL(file) }Rotasi gambar
Gambar yang diambil dengan kamera mungkin diputar karena arah pegangan kamera saat memotret, dan perlu dikoreksi. Mengoreksi rotasi memerlukan mengetahui informasi rotasi gambar. Di sini kita menggunakan perpustakaan bernama exif-js, yang dapat membaca metadata EXIF gambar, termasuk arah kamera saat memotret informasi gambar dapat dihitung.
Berikut ini adalah bit bendera rotasi EXIF. Total ada 8 jenis, tetapi saat memotret melalui kamera, hanya 1, 3, 6, dan 8 yang dapat dihasilkan, yang masing-masing sesuai dengan kamera normal, rotasi searah jarum jam 180°. , Rotasi 90° berlawanan arah jarum jam, dan rotasi searah jarum jam.
Oleh karena itu, untuk mengoreksi sudut rotasi gambar, Anda hanya perlu membaca tanda rotasi EXIF gambar, menentukan sudut rotasi, memutar gambar pada kanvas, dan mengekspor ulang gambar baru. Mengenai pengoperasian rotasi kanvas, Anda dapat merujuk ke artikel "Rotasi Gambar Kanvas dan Membuka Kunci Postur Flip". Fungsi berikut mengimplementasikan koreksi sudut rotasi file gambar, menerima file gambar, dan mengembalikan file gambar baru yang telah dikoreksi.
/** * Memperbaiki masalah sudut rotasi gambar * @param {file} gambar asli * @return {Promise} terselesaikan janji Mengembalikan gambar baru yang telah diperbaiki */function fixImageOrientation (file) { return new Promise((resolve, reject) => { // Dapatkan gambar const img = new Image(); img.src = window.URL.createObjectURL(file); img.onload = () => { // Dapatkan metadata gambar (Variabel EXIF adalah variabel global yang diekspos oleh perpustakaan Exif-js yang diperkenalkan) EXIF.getData(img, function() { // Dapatkan bendera rotasi gambar var orientasi = EXIF.getTag(ini, Orientasi); // Memutar gambar pada kanvas sesuai dengan sudut rotasi if (orientasi === 3 || orientasi === 6 || orientasi === 8) { const kanvas = document.createElement(kanvas); const ctx = canvas.getContext(2d); switch (orientasi) { kasus 3: // Putar 180° canvas.width = img.width = img.height; (180 * Matematika.PI) / 180); ctx.drawImage(img, -img.width, -img.height, img.width, img.height); break; case 6: // Putar 90° canvas.width = img.height; canvas.height = ctx.rotate((90 * Math.PI) / 180); ctx.drawImage(img, 0, -img.height, img.width, img.height); Putar -90° canvas.width = img.height; canvas.height = img.width; ctx.rotate((-90 * Math.PI) / 180); .width, img.height); break } // Mengembalikan gambar baru canvas.toBlob(file => resolve(file), 'gambar/jpeg', 0,92) } else { kembalikan tekad(file);Kompresi gambar
Saat ini, efek kamera ponsel menjadi lebih baik dan lebih baik, dan dengan itu ukuran gambar juga meningkat, yang dapat dengan mudah mencapai beberapa MB atau bahkan lebih dari sepuluh MB. Mengunggah gambar asli secara langsung lambat dan mudah untuk diunggah , dan latar belakang juga memiliki batasan pada ukuran isi permintaan, pemuatan tampilan gambar selanjutnya juga akan lebih lambat. Masalah ini dapat diatasi jika front-end mengompresi gambar dan kemudian mengunggahnya.
Fungsi berikut mengimplementasikan kompresi gambar. Prinsipnya adalah menggambar gambar berskala di kanvas, dan terakhir mengekspor gambar terkompresi dari kanvas. Ada dua cara untuk mengontrol kompresi gambar: yang pertama adalah mengontrol rasio zoom gambar; yang lainnya adalah mengontrol kualitas gambar yang diekspor.
/** * Gambar terkompresi * @param {file} Gambar masukan * @returns {Janji} terselesaikan janji Mengembalikan gambar terkompresi baru */fungsi kompresImage(file) { return new Promise((putuskan, tolak) => { // Dapatkan gambar (memuat gambar untuk mendapatkan lebar dan tinggi gambar) const img = new Image(); img.src = window.URL.createObjectURL(file); reject(error); img.onload = () => { // Lebar dan tinggi kanvas const canvasWidth = document.documentElement.clientWidth * window.devicePixelRatio; // Hitung penskalaan faktor // Di sini saya mengambil faktor penskalaan horizontal dan vertikal yang lebih besar sebagai faktor penskalaan, untuk memastikan bahwa semua konten gambar terlihat const scaleX = canvasWidth / img.width; const scaleY = canvasHeight / img.height; const scale = Math.min(scaleX, scaleY); // Skalakan gambar asli sesuai dengan faktor penskalaan dan gambarkan ke kanvas const canvas = document.createElement ('kanvas'); const ctx = kanvas.getContext(2d); kanvas.lebar = kanvas.tinggi = tinggi kanvas; img.lebar * skala; const imageHeight = img.height * skala; const dx = (canvasWidth - imageWidth) / 2; const dy = (canvasHeight - imageHeight) / 2; ); // Ekspor gambar baru // Tentukan jenis MIME gambar sebagai 'gambar/jpeg', kualitas lulus Kontrol kualitas gambar yang diekspor dan terapkan kompresi gambar const quality = 0.92 canvas.toBlob(file => resolve(tempFile), image/jpeg, quality };Unggah gambar
Buat data formulir melalui FormData dan mulai permintaan ajax POST. Fungsi berikut mengimplementasikan pengunggahan file.
Catatan: Saat mengirim data FormData, browser akan secara otomatis menyetel Tipe Konten ke nilai yang sesuai. Tidak perlu menyetel Tipe Konten, jika tidak, kesalahan akan dilaporkan karena batas pembatas badan permintaan HTTP dibuat oleh browser. dan tidak dapat diatur secara manual.
/** * Unggah file* @param {File} file File yang akan diunggah* @returns {Janji} Mengembalikan janji yang terselesaikan jika unggahan berhasil, jika tidak, mengembalikan janji yang ditolak */fungsi unggahFile (file) { return new Promise((resolve , tolak) = > { // Siapkan data formulir const formData = new FormData() formData.append('file', file) // Kirim permintaan const xhr = new XMLHttpRequest() xhr.open('POST', uploadUrl) xhr.onreadystatechange = function () { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { tekad(JSON.parse(this.responseText)) } else { tolak(ini.responTeks) } } xhr.kirim(formData) })}ringkasan
Dengan fungsi tambahan di atas, pemrosesannya jauh lebih sederhana. Kode panggilan terakhir adalah sebagai berikut:
function onFileChange (event) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] // Memperbaiki rotasi gambar fixImageOrientation(file).then(file2 => { // Buat pratinjau Gambar document.querySelector('img').src = window.URL.createObjectURL(file2) // Kompresi mengembalikan kompresImage(file2) }).then(file3 => { // Perbarui gambar pratinjau document.querySelector('img').src = window.URL.createObjectURL(file3) // Unggah return uploadFile(file3) }).then(data => { console.log('Upload berhasil') }).catch(error => { console.error('Upload gagal') })}
H5 menyediakan antarmuka untuk memproses file. Dengan bantuan kanvas, pemrosesan gambar yang kompleks dapat diimplementasikan di browser. Artikel ini merangkum beberapa praktik pemrosesan gambar dalam skenario mengunggah gambar di H5 pada terminal seluler referensi parsial ketika menghadapi kebutuhan serupa di masa depan.
Terlampir adalah referensi implementasi program kecil
// Ambil foto wx.chooseImage({ sourceType: [kamera], sukses: ({ tempFiles }) => { const file = tempFiles[0] // Memproses gambar }});/** * Kompres gambar* @param { Objek } params * filePath: String Jalur gambar masukan * sukses: Fungsi Dipanggil kembali ketika kompresi berhasil dan mengembalikan jalur gambar terkompresi baru * gagal: Fungsi Callback ketika kompresi gagal */compressImage({ filePath, sukses, gagal }) { // Dapatkan lebar dan tinggi gambar wx.getImageInfo({ src: filePath, sukses: ({ lebar, tinggi }) => { const systemInfo = wx .getSystemInfoSync(); const canvasWidth = systemInfo.screenWidth; const canvasHeight = systemInfo.screenHeight; Perbarui ukuran kanvas this.setData({ CanvasWidth, canvasHeight }) // Hitung rasio penskalaan const scaleX = canvasWidth / width; const scaleY = canvasHeight / height; * skala ; const imageHeight = tinggi * skala; // Gambarkan gambar berskala ke kanvas const ctx = wx.createCanvasContext(hidden-canvas); dx = (lebar kanvas - lebar gambar) / 2; biarkan dy = (tinggi kanvas - tinggi gambar) / 2; ctx.drawImage(filePath, dx, dy, imageWidth, imageHeight); Gambar terkompresi ke file sementara wx.canvasToTempFilePath({ canvasId: kanvas tersembunyi, lebar: CanvasWidth, tinggi: canvasHeight, destWidth: canvasWidth, destHeight: canvasHeight, fileType: jpg, kualitas: 0,92, sukses: ({ tempFilePath }) => { // Sembunyikan kanvas this.setData({ CanvasWidth: 0, canvasHeight: 0 } ) // Kompresi selesai berhasil({ tempFilePath } }, gagal: error => { // Sembunyikan kanvas this.setData({ CanvasWidth: 0, canvasHeight: 0 }) gagal(kesalahan); } } }); Unggah file*/uploadFile({ uploadUrl, filePath, onData, onError }) { wx.uploadFile({ url: uploadUrl filePath: filePath, nama: file, header: { Cookie: cookie }, sukses: res => { if (res.statusCode === 200) { onData(res.data) } else { onError(res); onError(kesalahan);Meringkaskan
Di atas adalah HTML5 dan program kecil yang diperkenalkan oleh editor untuk mewujudkan fungsi memutar, mengompresi, dan mengunggah gambar. Saya harap ini dapat membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan pesan kepada saya dan editor akan membalasnya kamu tepat waktu. Saya juga ingin mengucapkan terima kasih kepada semua orang atas dukungan Anda terhadap situs seni bela diri VeVb!