ที่อยู่เดิม: github.com/whinc/blog/…
ล่าสุดฉันได้รับคำขอให้โพสต์ความคิดเห็น: ผู้ใช้ป้อนความคิดเห็นและสามารถถ่ายรูปหรือเลือกรูปภาพจากอัลบั้มที่จะอัปโหลด ซึ่งหมายความว่ารองรับข้อความและความคิดเห็นรูปภาพ บทความนี้จำเป็นต้องดำเนินการกับทั้ง H5 และมินิโปรแกรมในเวลาเดียวกัน รหัสโครงการจะขึ้นอยู่กับกรอบงาน Vue เพื่อหลีกเลี่ยงการได้รับผลกระทบจากกรอบงาน ฉันจึงเปลี่ยนรหัสทั้งหมดเป็นการใช้งาน Native API เพื่ออธิบาย ในเวลาเดียวกัน ยังมีรายละเอียดและฟังก์ชันเพิ่มเติมอื่นๆ อีกมากมาย (ตัวอย่าง) , การครอบตัด ความคืบหน้าในการอัปโหลด ฯลฯ ) ในโค้ดโปรเจ็กต์ที่นี่ ละเว้นและแนะนำเฉพาะแนวคิดหลักและโค้ดที่เกี่ยวข้องกับการประมวลผลภาพ การใช้งานมินิโปรแกรมจะคล้ายกับ H5 และจะไม่ถูกทำซ้ำ รหัสการใช้งานของมินิโปรแกรมจะแนบอยู่ท้ายบทความ
ภาพถ่ายใช้แท็ก <input> ตั้งค่าประเภทเป็นไฟล์เพื่อเลือกไฟล์ ตั้งค่ายอมรับเป็น image/* เพื่อเลือกประเภทไฟล์และกล้อง และตั้งค่าหลายรายการเพื่อรองรับการเลือกหลายรายการ ฟังเหตุการณ์การเปลี่ยนแปลงเพื่อรับรายการไฟล์ที่เลือก แต่ละไฟล์จะเป็นประเภท Blob
<input type=file Accept=image/* multiple /> <img class=preivew /> <script type=text/javascript> ฟังก์ชั่น onFileChange (เหตุการณ์) { const files = Array.prototype.slice.call(event.target.files ) files.forEach(file => console.log('ชื่อไฟล์:', file.name)) } document.querySelector('input').addEventListener('change', onFileChange) </script>ตัวอย่างรูปภาพ
เมธอด URL.createObjectURL สามารถสร้างเส้นทาง URL ในเครื่องที่ชี้ไปยังวัตถุทรัพยากรในเครื่องได้ อินเทอร์เฟซนี้ใช้ด้านล่างเพื่อสร้างที่อยู่ของรูปภาพที่เลือกและแสดง
ฟังก์ชั่น onFileChange (เหตุการณ์) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] document.querySelector('img').src = window.URL.createObjectURL(file) }การหมุนภาพ
ภาพที่ถ่ายด้วยกล้องอาจหมุนได้เนื่องจากทิศทางการถือกล้องขณะถ่ายภาพ และจำเป็นต้องได้รับการแก้ไข การแก้ไขการหมุนจำเป็นต้องทราบข้อมูลการหมุนของภาพ ในที่นี้ เราใช้ไลบรารี่ที่เรียกว่า exif-js ซึ่งสามารถอ่านข้อมูลเมตา EXIF ของภาพ รวมถึงทิศทางของกล้องเมื่อถ่ายภาพตามทิศทางนี้ ข้อมูลของภาพสามารถคำนวณได้
ต่อไปนี้เป็นบิตธงการหมุน EXIF มีทั้งหมด 8 แบบ แต่เมื่อถ่ายภาพผ่านกล้องจะสร้างได้เพียง 1, 3, 6 และ 8 เท่านั้น ซึ่งสอดคล้องกับกล้องปกติหมุนตามเข็มนาฬิกา 180° , หมุนทวนเข็มนาฬิกา 90° และหมุนตามเข็มนาฬิกา
ดังนั้นเพื่อแก้ไขมุมการหมุนภาพ คุณเพียงแค่ต้องอ่านแฟล็กการหมุน EXIF ของรูปภาพ กำหนดมุมการหมุน หมุนภาพบนผืนผ้าใบ และส่งออกรูปภาพใหม่อีกครั้ง เกี่ยวกับการดำเนินการหมุนของผืนผ้าใบ คุณสามารถดูบทความ "การหมุนภาพแคนวาสและการปลดล็อกท่าพลิก" ฟังก์ชันต่อไปนี้ใช้การแก้ไขมุมการหมุนของไฟล์รูปภาพ รับไฟล์รูปภาพ และส่งคืนไฟล์รูปภาพใหม่ที่ถูกแก้ไข
/** * แก้ไขปัญหามุมการหมุนภาพ * @param {file} รูปภาพต้นฉบับ * @return {Promise} สัญญาที่ได้รับการแก้ไขแล้ว ส่งคืนรูปภาพใหม่ที่ถูกแก้ไข */function fixImageOrientation (ไฟล์) { return new Promise((แก้ไข, ปฏิเสธ) => { // รับรูปภาพ const img = รูปภาพใหม่ (); img.src = window.URL.createObjectURL (ไฟล์); img.onerror = () => แก้ไข (ไฟล์); img.onload = () => { // รับข้อมูลเมตาของรูปภาพ (ตัวแปร EXIF เป็นตัวแปรส่วนกลางที่เปิดเผยโดยไลบรารี่ exif-js ที่แนะนำ) EXIF.getData(img, function() { // รับการตั้งค่าสถานะการหมุนรูปภาพ var การวางแนว = EXIF.getTag(นี่, การวางแนว); // หมุนรูปภาพบนผืนผ้าใบตามมุมการหมุนถ้า (การวางแนว === 3 || การวางแนว === 6 || การวางแนว === 8) { const canvas = document.createElement(canvas); const ctx = canvas.getContext(2d); สวิตช์ (การวางแนว) { กรณีที่ 3: // หมุน 180° canvas.width = img.width; (180 * Math.PI) / 180); ctx.drawImage(img, -img.width, -img.height, img.width, img.height); กรณีที่ 6: // หมุน 90° canvas.width = img.height; canvas.height = ctx.rotate((90 * Math.PI) / 180); ctx.drawImage(img, 0, -img.height, img.width, img.height); กรณีที่ 8: // หมุน -90° canvas.width = img.height; canvas.height = img.width; ctx.rotate((-90 * Math.PI) / 180); .width, img.height); } // คืนรูปภาพใหม่ canvas.toBlob(file => solve(file), 'image/jpeg', 0.92) } อื่น ๆ { กลับแก้ไข (ไฟล์ } });}การบีบอัดภาพ
ปัจจุบันนี้ เอฟเฟ็กต์กล้องของโทรศัพท์มือถือเริ่มดีขึ้นเรื่อยๆ และด้วยขนาดรูปภาพที่เพิ่มขึ้น ซึ่งสามารถไปถึงสองสาม MB หรือแม้แต่มากกว่าสิบ MB ได้อย่างง่ายดาย การอัปโหลดรูปภาพต้นฉบับโดยตรงนั้นช้าและล้มเหลวในการอัปโหลดได้ง่าย และพื้นหลังยังมีข้อจำกัดเกี่ยวกับขนาดของเนื้อหาคำขอ การโหลดการแสดงรูปภาพในภายหลังก็จะช้าลงเช่นกัน ปัญหาเหล่านี้สามารถแก้ไขได้หากส่วนหน้าบีบอัดรูปภาพแล้วอัปโหลด
ฟังก์ชันต่อไปนี้ใช้การบีบอัดรูปภาพ หลักการคือการวาดภาพที่ปรับขนาดบนผืนผ้าใบ และสุดท้ายส่งออกภาพที่บีบอัดจากผืนผ้าใบ มีสองวิธีในการควบคุมการบีบอัดรูปภาพ วิธีแรกคือการควบคุมอัตราการซูมของรูปภาพ และวิธีที่สองคือการควบคุมคุณภาพของรูปภาพที่ส่งออก
/** * รูปภาพที่ถูกบีบอัด * @param {file} อินพุตรูปภาพ * @returns {Promise} สัญญาที่แก้ไขแล้ว ส่งคืนรูปภาพที่บีบอัดใหม่ */function compressImage(file) { return new Promise((แก้ไข, ปฏิเสธ) => { // รับ รูปภาพ (การโหลดรูปภาพเพื่อให้ได้ความกว้างและความสูงของรูปภาพ) const img = new Image(); img.src = window.URL.createObjectURL(file); img.onerror = error => ปฏิเสธ (ข้อผิดพลาด); img.onload = () => { // ความกว้างและความสูงของผ้าใบ const canvasWidth = document.documentElement.clientWidth * window.devicePixelRatio; const canvasHeight = document.documentElement.clientHeight * window.devicePixelRatio; factor // ในที่นี้ฉันใช้ปัจจัยสเกลแนวนอนและแนวตั้งที่ใหญ่กว่าเป็นปัจจัยสเกล เพื่อให้แน่ใจว่าเนื้อหารูปภาพทั้งหมดจะมองเห็นได้ const scaleX = canvasWidth / img.width; const scaleY = canvasHeight / img.height; const scale = Math.min(scaleX, scaleY); // ปรับขนาดรูปภาพต้นฉบับตามปัจจัยการปรับขนาดและวาดลงบนผืนผ้าใบ const canvas = document.createElement ('canvas'); const ctx = canvas.getContext(2d); canvas.width = canvasWidth; canvas.height = canvasHeight; img.width * สเกล; const imageHeight = img.height * สเกล; const dx = (canvasWidth - imageWidth) / 2; const dy = (canvasHeight - imageHeight) / 2; ); // ส่งออกรูปภาพใหม่ // ระบุประเภท MIME ของรูปภาพเป็น 'image/jpeg' ผ่านคุณภาพ ควบคุมคุณภาพของภาพที่ส่งออกและใช้การบีบอัดภาพ const quality = 0.92 canvas.toBlob(file => solve(tempFile), image/jpeg, quality); };อัพโหลดรูปภาพ
สร้างข้อมูลแบบฟอร์มผ่าน FormData และเริ่มคำขอ ajax POST
หมายเหตุ: เมื่อส่งข้อมูล FormData เบราว์เซอร์จะตั้งค่า Content-Type ให้เป็นค่าที่เหมาะสมโดยอัตโนมัติ ไม่จำเป็นต้องตั้งค่า Content-Type มิฉะนั้นข้อผิดพลาดจะถูกรายงานเนื่องจากเบราว์เซอร์สร้างขอบเขตตัวคั่นเนื้อหาคำขอ HTTP และไม่สามารถตั้งค่าด้วยตนเองได้
/** * อัปโหลดไฟล์* @param {ไฟล์} ไฟล์ ไฟล์ที่จะอัปโหลด* @returns {สัญญา} ส่งคืนสัญญาที่แก้ไขแล้ว หากการอัปโหลดสำเร็จ มิฉะนั้นจะส่งคืนสัญญาที่ถูกปฏิเสธ */function uploadFile (ไฟล์) { คืนสัญญาใหม่ ((แก้ไข , ปฏิเสธ) = > { // เตรียมข้อมูลแบบฟอร์ม const formData = new FormData() formData.append('file', file) // ส่งคำขอ const xhr = new XMLHttpRequest() xhr.open('POST', uploadUrl) xhr.onreadystatechange = function () { ถ้า (this.readyState === XMLHttpRequest.DONE && this.status === 200) { แก้ไข (JSON.parse (this.responseText)) } else { ปฏิเสธ(this.responseText) } } xhr.send(formData) })}สรุป
ด้วยฟังก์ชันเสริมข้างต้น การประมวลผลจึงง่ายกว่ามาก รหัสการโทรสุดท้ายมีดังนี้:
ฟังก์ชั่น onFileChange (เหตุการณ์) { const files = Array.prototype.slice.call(event.target.files) const file = files[0] // แก้ไขการหมุนภาพ fixImageOrientation(file).then(file2 => { // สร้างตัวอย่าง Image document.querySelector('img').src = window.URL.createObjectURL(file2) // การบีบอัดข้อมูลกลับ compressImage(file2) }).then(file3 => { // อัปเดตภาพตัวอย่าง document.querySelector('img').src = window.URL.createObjectURL(file3) // อัปโหลด return uploadFile(file3) }).then(data => { console.log('การอัปโหลดสำเร็จ') }).catch(ข้อผิดพลาด => { console.error('การอัปโหลดล้มเหลว') })}
H5 จัดเตรียมอินเทอร์เฟซสำหรับการประมวลผลไฟล์ ด้วยความช่วยเหลือของ Canvas การประมวลผลภาพที่ซับซ้อนสามารถนำมาใช้ในเบราว์เซอร์ได้ การอ้างอิงบางส่วนเมื่อเผชิญกับความต้องการที่คล้ายกันในอนาคต
สิ่งที่แนบมาด้วยคือข้อมูลอ้างอิงการใช้งานโปรแกรมขนาดเล็ก
// ถ่ายภาพ wx.chooseImage({ sourceType: [กล้อง], ความสำเร็จ: ({ tempFiles }) => { const file = tempFiles[0] // ประมวลผลภาพ }});/** * บีบอัดรูปภาพ* @param { วัตถุ } พารามิเตอร์ * filePath: สตริง เส้นทางรูปภาพอินพุต * ความสำเร็จ: ฟังก์ชัน จะถูกเรียกกลับเมื่อการบีบอัดสำเร็จ และส่งคืนเส้นทางรูปภาพที่บีบอัดใหม่ * ล้มเหลว: ฟังก์ชัน โทรกลับเมื่อการบีบอัดล้มเหลว */compressImage({ filePath, Success, Fail }) { // รับความกว้างและความสูงของภาพ wx.getImageInfo({ src: filePath, Success: ({ width, height }) => { const systemInfo = wx .getSystemInfoSync (); const canvasWidth = systemInfo.screenWidth; อัปเดตขนาดแคนวาส this.setData({ canvasWidth, canvasHeight }) // คำนวณอัตราส่วนสเกล const scaleX = canvasWidth / width; const scaleY = canvasHeight / height; const scale = Math.min(scaleX, scaleY); * scale ; const imageHeight = height * scale; // วาดภาพที่ปรับขนาดลงบนผืนผ้าใบ const ctx = wx.createCanvasContext(hidden-canvas); dx = (canvasWidth - imageWidth) / 2; ให้ dy = (canvasHeight - imageHeight) / 2; ctx.drawImage(filePath, dx, dy, imageWidth, imageHeight); ภาพที่บีบอัดเป็นไฟล์ชั่วคราว wx.canvasToTempFilePath ({ canvasId: Hidden-canvas, width: canvasWidth, ความสูง: canvasHeight, destWidth: canvasWidth, destHeight: canvasHeight, fileType: jpg, คุณภาพ: 0.92, ความสำเร็จ: ({ tempFilePath }) => { // ซ่อนผ้าใบ this.setData({ canvasWidth: 0, canvasHeight: 0 } ) // การบีบอัดสำเร็จแล้ว ({ tempFilePath } }, ล้มเหลว: error => { // ซ่อน canvas this.setData({ canvasWidth: 0, canvasHeight: 0 }) ล้มเหลว(ข้อผิดพลาด); อัปโหลดไฟล์*/uploadFile({ uploadUrl, filePath, onData, onError }) { wx.uploadFile({ url: uploadUrl filePath: filePath, ชื่อ: ไฟล์, ส่วนหัว: { Cookie: cookie }, Success: res => { if (res.statusCode === 200) { onData(res.data) } else { onError(res); } }, ล้มเหลว: error => { onError(ข้อผิดพลาด); } });}สรุป
ข้างต้นคือโปรแกรม HTML5 และโปรแกรมขนาดเล็กที่โปรแกรมแก้ไขแนะนำเพื่อใช้งานฟังก์ชั่นการหมุน การบีบอัด และการอัพโหลดรูปภาพ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใดๆ โปรดฝากข้อความถึงฉัน แล้วโปรแกรมแก้ไขจะตอบกลับ คุณทันเวลา ฉันอยากจะขอบคุณทุกคนที่ให้การสนับสนุนเว็บไซต์ศิลปะการต่อสู้ VeVb!