2015-03-24 1 views
0

У меня есть черно-белое изображение, и я хотел бы нарисовать его цветом, который я выбрал, не снимая изображения. Когда я начинаю рисовать свою картину, изображение тоже граничит.Нарисуйте изображение, не удаляя его на холсте html5

Я хотел бы еще иметь изображение там и краска просто «фон» в PNG изображения просто, как этот сценарий: «http://www.williammalone.com/articles/create-html5-canvas-javascript-drawing-app/#demo-sizes»

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
    <meta charset="utf-8"> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
    <meta name="viewport" content="width=device-width, initial-scale=1"> 
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet"> 
<script src="js/jquery-1.11.2.min.js"></script> 

<!--http://perfectionkills.com/exploring-canvas-drawing-techniques/--> 
<script type="text/javascript"> 


var isFirefox = typeof InstallTrigger !== 'undefined'; 

var CanvasLogBook = function() { 
    this.index = 0; 
    this.logs = []; 
    this.logDrawing(); 
}; 
CanvasLogBook.prototype.sliceAndPush = function(imageObject) { 
    var array; 
    if (this.index == this.logs.length-1) { 
     this.logs.push(imageObject); 
     array = this.logs; 
    } else { 
     var tempArray = this.logs.slice(0, this.index+1); 
     tempArray.push(imageObject); 
     array = tempArray; 
    } 
    if (array.length > 1) { 
     this.index++; 
    } 
    return array; 
}; 
CanvasLogBook.prototype.logDrawing = function() { 
    if (isFirefox) { 
     var image = new Image(); 

     image.src = document.getElementById('can').toDataURL(); 
     //var canvas = document.getElementsByClassName("can"); 
     //image.src = canvas.toDataURL(); 

     this.logs = this.sliceAndPush(image); 
    } else { 
     var imageData = document.getElementById('can').toDataURL(); 
     this.logs = this.sliceAndPush(imageData); 
    } 
}; 
CanvasLogBook.prototype.undo = function() { 
    ctx.clearRect(0, 0, $('#can').width(), $('#can').height()); 
    if (this.index > 0) { 
     this.index--; 
     this.showLogAtIndex(this.index); 
    } 
}; 
CanvasLogBook.prototype.redo = function() { 
    if (this.index < this.logs.length-1) { 
     ctx.clearRect(0, 0, $('#can').width(), $('#can').height()); 
     this.index++; 
     this.showLogAtIndex(this.index); 
    } 
}; 
CanvasLogBook.prototype.showLogAtIndex = function(index) { 
    ctx.clearRect(0, 0, $('#can').width(), $('#can').height()); 
    if (isFirefox) { 
     var image = this.logs[index]; 
     ctx.drawImage(image, 0, 0); 
    } else { 
     var image = new Image(); 
     image.src = this.logs[index]; 
     ctx.drawImage(image, 0, 0); 
    } 
}; 




$(document).ready(function() { 

    var canvasLogBook = new CanvasLogBook(); 

    $("#undo").click(function() { 
     canvasLogBook.undo(); 
    }); 

    $("#redo").click(function() { 
     canvasLogBook.redo(); 
    }); 


    $("canvas").click(function() { 
     canvasLogBook.logDrawing(); 
    }); 

}); 




var img = document.createElement("img");  // Create a <button> element 
img.setAttribute('src','img.png'); 

var canvas, ctx, flag = false, 
    prevX = 0, 
    currX = 0, 
    prevY = 0, 
    currY = 0, 
    dot_flag = false; 

var x = "black", 
    y = 10; 

function init() { 
    canvas = document.getElementById('can'); 
    ctx = canvas.getContext("2d"); 
    w = canvas.width; 
    h = canvas.height; 


    canvas.addEventListener("mousemove", function (e) { 
     findxy('move', e) 
    }, false); 
    canvas.addEventListener("mousedown", function (e) { 
     findxy('down', e) 
    }, false); 
    canvas.addEventListener("mouseup", function (e) { 
     findxy('up', e) 
    }, false); 
    canvas.addEventListener("mouseout", function (e) { 
     findxy('out', e) 
    }, false); 


    ctx.drawImage(img,90, 20); //desenho a img no começo 


} 

function color(obj) { 


    var cor_sombra_selecionado = $('input[name=sombra]:checked').val(); 
    if ((cor_sombra_selecionado == '') || (cor_sombra_selecionado =='nenhuma')){ 
     ctx.shadowColor = obj.id; 
    } else { 
     ctx.shadowColor = cor_sombra_selecionado; 
    } 


    switch (obj.id) { 
     case "green": 
      x = "green"; 
      break; 
     case "blue": 
      x = "blue"; 
      break; 
     case "red": 
      x = "red"; 
      break; 
     case "yellow": 
      x = "yellow"; 
      break; 
     case "orange": 
      x = "orange"; 
      break; 
     case "black": 
      x = "black"; 
      break; 
     case "white": 
      x = "white"; 
      break; 
    } 
    if (x == "white") y = 10; 
    else y = 10; 

} 

function sombra_funcao(cor) { 

    var cor_sombra_selecionado = $('input[name=sombra]:checked').val(); 
    console.log(cor_sombra_selecionado + ' cliquei na cor da sombra'); 
    if ((cor_sombra_selecionado == '') || (cor_sombra_selecionado =='nenhuma')){ 
     ctx.shadowColor = x; 
    } else { 
     ctx.shadowColor = cor_sombra_selecionado; 
    } 



} 

function draw() { 

    var cor_sombra_selecionado = $('input[type=radio]:checked').val(); 
    console.log(cor_sombra_selecionado + ' cliquei na cor'); 
    if ((cor_sombra_selecionado == '') || (cor_sombra_selecionado =='nenhuma')){ 
     ctx.shadowColor = x; 
    } else { 
     ctx.shadowColor = cor_sombra_selecionado; 
    } 


    ctx.beginPath(); 
    ctx.lineCap = "round"; 
    ctx.lineJoin = 'round'; 
    ctx.shadowBlur = 4; 


    ctx.moveTo(prevX, prevY); 
    ctx.lineTo(currX, currY); 
    ctx.strokeStyle = x; 
    ctx.lineWidth = y; 
    ctx.stroke(); 

    console.log("dsa"); 
    ctx.closePath(); 
} 

function erase() { 
    var m = confirm("Want to clear"); 
    if (m) { 
     ctx.clearRect(0, 0, w, h); 
     document.getElementById("canvasimg").style.display = "none"; 
    } 
    ctx.drawImage(img,90, 20); //desenho o bg 
} 

function save() { 

    document.getElementById("canvasimg").style.border = "2px solid"; 
    var dataURL = canvas.toDataURL(); 
    document.getElementById("canvasimg").src = dataURL; 
    document.getElementById("canvasimg").style.display = "inline"; 
} 

function findxy(res, e) { 
    if (res == 'down') { 
     prevX = currX; 
     prevY = currY; 
     currX = e.clientX - canvas.offsetLeft; 
     currY = e.clientY - canvas.offsetTop; 

     flag = true; 
     dot_flag = true; 
     if (dot_flag) { 
      ctx.strokeStyle = x; 

      ctx.beginPath(); 
      ctx.fillStyle = x; 
      //ctx.fillRect(currX, currY, 10, 10,10,10); 
      ctx.arc(currX, currY,4,0,2*Math.PI); 
      //ctx.arc(currX, currY,2,2,2,2*Math.PI); 
      ctx.lineCap = "round"; 
      ctx.lineJoin = 'round'; 
      //ctx.stroke(); 
      dot_flag = false; 
     } 
    } 
    if (res == 'up' || res == "out") { 
     flag = false; 
    } 
    if (res == 'move') { 
     if (flag) { 
      prevX = currX; 
      prevY = currY; 
      currX = e.clientX - canvas.offsetLeft; 
      currY = e.clientY - canvas.offsetTop; 
      draw(); 
     } 
    } 
} 

/*$(document).ready(function() { 

(function($) { 
    var tool; 


    var history = { 
    redo_list: [], 
    undo_list: [], 
    saveState: function(canvas, list, keep_redo) { 
     keep_redo = keep_redo || false; 
     if(!keep_redo) { 
     this.redo_list = []; 
     } 

     (list || this.undo_list).push(canvas.toDataURL()); 
    }, 
    undo: function(canvas, ctx) { 
     this.restoreState(canvas, ctx, this.undo_list, this.redo_list); 
    }, 
    redo: function(canvas, ctx) { 
     this.restoreState(canvas, ctx, this.redo_list, this.undo_list); 
    }, 
    restoreState: function(canvas, ctx, pop, push) { 
     if(pop.length) { 
     this.saveState(canvas, push, true); 
     var restore_state = pop.pop(); 
     var img = new Element('img', {'src':restore_state}); 
     img.onload = function() { 
      ctx.clearRect(0, 0, 600, 400); 
      ctx.drawImage(img, 0, 0, 600, 400, 0, 0, 600, 400); 
     } 
     } 
    } 
    }; 


    }); 


    $("#undo").click(function() { 
    console.log("das"); 
     history.undo(canvas, ctx); 
    }); 








}); //ready */ 



</script> 

</head> 

<body onload="init()"> 

<div class="container"> 

    <div class="row"> 
    <div class="col-md-12"><h3>Desenhar</h3></div> 
    </div> 

    <div class="row"> 

    </div> 

    <div class="row"> 



     <canvas id="can" class='teste' width="500" height="400" style="border:2px solid;float:right"></canvas> 

     <div class="col-md-6"> 
      <div class="col-md-12"> 
       <h3>Cores</h3> 
       <div class="col-md-2"> <label style="background:green;"><input type='radio' name='cor' id='green' onclick="color(this)">Verde</label> </div> 
       <div class="col-md-2"> <label style="background:blue;"><input type='radio' name='cor' id='blue' onclick="color(this)">Azul</label> </div> 
       <div class="col-md-2"> <label style="background:red;"><input type='radio' name='cor' id='red' onclick="color(this)">Vermelho</label> </div> 
       <div class="col-md-2"> <label style="background:yellow;"><input type='radio' name='cor' id='yellow' onclick="color(this)">Amarelo</label> </div> 
       <div class="col-md-2"> <label style="background:orange;"><input type='radio' name='cor' id='orange' onclick="color(this)">Laranja</label> </div> 
       <div class="col-md-2"> <label style="background:white;"><input type='radio' name='cor' id='white' onclick="color(this)">Branco</label> </div> 
      </div> 
     </div> 

     <div class="col-md-6"> 
      <div class="col-md-12"> 
       <h3>Sombras</h3> 
       <div class="col-md-2"> <label style="background:green;"><input type='radio' name='sombra' value='green' onclick="sombra_funcao('green')">Verde</label> </div> 
       <div class="col-md-2"> <label style="background:blue;"><input type='radio' name='sombra' value='blue' onclick="sombra_funcao('blue')">Azul</label> </div> 
       <div class="col-md-2"> <label style="background:red;"><input type='radio' name='sombra' value='red' onclick="sombra_funcao('red')">Vermelho</label> </div> 
       <div class="col-md-2"> <label style="background:yellow;"><input type='radio' name='sombra' value='yellow' onclick="sombra_funcao('yellow')">Amarelo</label> </div> 
       <div class="col-md-2"> <label style="background:orange;"><input type='radio' name='sombra' value='orange' onclick="sombra_funcao('orange')">Laranja</label> </div> 
       <div class="col-md-2"> <label style="background:white;"><input type='radio' name='sombra' value='nenhuma' onclick="sombra_funcao('nenhuma')" checked>Nenhuma</label> </div> 
      </div> 
     </div> 

    </div> 


    <div class="row"> 
     <div class="col-md-6"> 
      <img id="canvasimg" style="position:relative;float:left;border:1px solid #000" style="display:none;"> 
      <input type="button" value="save" id="btn" size="30" onclick="save()" style=""> 
      <input type="button" value="clear" id="clr" size="23" onclick="erase()" style=""> 
      <span class="controller" id="undo">desfazer </span> 
      <span class="controller" id="redo">redo</span> 
     </div> 


    </div> 

</div> 

</body> 
</html> 

ответ

2

перерисовать контур сверху, когда краски пользователя добавленный цвет

Это, вероятно, самый простой способ всегда иметь оригинальный контур над окрашенным полотном. Если у вас цветной фон вне исходного изображения, то перерисовка исходного изображения устраняет любую окраску вне контура.

Интересная альтернатива: использование Compositing окрашивать за оригинальный контур

Если вы хотите, чтобы ваши новые расцветки всегда быть позади исходного контура, вы можете установить context.globalCompositeOperation='destination-over' и тогда все ваши новые расцветки всегда будет обращено за существующим планом.

Примечание. Этот метод работает только при раскрашивании новых пикселей, где новый пиксель не перекрывает никакого существующего цветного пикселя.

Таким образом, чтобы использовать эту технику, вы должны сделать эти изменения на контурное изображении:

  • Используйте схему, которая уже не залитый цветом. Хорошая работа Уильяма Мэлоуна использует утку, которая уже заполнена белым. Вам придется удалить этот белый цвет.

  • Заполните фон вне контура с цветом (не прозрачный)

I включают модифицированный образ утки набросков Уильяма Мэлоуна, который правильно настроен для использования композитинга всегда «рисовать в пределах линий» , Хотя вы не можете увидеть его с изображением на белом фоне ...

  • фона за пределами изображения белого цвета

  • и интерьер утка прозрачен.

enter image description here

Вот шарлатан пример, я имею в виду быстрый пример (каламбур!):

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
function reOffset(){ 
 
    var BB=canvas.getBoundingClientRect(); 
 
    offsetX=BB.left; 
 
    offsetY=BB.top;   
 
} 
 
var offsetX,offsetY; 
 
reOffset(); 
 
window.onscroll=function(e){ reOffset(); } 
 

 
var isDown=false; 
 
var startX,startY; 
 

 
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/duck.png"; 
 
function start(){ 
 

 
    cw=canvas.width=img.width; 
 
    ch=canvas.height=img.height; 
 

 
    ctx.fillStyle='gold'; 
 

 
    ctx.drawImage(img,0,0); 
 

 
    ctx.globalCompositeOperation='destination-over'; 
 

 
    $("#canvas").mousedown(function(e){handleMouseDown(e);}); 
 
    $("#canvas").mousemove(function(e){handleMouseMove(e);}); 
 
    $("#canvas").mouseup(function(e){handleMouseUp(e);}); 
 
    $("#canvas").mouseout(function(e){handleMouseOut(e);}); 
 

 

 
} 
 

 

 

 
function handleMouseDown(e){ 
 
    // tell the browser we're handling this event 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    // Put your mousedown stuff here 
 
    isDown=true; 
 
} 
 

 
function handleMouseUp(e){ 
 
    // tell the browser we're handling this event 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    // Put your mouseup stuff here 
 
    isDown=false; 
 
} 
 

 
function handleMouseOut(e){ 
 
    // tell the browser we're handling this event 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    // Put your mouseOut stuff here 
 
    isDown=false; 
 
} 
 

 
function handleMouseMove(e){ 
 
    if(!isDown){return;} 
 
    // tell the browser we're handling this event 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    mouseX=parseInt(e.clientX-offsetX); 
 
    mouseY=parseInt(e.clientY-offsetY); 
 

 
    ctx.beginPath(); 
 
    ctx.arc(mouseX,mouseY,10,0,Math.PI*2); 
 
    ctx.closePath(); 
 
    ctx.fill(); 
 

 
}
body{ background-color: ivory; } 
 
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
<canvas id="canvas" width=300 height=300></canvas>

+0

Важны, и мы надеюсь, конструктивные, обратите внимание, с помощью назначения-над - позволяет сказать, вы рисуете с синим, но хочет использовать зеленый цвет на вершине синий (все еще за черным контуром). Теперь зеленый цвет будет окрашен * позади * синим, а не сверху (не то, что зеленая утка лучше голубой). Конечно, для отдельных цветов не проблема (как в живом примере), а что-то, что нужно иметь в виду для нескольких параметров цвета (также см. Дубликат указателя для решения этого). – K3N

+0

Да, несколько цветов (и случайные розыгрыши, охватывающие 2+ выделенные области) - проблема, которая должна быть решена. ;-) Возможно, оригинальное решение Уильяма Мэлоуна, использующее наводнение, является выигрышным решением. : -/ – markE

+0

Наводнение прекрасно работает, но отвлекает удовольствие от этих рисунков (imo). : ^) – K3N

2

Очень другое решение приходит на ум теперь, когда холст пришел на сцену два: более режимов наложения, что упрощает весь процесс:

  • Нарисовать изображение , убедитесь, что фон белый, линии черные («да», возможно, но важны)
  • Изменить режим композитного (смешивания) на multiply - примечание: в IE не работает (Вкл. v.11).
  • Нарисуйте свое сердце на вершине его; создавать мастер-части, такие как это:

Weee
(эм ... рейв-утка!)

Этот режим также будет действовать больше как реальная бумага и маркеры, то есть. субтрактивный свет при смешивании цветов вместе.

Здесь вам не нужно беспокоиться о альфа-канале/прозрачности, так как он использует только смешивание режим (без композиции, но с обычным истоком, имеет место).

Вы можете дополнительно регулировать соотношение смешивания пути регулирования глобального альфа (примечание также, что вы получите те перекрытий на места соединений - не охваченные в этом ответе, но one possible solution here (overlap), и для recording points here).

ctx.globalAlpha = 0.75; // example, set/adjust before drawing 

Demo

var img = new Image; 
 
img.onload = setup; 
 
img.src = "http://i.stack.imgur.com/xL8it.png"; 
 

 
function setup() { 
 
    var canvas = document.querySelector("canvas"), 
 
     ctx = canvas.getContext("2d"), 
 
     lastPos, isDown = false; 
 

 
    ctx.drawImage(this, 0, 0, canvas.width, canvas.height); // draw duck   
 
    ctx.lineCap = "round";         // make lines prettier 
 
    ctx.lineWidth = 16; 
 
    ctx.globalCompositeOperation = "multiply";    // KEY MODE HERE 
 
    
 
    canvas.onmousedown = function(e) { 
 
     isDown = true; 
 
     lastPos = getPos(e); 
 
     ctx.strokeStyle = "hsl(" + (Math.random() * 360) + ", 100%, 85%)"; 
 
    }; 
 
    window.onmousemove = function(e) { 
 
     if (!isDown) return; 
 
     var pos = getPos(e); 
 
     ctx.beginPath(); 
 
     ctx.moveTo(lastPos.x, lastPos.y); 
 
     ctx.lineTo(pos.x, pos.y); 
 
     ctx.stroke(); 
 
     lastPos = pos; 
 
    }; 
 
    window.onmouseup = function(e) {isDown = false}; 
 
    
 
    function getPos(e) { 
 
     var rect = canvas.getBoundingClientRect(); 
 
     return {x: e.clientX - rect.left, y: e.clientY - rect.top} 
 
    } 
 
}
canvas{border:1px solid #000;cursor:crosshair}
<canvas width=400 height=400></canvas>

+0

работает отлично для одного цвета, но когда я пытаюсь использовать несколько цветов, новый цвет отображается за старым, любое решение для этой проблемы? Из-за этого мой ластик не работает, спасибо :) –

Смежные вопросы