Fitur komponen ini meliputi:
Pemangkasan gambar (seret kotak pemangkasan dan ubah ukuran kotak pemangkasan);
Gambar mosaik (menggambar mosaik, menghapus mosaik);
Pratinjau gambar, restorasi gambar (kembali ke gambar asli, kembali ke gambar yang diproses);
Unggah gambar (dapatkan tanda tangan, unggah gambar).
2. Logika inti2.1 Pemangkasan gambar
Dapatkan posisi kotak pemangkasan (persegi panjang) relatif terhadap kanvas (kiri atas) serta tinggi dan lebar kotak pemangkasan. Dapatkan (getImageData) objek gambar (ImageData) pada posisi kanvas yang sesuai. Bersihkan kanvas kanvas. Gambarlah objek gambar (ImageData) yang diperoleh (putImageData) pada posisi kanvas yang sesuai. Hasilkan gambar pratinjau.
2.2 Gambar Mosaik
Menggambar mosaik adalah menggambar ulang area yang berpusat pada jalur sapuan mouse (lebar kuas) menjadi warna lain. Hasil umumnya adalah warna di sekitarnya akan serupa.
Metode pemilihan warna:
1) Misalnya, jika Anda memiliki koordinat (x, y) suatu titik yang dilintasi mouse, tentukan persegi panjang dengan koordinat sudut kiri atas (x, y), lebar 30 piksel, dan tinggi 30 piksel. Kita membagi lebar dan tinggi persegi panjang dengan 5 (dibagi menjadi 5 bagian, yang dapat disesuaikan menjadi n bagian), jadi sekarang ada 25 grid kecil berukuran 6px. Setiap grid kecil memiliki lebar dan tinggi 6px.
2) Kemudian, kita secara acak memperoleh kotak kecil dan memperoleh (getImageData) objek gambar (ImageData) dari kotak kecil ini; kemudian secara acak memperoleh warna warna (rgba: ImageD) dari piksel tertentu (lebar 1px, tinggi 1px) pada ini objek gambar ata.data[0], ImageData.data[1], ImageData.data[2], ImageData.data[3]); Terakhir, kami mengatur warna setiap piksel dari kotak kecil 6x6px pertama menjadi color .
3) Untuk warna 24 kotak kecil lainnya, cukup ikuti 2 langkah.
2.3 Hapus mosaik
Kita perlu memahami suatu masalah, apakah itu menggambar mozaik atau membersihkan mozaik, intinya menggambar. Kita menggambar mozaik di lokasi tertentu. Saat kita membersihkannya, kita menggambar lagi objek gambar asli di lokasi saat ini. Efek pembersihan tercapai. Oleh karena itu, kita perlu membuat cadangan kanvas yang sama persis dengan gambar aslinya. Saat membersihkan, kita perlu mendapatkan gambar pada posisi yang sesuai pada kanvas cadangan dan menariknya ke posisi mosaik.
2.4 Pratinjau gambar
Pratinjau gambar adalah untuk memperoleh area bingkai yang dipotong dan memperoleh objek gambar pada area tersebut. Lalu gambarlah di kanvas.
2.5 Mengembalikan gambar ke gambar aslinya
Bersihkan kanvas dan gambar kembali gambar aslinya
2.6 Kembalikan ke gambar yang dimanipulasi
Pratinjau adalah menyimpan objek gambar kanvas (ImageData), menghapus kanvas, dan menarik objek gambar yang disimpan ke kanvas.
2.7 Unggah gambar
Dapatkan jalur gambar kanvas (toDataURL) dan ubah gambar base64 yang diperoleh menjadi objek File. untuk mengunggah.
3. Kode lengkapnya adalah sebagai berikut:
<templat> <div class=canvas-clip :loading=loading> <div v-show=isDrop class=canvas-mainBox ref=canvas-mainBox id=canvas-mainBox @mousedown.stop=startMove($event) > <div class=canvas-minBox kiri atas @mousedown.stop=startResize($event,0)></div> <div class=canvas-minBox atas @mousedown.stop=startResize($event,1)></div> <div class=canvas-minBox kanan-up @mousedown.stop=startResize($event,2)></div> <div class=canvas- minBox kanan @mousedown.stop=startResize($event,3)></div> <div class=canvas-minBox kanan bawah @mousedown.stop=startResize($event,4)></div> <div class=canvas-minBox bawah @mousedown.stop=startResize($event,5)></div> <div class=canvas-minBox kiri-bawah @mousedown.stop=startResize($event,6)></ div div> <div class=canvas-minBox kiri @mousedown.stop=startResize($event,7)></div> </div> <!-- Canvas--> <canvas class=canvas-area ref=canvas id=canvas :width=canvasWidth :height=canvasHeight @mousedown.stop=startMove($event) :class={hoverPaint:isMa,hoverClear:isMaClear} ></canvas> <!-- Kanvas cadangan--> <kelas kanvas=salinan kanvas ref=canvasCopy :lebar=lebar kanvas :height=canvasHeight></canvas> <div class=canvas-btns> <button v-if=backBtn @click=clipBack>Kembali</button> <button :class={active:btnIndex==0} @click= sourceImg>Gambar asli</button> <button :class={active:btnIndex==1} @click=paintRectReady :disabled=isDisabled>Mosaik</button> <button :class={active:btnIndex==2} @click=paintRectClearReady :disabled=isDisabled>Penghapus</button> <button :class={active:btnIndex==3 } @click=clipReady :disabled=isDisabled>Pangkas</button> <button :class={active:btnIndex==4} @click=clipPosition>Pratinjau</button> <button @click=getSignature>Unggah</button> <button class=close @click=canvasClose()>x</button> <!-- <div class=paint-size v-if=isMaClear ||.isMa> <span>Ukuran Kuas</span> <input :defaultValue=maSize v-model=maSize max=100 min=1 type=range> <span class=size-num>{{maSize}}</span> </div> --> </div> </div></template><script>impor axios dari axios;impor md5 dari js-md5 ;permintaan impor dari ../../axios/config;ekspor default { alat peraga: [imgUrl], data() { return { resizeFX: , movePrev: , CanvasWidth: 800, // Lebar kanvas canvasHeight: 600, // Tinggi kanvas memuat: false, isDrop: false, // Memotong isMa: false, // Ukuran mosaik: 30, // Ukuran mosaik isMaClear: false, // Hapus mosaik backBtn: false, // Tombol kembali isDisabled: false, // Nonaktifkan tombol btnIndex: 0, //Tombol saat ini mouseX:'', // Posisi mouse mouseY:'', clipEle: , // Memotong elemen kotak canvasDataSession: , // Informasi kanvas sebelum pratinjau kanvas: , // Kanvas ctx: , // Konteks Kanvas canvasCopy: , // salin kanvas ctxCopy: , // salin konteks kanvas uploadOption: { // Jalur parameter unggahan gambar: , kebijakan: , tanda tangan: , nama pengguna: } }; }, dipasang() { ini.clipEle = ini.$refs[kanvas-mainBox]; ini.kanvas = ini.$refs[kanvas]; = ini.$refs[canvasCopy]; ini.ctxCopy = ini.canvasCopy.getContext(2d); Buat gambar draw() { var img = new Image(); img.setAttribute('crossOrigin', 'anonymous'); , 600); ini.ctxCopy.drawImage(img, 0, 0, 800, 600 }; img.src = this.imgUrl + '?time=' + new Date().valueOf(); }, //Pratinjau menghitung posisi kotak pemangkasan (koordinat kiri atas) clipPosition() { this.isDisabled = true; this.backBtn = benar; this.isMa = false; this.isMaClear = false; this.btnIndex = 4; = this.canvas.offsetTop; if (this.isDrop) { // Posisi kotak pemangkasan var clipPx = this.clipEle.offsetLeft, clipPy = this.clipEle.offsetTop, x = clipPx - canvasPx, y = clipPy - canvasPy, w = this.clipEle.offsetWidth, h = this.clipEle.offsetHeight, // Pusatkan posisi gambar pratinjauX = 400 - this.clipEle.offsetWidth / 2, positionY = 300 - this.clipEle.offsetHeight / 2; } else { // Tanpa kotak cropping, simpan gambar lengkap var x = 0, w = this.canvas.offsetWidth , h = this.canvas.offsetHeight, // Pusatkan gambar pratinjau positionX = 0, positionY = 0; ini.ctx.getImageData(x, y, w, h); ini.canvasDataSession = ini.ctx.getImageData( 0, 0, ini.canvasWidth, ini.canvasHeight ); CanvasWidth, this.canvasHeight); this.ctx.putImageData(imageData, positionX, positionY); this.clipEle.style.display = tidak ada; this.canvasCopy.style.display = tidak ada; }, // Kembali ke status pra-pratinjau clipBack() { this.btnIndex = -1; = salah ; ini.isDrop = salah; ini.ctx.putImageData(ini.canvasDataSession, 0, 0); ini.canvasCopy.style.display = blok; }, // gambar asli sourceImg() { this.isDisabled = false; this.btnIndex = 0; this.backBtn = false; = Gambar baru(); this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); img.setAttribute('crossOrigin', 'anonim'); img.onload = () => { this.ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight }; .imgUrl + '?time=' + Tanggal baru().valueOf(); this.canvasCopy.style.display = blok }, // Dapatkan tanda tangan getSignature() { // Gambar kanvas base64 ke Objek file var dataURL = this.canvas.toDataURL(image/jpg), arr = dataURL.split(,), mime = arr[0].match(/:( .*?);/)[1], bstr = atob(arr[1]), n = bstr.panjang, u8arr = new Uint8Array(n); (n--) { u8arr[n] = bstr.charCodeAt(n); var obj = Gumpalan baru([u8arr], { ketik: mime }), waktu = Tanggal baru().toGMTString(), formData = baru FormData(); formData.append(file, obj); // Dapatkan akhiran file var suffix = formData.get(file).type.split(/)[1]; req .get(/carsource-api/upyun/sign, { akhiran: akhiran }) .then(response => { if (response.data.code === 0) { this.uploadOption.path = respon.data.data.path; formData.append(kebijakan, respon.data.data.kebijakan); formData.append(otorisasi, respon.data.data.tanda tangan); this.updateImg(formData); : http://v0.api.upyun.com/tmp-img, metode: POST, data: formData }).then(response => { if (response.data.code == 200) { this.$message.success(gambar berhasil diubah); this.canvasClose(upload, respon.data.url.slice(4)); Pemindahan pembesaran kotak startResize(e, n) { this.resizeFX = n; $(document).mousemove(this.resizeDiv); document.addEventListener(mouseup, this.stopResize }, stopResize(e) { $(document).off(mousemove, this.resizeDiv); document.removeEventListener(mouseup, this.stopResize); this.movePrev = [e.pageX, e.pageY]; $(document).mousemove(this.moveDiv); document.addEventListener(mouseup, this.stopMove); }, stopMove(e) { $(document).off(mousemove, this.moveDiv); this.stopMove); }, moveDiv(e) { // Mosaik if (ini.isMa) { this.paintRect(e); } // Hapus mosaik if (this.isMaClear) { this.paintRectClear(e); // Pangkas if (this.isDrop) { var targetDiv = $(#canvas-mainBox), offsetArr = targetDiv.offset(); var chaX = e.pageX - ini.movePrev[0], chaY = e.pageY - this.movePrev[1], ox = parseFloat(targetDiv.css(kiri)), oy = parseFloat(targetDiv.css(atas)); targetDiv.css({ kiri: ox + chaX + px, atas: oy + chaY + px }); ini.movePrev = [e.pageX, e.pageY]; e.preventDefault(); e.stopPropagation(); // Dapatkan jarak dari elemen yang ukurannya perlu diubah ke halaman var targetDiv = $(#canvas-mainBox), offsetArr = targetDiv.offset(); = targetDiv.width() , eleSHeight = targetDiv.height(), ox = parseFloat(targetDiv.css(kiri)), oy = parseFloat(targetDiv.css(top)); // Ambil posisi mouse dan bandingkan dengan offset awal elemen, var chaX = e.pageX - offsetArr.left, chaY = e.pageY - offsetArr.top; this.resizeFX) { case 0: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaX >= eleSWidth - 10 || chaY >= eleSHeight - 10) { return; } // Dapatkan selisih posisi (saya), atur lebar dan tinggi terlebih dahulu, lalu atur posisinya // Lebar dan tinggi asli + ((saya) *-1), posisi awal + (saya) targetDiv.css({ lebar: eleSWidth + chaX * -1 + px, tinggi: eleSHeight + chaY * -1 + px, kiri: ox + chaX + px, atas: oy + chaY + px }); break; case 1: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan if (chaY >= eleSHeight - 10) { return } // Dapatkan perbedaan posisi (me), atur lebar dan tinggi terlebih dahulu, lalu atur posisinya // Lebar dan tinggi asli + ((saya) *-1), posisi asli + (saya) targetDiv.css({ tinggi: eleSHeight + chaY * -1 + px, atas: oy + chaY + px }); break; case 2: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaX <= 10 || chaY >= eleSHeight - 10) { return } // Dapatkan posisinya selisih (saya), Pertama atur lebar dan tinggi, atur posisi // tinggi asli + ((saya) *-1), lebar asli + ((saya)), posisi asli + (saya) targetDiv.css({ lebar : chaX + piksel, tinggi: eleSHeight + chaY * -1 + px, atas: oy + chaY + px break; case 3: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaX <= 10 ) { return; } // Dapatkan selisih posisi (saya), atur dulu lebar dan tinggi, lalu atur posisinya // Lebar dan tinggi asli + ((saya) *-1), posisi asli + (saya) targetDiv .css({ lebar: chaX + px }); break; case 4: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaX <= 10 || chaY <= 10) { return; perbedaan (saya), Atur lebar dan tinggi terlebih dahulu, lalu atur posisi // Lebar dan tinggi asli + ((saya) *-1), posisi asli + (saya) targetDiv.css({ lebar: chaX + px, tinggi : chaY + px }); break; case 5: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaY <= 10) { return } // Dapatkan perbedaan posisi (me), atur lebar dan tinggi pertama, lalu atur posisinya // Lebar dan tinggi asli + ((me) *-1), posisi asli + (me) targetDiv.css({ tinggi: chaY + px }); jarak pergerakan mendekati lebar atau tinggi, tidak ada tindakan yang akan dilakukan jika (chaX >= eleSWidth - 10 ||.chaY <= 10) { return; } // Dapatkan selisih posisi (me), atur dulu lebar dan tinggi, lalu atur posisinya // Lebar dan tinggi asli + ((me) * -1), Posisi asli + (saya) targetDiv.css({ lebar: eleSWidth + chaX * -1 + px, tinggi: chaY + px, kiri: ox + chaX + px break; 7: //Jika jarak pergerakan mendekati lebar atau tinggi, tidak ada perubahan yang dilakukan jika (chaX >= eleSWidth - 10) { return; } // Dapatkan perbedaan posisi (me), atur lebar dan tinggi terlebih dahulu , lalu atur posisinya // Lebar dan tinggi Asli + ((saya) *-1), posisi asli + (saya) targetDiv.css({ lebar: eleSWidth + chaX * -1 + px, kiri: ox + chaX + piksel }); istirahat; default: istirahat; } }, // kliping clipReady() { this.btnIndex = 3; this.isMa = false; this.isDrop = true; .btnIndex = 1; ini.isMa = benar; ini.isDrop = salah; Penghapus paintRectClearReady() { this.btnIndex = 2; this.isMa = false; this.isDrop = false; this.isMaClear = true }, // Gambar mosaik paintRect(e) { var offT = this.canvas.offsetTop, / / Jarak dari atas offL = this.canvas.offsetLeft, // Jarak dari kiri x = e.clientX, y = e.klienY; jika(ini.mouseX - x > ini.maSize/2 || x - ini.mouseX > ini.maSize/2 || ini.mouseY - y > ini.maSize/2 || y - ini.mouseY > ini.maSize/2){ var oImg = ini.ctx.getImageData(x - offL ,y - offT,this.maSize,this.maSize); var w = oImg.width; var h = oImg.height; //Tingkat mosaik, semakin besar angkanya, semakin kabur var num = 6; canvas var stepW = w/ num; var stepH = h/num; //Berikut adalah piksel dari loop canvas for(var i=0;i<stepH;i++){ for(var j=0;j<stepW; j++){ //Dapatkan warna acak dari kotak kecil. Ini adalah warna var yang diperoleh dari posisi acak kotak kecil = this.getXY(oImg,j*num+Math.floor(Math.random()*num),i *num +Math.floor(Math.random()*num)); //Berikut adalah piksel dari persegi kecil melingkar, for(var k=0;k<num;k++){ for(var l=0; aku< angka;l++){ //Mengatur warna kotak kecil this.setXY(oImg,j*num+l,i*num+k,color); ; ini.mouseX = e.clientX this.mouseY = e.clientY } }, getXY(obj,x,y){ var w = obj.width; var h = objek.tinggi; var d = objek.data; var warna = []; warna[0] = d[4*(y*w+x)]; w+x)+1]; warna[2] = d[4*(y*w+x)+2]; warna[3] = d[4*(y*w+x)+3]; ; setXY(obj,x,y,warna){ var w = obj.lebar; var h = obj.tinggi; var d = obj.data; d[4*(y*w+x)] = warna[0]; d[4*(y*w+x)+1] = warna[1]; d[4*(y*w+x)+2] = warna[2]; d[4*(y*w+x)+3] = warna[3] }, // Hapus mosaik paintRectClear(e) { var offT = this.canvasCopy.offsetTop, // Jarak dari atas offL = this.canvasCopy .offsetLeft, // Jarak ke kiri x = e.clientX, y = e.clientY, // Dapatkan data gambar pada posisi ini dari gambar asli imageData = this.ctxCopy.getImageData( x - offL, y - offT, this.maSize, this.maSize ); this.ctx.putImageData(imageData, x - offL, y - offT }, // Tutup kanvas canvasClose(type , url) { this.$emit(isShowImgChange, ketik, url) } }};</script><style scoped>.canvas-clip { posisi: tetap; atas: 0; bawah: 0; kiri: 0; kanan: 0; indeks-z: 9010; 400 piksel; tinggi: 300 piksel; kiri: 50%; atas: 50%; margin-kiri: -200 piksel; 1px solid #FFF; kursor: pindah; z-index: 9009;}.canvas-minBox { posisi: absolut; lebar: 8px; latar belakang: #FFF;}.kiri-atas { atas: -4px kiri : -4px; kursor: nw-resize;}.up { atas: -4px; kiri: 50%; margin-kiri: -4px; n-resize;}.right-up { atas: -4px; kanan: -4px; kursor: ne-resize;}.kanan { atas: 50%; margin-atas: -4px; -mengubah ukuran;}.kanan-bawah { bawah: -4px; kanan: -4px; kursor: se-resize;}.bawah { bawah: -4px kiri: 50%; margin-kiri: -4px; kursor: s-resize;}.kiri-bawah { bawah: -4px; kiri: -4px; kursor: sw-resize;}.kiri { atas: 50%; ; kiri: -4px; kursor: w-resize;}.canvas-btns { posisi: kanan: 50px; z-index: 9003;}.canvas-btns button { tampilan: inline-blovk; latar belakang: hijau; kursor: penunjuk; batas: tidak ada; lebar: 60 piksel; ukuran font: 15px;}.kanvas-btns button.active { latar belakang: rgb(32, 230, 32);}.canvas-btns button.close { latar belakang: rgb(230, 72, 32);}.canvas-copy { posisi: absolut; atas: 50% kiri: 50%; margin-kiri: -400px; z-index: 9007;}.canvas-mosatic { posisi: absolut; atas: 50%; 50%; margin-atas: -300 piksel; margin-kiri: -400 piksel; indeks-z: 9009;}.area-kanvas { posisi: absolut; margin-kiri: -400 piksel; indeks-z: 9008;}.ukuran cat{ margin-atas: 20 piksel; 13 piksel; warna: #FFF; tinggi: 30 piksel; tinggi garis: 30 piksel; perataan teks: kanan;}.input ukuran cat{ perataan vertikal: tengah; tampilan: blok sebaris; lebar: 15 piksel;}.hoverClear{ kursor: url('./paint.png'),auto;}.hoverPaint{ kursor: url('./paint.png'),auto;}</style>
4. Terjemahannya adalah sebagai berikut:
MeringkaskanDi atas adalah apa yang diperkenalkan editor kepada Anda berdasarkan kanvas Html5 untuk mewujudkan fungsi pemotongan dan mosaik serta fungsi unggahan cloud. Saya harap ini dapat membantu Anda membalas Anda tepat waktu. Saya juga ingin mengucapkan terima kasih kepada semua orang atas dukungan Anda terhadap situs seni bela diri VeVb!
Jika menurut Anda artikel ini bermanfaat, silakan cetak ulang, harap sebutkan sumbernya, terima kasih!