تتضمن ميزات هذا المكون ما يلي:
اقتصاص الصورة (اسحب مربع الاقتصاص وقم بتغيير حجم مربع الاقتصاص)؛
صورة فسيفساء (رسم فسيفساء، فسيفساء واضحة)؛
معاينة الصورة، استعادة الصورة (العودة إلى الصورة الأصلية، العودة إلى الصورة المعالجة)؛
تحميل الصورة (الحصول على التوقيع، تحميل الصورة).
2. المنطق الأساسي2.1 اقتصاص الصورة
احصل على موضع صندوق الاقتصاص (المستطيل) بالنسبة إلى اللوحة القماشية (أعلى اليسار) وارتفاع صندوق الاقتصاص وعرضه. احصل على (getImageData) كائن الصورة (ImageData) في الموضع المقابل من اللوحة القماشية. قم بمسح قماش القماش. ارسم كائن الصورة (ImageData) الذي تم الحصول عليه بواسطة (putImageData) في الموضع المقابل من اللوحة القماشية. إنشاء صورة المعاينة.
2.2 صورة الفسيفساء
رسم الفسيفساء هو إعادة رسم المنطقة المتمركزة على مسار ضربة الماوس (عرض الفرشاة) إلى ألوان أخرى. والنتيجة العامة هي أن الألوان المحيطة ستكون متشابهة.
طريقة اختيار الألوان:
1) على سبيل المثال، إذا كان لديك إحداثيات (x، y) لنقطة متقاطعة بالماوس، فحدد مستطيلًا بإحداثيات الزاوية اليسرى العليا (x، y) وعرضه 30 بكسل وارتفاعه 30 بكسل. نقسم عرض المستطيل وارتفاعه على 5 (مقسمين إلى 5 أجزاء، والتي يمكن تخصيصها إلى أجزاء n)، لذا يوجد الآن 25 شبكة صغيرة بحجم 6 بكسل. يبلغ عرض كل شبكة صغيرة وارتفاعها 6 بكسل.
2) بعد ذلك، نحصل بشكل عشوائي على شبكة صغيرة ونحصل على (getImageData) كائن الصورة (ImageData) لهذه الشبكة الصغيرة، ثم نحصل بشكل عشوائي على لون اللون (rgba: ImageD) لبكسل معين (العرض 1 بكسل، الارتفاع 1 بكسل) على هذا؛ كائن الصورة ata.data[0], ImageData.data[1], ImageData.data[2], ImageData.data[3]); وأخيرًا، قمنا بتعيين لون كل بكسل في الشبكة الصغيرة الأولى مقاس 6x6 بكسل لتلوين .
3) للحصول على ألوان الشبكات الصغيرة الـ 24 الأخرى، ما عليك سوى اتباع خطوتين.
2.3 فسيفساء واضحة
نحن بحاجة إلى فهم المشكلة، سواء كانت رسم فسيفساء أو إزالة فسيفساء، فإن جوهرها هو رسم صورة. قمنا برسم الفسيفساء في موضع معين وعندما نقوم بإزالتها، فإننا نرسم كائن الصورة الأصلي في الموضع الحالي مرة أخرى. يتم تحقيق تأثير التنظيف. لذلك، نحتاج إلى عمل نسخة احتياطية من اللوحة القماشية التي تطابق تمامًا الصورة الأصلية. عند المسح، نحتاج إلى الحصول على الصورة في الموضع المقابل على اللوحة القماشية الاحتياطية ورسمها إلى موضع الفسيفساء.
2.4 معاينة الصورة
تهدف معاينة الصورة إلى الحصول على مساحة إطار الاقتصاص والحصول على كائنات الصورة الموجودة في المنطقة. ثم ارسمه على القماش.
2.5 استعادة الصورة إلى الصورة الأصلية
امسح القماش وارسم الصورة الأصلية مرة أخرى
2.6 استعادة الصورة التي تم التلاعب بها
تهدف المعاينة إلى حفظ كائن صورة اللوحة القماشية (ImageData)، ومسح اللوحة القماشية، ورسم كائن الصورة المحفوظة على اللوحة القماشية.
2.7 تحميل الصور
احصل على مسار صورة قماش (toDataURL) وقم بتحويل صورة base64 التي تم الحصول عليها إلى كائن ملف. للتحميل.
3. الكود الكامل هو كما يلي:
<قالب> <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 left-up @mousedown.stop=startResize($event,0)></div> <div class=canvas-minBox up @mousedown.stop=startResize($event,1)></div> <div class=canvas-minBox right-up @mousedown.stop=startResize($event,2)></div> <div class=canvas- minBox يمين @mousedown.stop=startResize($event,3)></div> <div class=canvas-minBox يمين لأسفل @mousedown.stop=startResize($event,4)></div> <div class=canvas-minBox down @mousedown.stop=startResize($event,5)></div> <div class=canvas-minBox left-down @mousedown.stop=startResize($event,6)></ div div> <div class=canvas-minBox left @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> <!-- قماش النسخ الاحتياطي--> <canvas class=canvas-copy ref=canvasCopy :width=canvasWidth :height=canvasHeight></canvas> <div class=canvas-btns> <button v-if=backBtn @click=clipBack>رجوع</button> <button :class={active:btnIndex==0} @click= sourceImg>الصورة الأصلية</button> <button :class={active:btnIndex==1} @click=paintRectReady :disabled=isDisabled>فسيفساء</button> <button :class={active:btnIndex==2} @click=paintRectClearReady :disabled=isDisabled>Eraser</button> <button :class={active:btnIndex==3 } @click=clipReady :disabled=isDisabled>اقتصاص</button> <button :class={active:btnIndex==4} @click=clipPosition>معاينة</button> <button @click=getSignature>تحميل</button> <button class= Close @click=canvasClose()>x</button> <!-- <div class=paint-size v-if=isMaClear ||.isMa> <span>حجم الفرشاة</span> <input :defaultValue=maSize v-model=maSize max=100 min=1 type=range> <span class=size-num>{{maSize}}</span> </div> --> </div> </div></template><script>استيراد المحاور من axios;استيراد md5 من js-md5 ؛ استيراد الطلب من ../../axios/config؛ تصدير الافتراضي { الدعائم: [imgUrl]، data() { return { resizeFX: , movePrev: , عرض القماش: 800، // عرض القماش، ارتفاع القماش: 600، // تحميل ارتفاع القماش: خطأ، isDrop: خطأ، // الاقتصاص isMa: خطأ، // فسيفساء maSize: 30، // حجم الفسيفساء isMaClear: false، // مسح الفسيفساء backBtn: خطأ، // زر الرجوع معطل: خطأ، // زر التعطيل btnIndex: 0, // الزر الحالي mouseX:'', // موضع الماوس mouseY:'', clipEle: , // عنصر مربع الاقتصاص CanvasDataSession: , // معلومات اللوحة القماشية قبل معاينة اللوحة القماشية: , // Canvas ctx: , // Canvas context CanvasCopy: ، // نسخ القماش ctxCopy:، // نسخ سياق القماش، uploadOption: { // مسار معلمات تحميل الصورة:، السياسة:، التوقيع:، اسم المستخدم: } }; = this.$refs[canvasCopy]; this.ctxCopy = this.canvasCopy.getContext(2d); إنشاء رسم صورة () { var img = new Image();('crossOrigin', 'anonymous'); , 600); this.ctxCopy.drawImage(img, 0, 0, 800, 600 }); img.src = this.imgUrl + '?time=' + new Date().valueOf(); }, // تحسب المعاينة موضع مربع الاقتصاص (الإحداثي العلوي الأيسر) clipPosition() { this.isDisabled = true; this.backBtn = true; this.isMa = false; this.isMaClear = false; this.btnIndex = 4; = this.canvas.offsetTop; if (this.isDrop) { // موضع مربع الاقتصاص var clipPx = this.clipEle.offsetLeft, clipPy = this.clipEle.offsetTop, x = clipPx - CanvasPx, y = clipPy - CanvasPy, w = this.clipEle.offsetWidth, h = this.clipEle.offsetHeight, // توسيط موضع صورة المعاينة X = 400 - this.clipEle.offsetWidth / 2,positionY = 300 - this.clipEle.offsetHeight / 2; } else { // لا يوجد مربع اقتصاص، احفظ الصورة الكاملة var x = 0, y = 0, w = this.canvas.offsetWidth , h = this.canvas.offsetHeight, // توسيط صورة المعاينة PositionX = 0,positionY = 0 } var imageData = this.ctx.getImageData(x, y, w, h); this.canvasDataSession = this.ctx.getImageData( 0, 0, this.canvasWidth, this.canvasHeight ); this.canvasWidth, this.canvasHeight); this.ctx.putImageData(imageData,positionX,positionY); this.clipEle.style.display = none; this.canvasCopy.style.display = none }, // العودة إلى حالة المعاينة المسبقة clipBack() { this.btnIndex = -1; isDisabled = false ; this.isDrop = false; this.ctx.putImageData(this.canvasDataSession, 0, 0); block; }, // مصدر الصورة الأصلي() { this.isDisabled = false; this.btnIndex = 0; this.backBtn = false; = new Image(); this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); img.setAttribute('crossOrigin', 'anonymous'); img.onload = () => { this.ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight }; .imgUrl + '?time=' + new Date().valueOf(); this.canvasCopy.style.display = block }, // احصل على التوقيع getSignature() { // قاعدة صورة القماش إلى كائن الملف var dataURL = this.canvas.toDataURL(image/jpg), arr = dataURL.split(,), mime = arr[0].match(/:( .*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); (n--) { u8arr[n] = bstr.charCodeAt(n); } var obj = new Blob([u8arr], { type: mime }), time = new Date().toGMTString(), formData = new FormData();formData.append(file, obj); // احصل على لاحقة الملف var suffix = formData.get(file).type.split(/)[1]; req .get(/carsource-api/upyun/sign, { suffix: suffix }) .then(response => { if (response.data.code === 0) { this.uploadOption.path = Response.data.data.path;formData.append(policy, Response.data.data.policy); formData.append(authorization, Response.data.data.signature); this.updateImg(formData); : http://v0.api.upyun.com/tmp-img، الطريقة: POST، البيانات: formData }).then(response => { if (response.data.code == 200) { this.$message.success(تم تعديل الصورة بنجاح)؛ this.canvasClose(upload, Response.data.url.slice(4)); تحريك تكبير المربع startResize(e, n) { this.resizeFX = n $(document).mousemove(this.resizeDiv); document.addEventListener(mouseup, this.stopResize }, stopResize(e) { $(document).off(mousemove, this.resizeDiv); 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) { // فسيفساء if (this.isMa) { this.paintRect(e); } // مسح الفسيفساء if (this.isMaClear) { this.paintRectClear(e) } // Crop if (this.isDrop) { var targetDiv = $(#canvas-mainBox), offsetArr = targetDiv.offset(); var chaX = e.pageX - this.movePrev[0], chaY = e.pageY - this.movePrev[1], ox = parseFloat(targetDiv.css(left)), oy = parseFloat(targetDiv.css(top)); targetDiv.css({ left: ox + chaX + px, top: oy + chaY + px }); this.movePrev = [e.pageX, e.pageY]; } }, resizeDiv(e) { e.preventDefault(); e.stopPropagation(); // احصل على المسافة من العنصر الذي يجب تغيير حجمه إلى الصفحة var targetDiv = $(#canvas-mainBox), offsetArr = targetDiv.offset(); = targetDiv.width() , eleSHeight = targetDiv.height(), ox = parseFloat(targetDiv.css(left)), oy = parseFloat(targetDiv.css(top)); // احصل على موضع الماوس وقارنه بالإزاحة الأولية للعنصر، var chaX = e.pageX - offsetArr.left, chaY = e.pageY - offsetArr.top التبديل ( this.resizeFX) { الحالة 0: // إذا كانت مسافة الحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaX >= eleSWidth - 10 || chaY >= eleSHeight - 10) { return } // احصل على فرق الموضع (أنا)، اضبط العرض والارتفاع أولاً، ثم اضبط الموضع // العرض الأصلي والارتفاع + ((me) *-1)، الموضع الأصلي + (me) targetDiv.css({ width: eleSWidth + chaX * -1 + px, height: eleSHeight + chaY * -1 + px, left: ox + chaX + px, top: oy + chaY + px }); Break; case 1: // إذا كانت مسافة الحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaY >= eleSHeight - 10) { return } // احصل على فرق الموضع (أنا)، وقم بتعيين العرض و الارتفاع أولاً، ثم قم بتعيين الموضع // العرض والارتفاع الأصليان + ((me) *-1)، الموضع الأصلي + (me) targetDiv.css({ height: eleSHeight + chaY * -1 + px, top: oy + تشاي + بيكسل }); Break; case 2: // إذا كانت المسافة المتحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaX <= 10 || chaY >= eleSHeight - 10) { return } // احصل على الموضع الفرق (أنا)، قم أولاً بتعيين العرض والارتفاع، قم بتعيين الموضع // الارتفاع الأصلي + ((me) *-1)، العرض الأصلي + ((me))، الموضع الأصلي + (me) targetDiv.css({ width : تشاكس + بكسل، height: eleSHeight + chaY * -1 + px, top: oy + chaY + px }); case 3: // إذا كانت مسافة الحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaX <= 10) ) { return } // احصل على فرق الموضع (أنا)، قم أولاً بتعيين العرض والارتفاع، ثم قم بتعيين الموضع // العرض الأصلي والارتفاع + ((me) *-1)، الموضع الأصلي + (me) targetDiv; .css({ العرض: chaX + px });break; case 4: // إذا كانت المسافة المتحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaX <= 10 || chaY <= 10) { return; الفرق (أنا)، قم بتعيين العرض والارتفاع أولاً، ثم قم بتعيين الموضع // العرض والارتفاع الأصلي + ((me) *-1)، الموضع الأصلي + (me) targetDiv.css({ width: chaX + px, height : chaY + بكسل }); Break; case 5: // إذا كانت مسافة الحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaY <= 10) { return } // احصل على فرق الموضع (أنا)، وقم بتعيين العرض والارتفاع أولاً، ثم قم بتعيين الموضع // العرض والارتفاع الأصلي + ((me) *-1)، الموضع الأصلي + (me) targetDiv.css({ height: chaY + px }); مسافة الحركة قريبة من العرض أو الارتفاع، ولن يتم اتخاذ أي إجراء إذا كان (chaX >= eleSWidth - 10 ||.chaY <= 10) { return } // احصل على فرق الموضع (أنا)، قم أولاً بتعيين العرض والارتفاع، ثم قم بتعيين الموضع // العرض والارتفاع الأصلي + ((me) * -1)، الموضع الأصلي + (me) targetDiv.css({ width: eleSWidth + chaX * -1 + px, height: chaY + px, left: ox + chaX + px }); 7: // إذا كانت مسافة الحركة قريبة من العرض أو الارتفاع، فلن يتم إجراء أي تغيير if (chaX >= eleSWidth - 10) { return } // احصل على فرق الموضع (أنا)، قم بتعيين العرض والارتفاع أولاً ، ثم قم بتعيين الموضع // العرض الأصلي والارتفاع + ((me) *-1)، الموضع الأصلي + (me) targetDiv.css({ width: eleSWidth + chaX * -1 + px, left: ox + chaX + بكسل }); فاصل؛ الافتراضي: فاصل } }, // clipReady() { this.btnIndex = 3; this.isMa = false; this.isDrop = true; btnIndex = 1; this.isMa = true; this.isDrop = false; ممحاة PaintRectClearReady() { this.btnIndex = 2; this.isMa = false; this.isDrop = false; this.isMaClear = true }, // رسم الفسيفساء PaintRect(e) { var offT = this.canvas.offsetTop, / / المسافة من الأعلى offL = this.canvas.offsetLeft, // المسافة من اليسار x = e.clientX, y = e.clientY; if(this.mouseX - x > this.maSize/2 || x - this.mouseX > this.maSize/2 || this.mouseY - y > this.maSize/2 || y - this.mouseY; > this.maSize/2){ var oImg = this.ctx.getImageData(x - offL ,y - offT,this.maSize,this.maSize); var w = oImg.width; var h = oImg.height; // درجة الفسيفساء، كلما زاد العدد، زاد التشويش var num = 6; Canvas var stepW = w/ num; var stepH = h/num; ي++){ // احصل على اللون العشوائي لمربع صغير. هذا هو لون var الذي تم الحصول عليه من الموضع العشوائي للمربع الصغير = this.getXY(oImg,j*num+Math.floor(Math.random()*num),i. *num +Math.floor(Math.random()*num)); // هنا هي بكسلات المربع الصغير الدائري، for(var k=0;k<num;k++){ for(var l=0; ل< الأعداد؛ل++){ // اضبط لون المربع الصغير this.setXY(oImg,j*num+l,i*num+k,color); this.mouseX = e.clientX this.mouseY = e.clientY } }, getXY(obj,x,y){ var w = obj.width; var h = obj.height; var d = obj.data; var color[0] = d[4*(y*w+x)]; w+x)+1]; color[2] = d[4*(y*w+x)+2]; color[3] = d[4*(y*w+x)+3]; }, setXY(obj,x,y,color){ var w = obj.width; var h = obj.height; var d = obj.data; d[4*(y*w+x)+1] = color[1]; d[4*(y*w+x)+2] = color[2]; d[4*(y*w+x)+3] = color[3] }, // مسح الفسيفساء PaintRectClear(e) { var offT = this.canvasCopy.offsetTop, // المسافة من الأعلى offL = this.canvasCopy .offsetLeft, // المسافة إلى اليسار x = e.clientX, y = e.clientY, // احصل على بيانات الصورة في هذا الموضع من الصورة الأصلية imageData = this.ctxCopy.getImageData( x - offL, y - offT, this.maSize, this.maSize ); this.ctx.putImageData(imageData, x - offL, y - offT }, // أغلق اللوحة القماشية CanvasClose(type , url) { this.$emit(isShowImgChange, type, url } }};</script><style نطاق>.canvas-clip { الموضع: ثابت؛ الجزء السفلي: 0؛ اليمين: مؤشر z: 9010؛ }.canvas-mainBox { الموضع: العرض المطلق: 400 بكسل؛ الارتفاع: 300 بكسل؛ اليسار: 50%؛ الهامش الأيسر: -200 بكسل؛ 1px Solid #FFF؛ : -4px؛ المؤشر: nw-resize;}.up { الأعلى: -4px; n-resize;}.right-up { top: -4px; right: -4px; -resize;}.right-down { Bottom: -4px; اليمين: -4px; الهامش الأيسر: -4 بكسل؛ المؤشر: تغيير الحجم؛ }.left-down { أسفل: -4px؛ اليسار: -4px؛ }.left { top: 50%; ؛ اليسار: -4 بكسل؛ المؤشر: تغيير الحجم؛}.canvas-btns { الموضع: ثابت على اليمين: 50 بكسل؛ z-index: 9003;}.canvas-btns Button {display: inline-blovk; حجم الخط: 15px;}.canvas-btns Button.active { الخلفية: rgb(32, 230, 32);.canvas-btns Button.إغلاق { الخلفية: rgb(230, 72, 32);).canvas-copy { الموضع: الجزء العلوي المطلق: 50% اليسار: 50%; الهامش الأيسر: -400 بكسل؛ الفهرس z: 9007؛ }.canvas-mosatic { الموضع: الجزء العلوي المطلق: 50%؛ 50% الهامش العلوي: -300 بكسل؛ الهامش الأيسر: -400 بكسل؛ .canvas-area { الموضع: الأعلى المطلق: 50%؛ الهامش الأيسر: -400 بكسل؛ الفهرس z: 9008؛}.حجم الطلاء{ الهامش العلوي: 20 بكسل حجم الخط: 13 بكسل؛ اللون: #FFF؛ الارتفاع: 30 بكسل؛ ارتفاع الخط: 30 بكسل؛ عرض: كتلة مضمنة؛ العرض: 15 بكسل؛}.hoverClear{ المؤشر: url('./paint.png'),auto;}.hoverPaint{ المؤشر: url('./paint.png'),auto;}</style>
4. الاداءات هي كما يلي:
تلخيصما ورد أعلاه هو ما يقدمه لك المحرر استنادًا إلى لوحة Html5 لتحقيق وظائف اقتصاص الصور والفسيفساء وتحميل الصور إلى السحابة، وآمل أن يكون ذلك مفيدًا لك، إذا كانت لديك أي أسئلة، فيرجى ترك رسالة لي سيقوم المحرر بالرد عليك في الوقت المناسب. أود أيضًا أن أشكر الجميع على دعمكم لموقع VeVb للفنون القتالية!
إذا كنت تعتقد أن هذه المقالة مفيدة لك، فنحن نرحب بإعادة طبعها، يرجى الإشارة إلى المصدر، شكرًا لك!