html5 canvas อัพโหลด และ ลบพื้นหลังของรูป

html5-canvas-อัพโหลด-และ-ลบพื้นหลังของรูป
html5-canvas-อัพโหลด-และ-ลบพื้นหลังของรูป

canvas คือ tags ที่เกิดขึ้นใหม่ใน html เวอร์ชั่น 5 หรือที่เรามักเรียกติดปากว่า html5 ความสามารถของ html5 canvas คือ เราจะสามารถจัดการกับวัตถุที่ถูกวาดลงบน canvas ได้ละเอียดมากขึ้น มากกว่า html element ทั่วไป

canvas จึงเหมาะกับการพัฒนา Game, Animation Frame By Frame, Web Application ในบทความความจะมาแนะนำการอัพโหลดรูปจากเครื่องเรา ไปแสดงผลบน canvas จากนั้นใช้ความสามารถของ canvas context2d ในการลบพื้นหลังของรูป

อัพโหลดรูปแสดงผลบน Canvas

  • เริ่มต้นสร้าง canvas กำหนดความกว้างและความสูง และสร้าง input สำหรับ upload ไฟล์

  • ในส่วนของ javascript เรียกใช้งาน canvas และใช้ getContext2D สำหรับ Context2D เป็นคำสั่งที่จะทำให้เราสามารถ จัดการกับ graphic แบบ 2 มิติบน canvas ได้ ทั้งการวาด การดึง pixel
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
  • เพิ่ม event สำหรับอัพโหลดรูปและสร้างฟังก์ชั่นรับข้อมูลรูป จากนั้นใช้ context2d ในการวาดรูปลงบน canvas
function handleImage(e){
    var reader = new FileReader();
    reader.onload = function(event){
        var img = new Image();
        img.onload = function(){
            var hRatio = canvas.width / img.width    ;
            var vRatio = canvas.height / img.height  ;
            var ratio  = Math.min(hRatio, vRatio);
            ctx.drawImage(img, 0,0, img.width, img.height, 0,0,img.width*ratio, img.height*ratio);
        }
        img.src = event.target.result;
    }
    reader.readAsDataURL(e.target.files[0]);     
}
document.getElementById('fileupload').onchange = handleImage;

ลบพื้นหลังของรูปด้วย Context2D

  • หลังจากที่เราได้รูปที่แสดงบน canvas เรียบร้อยแล้ว ในขั้นตอนต่อไป จะทำการลบพื้นหลังของรูป โดยขั้นตอนการลบพื้นหลังของรูปนั้น ไม่ได้มีอะไรซับซ้อนครับ ก่อนอื่นต้องเข้าใจก่อนว่า รูปแต่ละรูปจะประกอบไปด้วยค่า rgba คือ
    • R = red channel ค่าสีแดง ให้ค่าตัวเลขตั้งแต่ 0 – 255
    • G = green channel ค่าสีเขียว ให้ค่าตัวเลขตั้งแต่ 0 – 255
    • B = blue channel ค่าสีน้ำเงิน ให้ค่าตัวเลขตั้งแต่ 0 – 255
    • A = alpha channel ค่าความโปรงใส ให้ค่าตัวเลขตั้งแต่ 0 – 1
  • จากข้อมูลด้านบนเราคงพอจะนึกภาพออกแล้วไช่ไหมครับว่าจะเปลี่ยนค่าส่วนไหนของรูป เพื่อลบพื้นหลังของเรา นั่นก็คือค่า A หรือ Alpha channel นั่นเอง แต่ก่อนที่เราจะลดค่า alpha ให้เป็น 0 เราต้องรู้ก่อนว่า pixel ไหนบนรูปคือส่วนของ background วิธีการหาว่า pixel ตำแหน่งไหนบนรูปคือ pixel ที่เป็นส่วนของพื้นหลัง วิธีการคือการ นำค่า rgb ไปบนรูป ไปแปลงเป็นค่าสีแบบ hex จากนั้น loop เพื่อหาค่า hex ที่มีจำนวนมากที่สุดบนรูป เราจะได้ค่าสีแบบ hex ตามลำดับ 1 2 3 และนำค่าสี 1 2 3 ตามลำดับนั้นไปลดค่า Alpha channel ให้เท่ากับ 0
  • ใช้คำสั่ง getImageData เพื่อดึง pixel ทั้งหมดบนรูปมา loop หาค่า rgba
var image = ctx.getImageData(0,0,img.width*ratio, img.height*ratio);
var imageData = image.data;
var length = imageData.length;
for (var i=0; i < length; i++) {
    var r = imageData[i];
    var g = imageData[i+1];
    var b = imageData[i+2];
    var a = imageData[i+3];
}
  • จากนั้นแปลงค่า rgba เป็นค่าสีแบบ hex ก่อน
for (var i=0; i < length; i++) {
    var r = imageData[i];
    var g = imageData[i+1];
    var b = imageData[i+2];
    var a = imageData[i+3];
    var hex = RGBtoHEX(parseInt(r),parseInt(g),parseInt(b));
}
function RGBtoHEX(r,g,b){
	return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function componentToHex(c) {
    var hex = c.toString(16);
    return hex.length == 1 ? "0" + hex : hex;
}
  • นำค่าสีแบบ hex ที่ได้จากการ loop pixel ทั้งหมดของรูป ( หรือจริง ๆ ไม่จำเป็นต้อง loop ทุก pixel ก็ได้ อาจจะใช้ row แรก ของ pixel ก็พอจะคาดเดาค่าสีได้ ) ไปเทียบกับค่าสี hex พื้นหลังของรูปภาพ ที่เราได้จากที่อธิบายไว้ในข้อ 2 ถ้าค่าตรงกัน ให้เราทำการลดค่า alpha channel เป็น 0 และใช้คำสั่ง putImageData เพื่อคืนค่า pixel ใหม่กลับไปที่รูปเดิม จะได้ code ทั้งหมด ตามด้านล่างครับ
var color_code_for_remove = "#fbe88c";
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function handleImage(e){
    var reader = new FileReader();
    reader.onload = function(event){
        var img = new Image();
        img.onload = function(){
            var hRatio = canvas.width / img.width    ;
            var vRatio = canvas.height / img.height  ;
            var ratio  = Math.min(hRatio, vRatio);
            ctx.drawImage(img, 0,0, img.width, img.height, 0,0,img.width*ratio, img.height*ratio);

            var image = ctx.getImageData(0,0,img.width*ratio, img.height*ratio);
            var imageData = image.data;
            var length = imageData.length;
            for (var i=0; i < length; i++) {
                var r = imageData[i];
                var g = imageData[i+1];
                var b = imageData[i+2];
                var a = imageData[i+3];
                var hex = RGBtoHEX(parseInt(r),parseInt(g),parseInt(b));
                if(hex == color_code_for_remove){
                    imageData[i+3] = 0;
                }
            }
            
            image.data = imageData;
            ctx.putImageData(image, ((img.height*ratio)/2)+130, 0);
        }
        img.src = event.target.result;
    }
    reader.readAsDataURL(e.target.files[0]);     
}

function RGBtoHEX(r,g,b){
	return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function componentToHex(c) {
    var hex = c.toString(16);
    return hex.length == 1 ? "0" + hex : hex;
}

Leave a Reply