เคยไหมกับการที่เราต้องการทำระบบเซฟภาพจากเว็บไซต์ของเรา แต่ที่เราต้องการเซฟดันเป็น HTML แทนที่จะเป็นไฟล์ภาพ จะให้ user แคปจอเอาเองก็ดูจะเป็นการลำบาก user ไปหน่อย ในบทความนี้จะขอนำเสนอ Library ที่จะแปลง HTML ให้กลายเป็นรูปภาพ นั่นก็คือ HTML2Canvas นั่นเอง!
เขียนโดย
Thanawat Udchachon
Internship @ borntoDev
Canvas คืออะไร
ก่อนอื่นเรามาทำความรู้จักกับ Canvas กันก่อนดีกว่าว่ามันคืออะไร เจ้า Canvas มันก็คือ element หนึ่งใน HTML5 ที่ใช้สำหรับการวาดกราฟฟิก ไม่ว่าจะเป็น text เส้น หรือรูปทรงต่าง ๆ ซึ่งเราสามารถคลิกขวาแล้วเซฟเป็นไฟล์ภาพได้ โดย canvas จะมี attribute 2 ตัวคือ width และ height ซึ่งก็คือความกว้างและความสูงของ canvas โดยมีข้อควรรู้คือ canvas จะเริ่มจุด 0, 0 ที่มุมซ้ายบน ต่างจากที่เราคุ้นชินกันที่จะเริ่มจุด 0, 0 ที่ตรงกลาง
การใช้งาน HTML2Canvas
ทีนี้เราก็มาถึงพระเอกของบทความนี้กันแล้ว นั่นก็คือ HTML2Canvas โดยมันคือสคริปที่ใช้สำหรับการแปลง HTML ให้กลายเป็นภาพ png, jpg หรือ pdf ได้โดยการแปลง HTML เหล่านั้นเป็น Canvas นั่นเอง
สำหรับการใช้งานก็สามารถไปติดตั้งตามลิงก์นี้ได้เลยครับ https://www.npmjs.com/package/html2canvas
สำหรับการใช้งาน ในที่นี้เราก็จะใช้เป็น react เช่นเคย และตัวอย่างของเราก็คือ ใบ certificate ของ devlab นั่นเอง
จะเห็นได้จากตัวอย่างจะเห็นได้ว่าเราไม่สามารถคลิกขวาที่ certificate เพื่อ save as image ได้ เพราะตัว certificate นี้เป็น HTML ดังนั้นสิ่งที่เราจะทำกันก็คือแปลง HTML นี้ให้เป็น canvas มาดูตัวอย่างโค้ดกันเลยดีกว่า
import React, { useRef } from 'react'; import html2canvas from 'html2canvas'; const Certification = () => { const certificateRef = useRef(null); const screenShot = (element) => { html2canvas(element).then((canvas) => { document.body.appendChild(canvas); }); }; return ( <div> <div ref={certificateRef}> <Certificate /> </div> <button onClick={() => screenShot(certificateRef.current)}> ดาวน์โหลด </button> </div> ); }; export default CertificationOnline;
จากโค้ดตัวอย่าง เราได้สร้าง function ที่ชื่อว่า screenShot โดย function นี้ก็จะทำการใช้ html2canvas เพื่อแปลง HTML element ที่เราใส่เข้ามาให้กลายเป็น canvas แล้วหลังจากนั้นก็ทำการแสดงผล canvas นั้น และสำหรับในฝั่ง return ก็จะมี component ที่เราต้องการที่จะแปลงเป็น canvas เราก็ใช้ useRef ที่เป็น hook ของ react สำหรับการอ้างอิง (ถ้าหากเพื่อน ๆ ไม่ได้ใช้ react ก็สามารถใช้ id แทนได้นะครับ) จากนั้นเราก็สร้างปุ่มที่เมื่อกดจะไปเรียกฟังก์ชัน screenShot โดยใส่ element เป็นตัว certificate ของเราโดยอ้างอิงจาก useRef ที่เราได้ใส่ไปนั่นเอง
ทีนี้ตัว certificate ที่เราได้ทำการ append ออกมาก็สามารถที่จะเซฟเป็นภาพได้แล้วครับผม
โดยถ้าหากเพื่อน ๆ ไม่ได้ต้องการให้เป็นการกดปุ่มเพื่อ append ต่อออกมา แต่ต้องการให้เมื่อกดปุ่มแล้วเป็นการเซฟภาพลงเครื่องเลยก็สามารถทำได้เช่นกันครับ เรามาดูตัวอย่างโค้ดกันดีกว่า
const printDocument = (domElement) => { html2canvas(domElement).then((canvas) => { const image = canvas.toDataURL('png'); const a = document.createElement('a'); a.setAttribute('download', 'certificate.png'); a.setAttribute('href', image); a.click(); }); };
ในส่วนของ function นี้เราก็แค่เปลี่ยนจาก document.body.appendChild(canvas); เป็นการแปลง canvas ที่ได้ออกมาเป็นไฟล์ png แล้วเมื่อกดปุ่มก็จะเป็นการดาวน์โหลดภาพนั้น โดยจะมีชื่อว่า certificate.png ครับ
Options ของ HTML2Canvas
นอกจากการเปลี่ยง HTML ให้เป็น canvas เฉย ๆ แล้ว library ตัวนี้ก็ยังมี options เพิ่มเติมในการสร้าง canvas อยู่อีก ตัวอย่างเช่น หากหน้าที่เราต้องการที่จะ screenshot นั้นเป็นหน้ายาว เราก็สามารถใส่ option scrollY ตามตัวอย่างโค้ดด้านล่างนี้
html2canvas(element, { scrollY: -window.scrollY }).then((canvas) => { document.body.appendChild(canvas); });
หรือเราต้องการให้ canvas ที่ออกมาใหญ่กว่า HTML ที่เราเขียนไว้ด้วย ก็สามารถใส่ option scale ได้ตามตัวอย่างโค้ดนี้
html2canvas(element, { scrollY: -window.scrollY, scale: 2 }).then((canvas) => { document.body.appendChild(canvas); });
นอกจากนี้ก็ยังมี options อื่น ๆ อีกมากมาย เพื่อน ๆ สามารถดูรายละเอียดเพิ่มเติมได้ที่ลิงก์นี้เลยครับผม https://html2canvas.hertzen.com/configuration
ข้อจำกัดของ HTML2Canvas
ถึงจะดูใช้ง่ายใช้ดีอย่างนี้ แต่ HTML2Canvas ก็มีข้อจำกัดอยู่บ้างเหมือนกันเพราะด้วยความที่มันไม่ได้เป็นการ screenshot หน้านั้นมาตรง ๆ เหมือนกับการแคปหน้าจอโทรศัพท์ แต่เป็นการสร้างภาพนั้นจาก browser ของฝั่ง client เอง ทำให้ไม่สามารถสร้างภาพที่เรนเดอร์จากฝั่ง server ได้ ยังมีการติดในเรื่องของ cross-origin และ proxy อยู่ในการสร้างภาพ จะทำให้ไม่สามารถแสดงภาพเหล่านั้นได้ ดังรูป
จะเห็นได้ว่าภาพที่ติดปัญหาจะไม่ขึ้น ซึ่งเกิดมาจากการที่โหลดข้อมูลจาก origin อื่นที่ไม่ผ่าน CORS ทำให้ canvas นั้นเป็น taint ซึ่งจะส่งผลทางด้านความปลอดภัย แต่ก็สามารถแก้ได้ด้วยการใส่ allowTaint: true เพื่อเป็นการอนุญาตให้แสดงภาพที่เป็น taint ได้ ไปในส่วนของ option ดังตัวอย่างโค้ด
html2canvas(element, { allowTaint: false }).then((canvas) => { document.body.appendChild(canvas); });
ซึ่งก็จะสามารถสร้าง canvas ที่มีภาพที่ติดปัญหาได้แล้ว แต่ถ้าหาก function ของเราเป็นการเซฟภาพลงเครื่องแล้วก็จะเจอกับ error DOMException: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported. ดังนั้นการตรวจสอบที่อยู่ไฟล์น่าจะเป็นทางออกที่ดีที่สุดครับ นอกจากนี้ก็ยังมีปัญหากับบางภาษา เช่น สระลอยในภาษาไทย
สรุปสุดท้ายสิ่งที่ผู้อ่านจะได้รับ
เป็นยังไงกันบ้างครับสำหรับการนำ HTML2Canvas มาเปลี่ยน HTML เป็น Canvas เรียกได้ว่าค่อนข้างง่ายไม่ซับซ้อนกันเลยทีเดียว แต่สำหรับ library ตัวนี้ทางผู้พัฒนาได้บอกไว้ว่ายังเป็น script สำหรับ experimental อยู่ แต่ก็ถือว่าเป็นทางเลือกหนึ่งสำหรับการนำ library นี้ไปปรับใช้กับโปรเจกต์ของเพื่อน ๆ ครับผม
อ้างอิงจาก
- HTML5 Canvas คืออะไร? + วิธีใช้งานเบื้องต้น, สืบค้นเมื่อ 18 กุมภาพันธ์ 2565 จาก: https://devahoy.com/blog/2015/02/html5-canvas-tutorial/
- html2canvas Screenshots with JavaScript, สืบค้นเมื่อ 14 กุมภาพันธ์ 2565 จาก: https://html2canvas.hertzen.com/
- Html2canvas configuration, สืบค้นเมื่อ 17 กุมภาพันธ์ 2565 จาก: https://html2canvas.hertzen.com/configuration
- html2canvas, สืบค้นเมื่อ 14 กุมภาพันธ์ 2565 จาก: https://www.npmjs.com/package/html2canvas
- Allowing cross-origin use of images and canvas, สืบค้นเมื่อ 17 กุมภาพันธ์ 2565 จาก: https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image