使用canvas進(jìn)行圖像編輯的實(shí)例
前面的話
本文將分為幾個(gè)小功能的形式來(lái)詳細(xì)介紹canvas圖像編輯
縮放
下面是一張分析圖,假設(shè)默認(rèn)情況下,圖片和canvas寬高相同。圖片的縮放(scale)范圍為0.5到3,縮放時(shí)改變的是圖片的大小和圖片的坐標(biāo)位置
W(寬) = canvas.width * scale H(高) = canvas.height * scale x坐標(biāo) = (W - canvas.width)/2; y坐標(biāo) = (H - canvas.height)/2;

因此,代碼如下
<canvas id="drawing" >
<p>The canvas element is not supported!</p>
</canvas>
<br>
<input id="scale-range" min="0.5" max="1.5" step="0.01" type="range" >
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
var context = drawing.getContext('2d');
var slider = document.getElementById('scale-range');
var W = 400;
var H = 290;
drawing.width = W;
drawing.height = H;
var image = new Image();
image.src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg";
image.onload = function(){
drawImgByScale(slider.value);
slider.onmousemove = function(){
drawImgByScale(slider.value);
}
}
function drawImgByScale(scale){
var imgW = W * scale;
var imgH = H * scale;
var dx =(W - imgW)/2;
var dy =(H - imgH)/2;
context.clearRect(0,0,W,H);
context.drawImage(image,dx,dy,imgW,imgH);
}
}
</script>
水印
利用canvas可以實(shí)現(xiàn)向圖片添加水印的功能,先通過(guò)file控件的reader選擇圖片,然后使用canvas添加圖片及水印,并且使用toDataURL()和a標(biāo)簽實(shí)現(xiàn)添加水印后的圖片的下載功能
<canvas id="drawing" >
<p>The canvas element is not supported!</p>
</canvas>
<div>
<span>
<input type="file" id="addImgHelper" >
<button id="addImg">選擇圖片</button>
</span>
<span>
<button id="addWaterMark" disabled>添加水印</button>
<span>水印文字為</span>
<input id="waterMarkWords" type="text" value="小火柴的藍(lán)色理想">
</span>
<span>
<button id="downloadImg" disabled>下載圖片</button>
<a id="downloadImgHelper" href="#" rel="external nofollow" download="帶水印圖片" ></a>
</span>
</div>
<script>
if(drawing.getContext){
var cxt = drawing.getContext('2d');
var W,H;
addImg.onclick = function(){
addImgHelper.click();
}
addImgHelper.onchange = function(){
addWaterMark.disabled = true;
downloadImg.disabled = true;
var file = addImgHelper.files[0];
if(file && /image/.test(file.type)){
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
var img = new Image();
img.src= reader.result;
img.onload = function(){
addWaterMark.disabled = false;
drawing.width = W = img.width;
drawing.height = H = img.height;
cxt.drawImage(img,0,0);
addWaterMark.onclick = function(){
downloadImg.disabled = false;
cxt.clearRect(0,0,W,H);
cxt.drawImage(img,0,0);
var str = waterMarkWords.value;
cxt.font = "bold 50px Arial";
cxt.lineWidth = '1';
cxt.fillStyle = 'rgba(255,255,255,0.5)';
cxt.textBaseline = "bottom";
cxt.textAlign = 'end';
cxt.fillText(str,W-10,H-10,W/2);
downloadImg.onclick = function(){
downloadImgHelper.href = drawing.toDataURL('image/png');
downloadImgHelper.click();
}
}
}
}
}
}
}
</script>
放大鏡
下面來(lái)實(shí)現(xiàn)一個(gè)放大鏡的效果,鼠標(biāo)按下并移動(dòng)時(shí),顯示當(dāng)前圖片區(qū)域的放大效果,抬起后效果消失。放大鏡效果主要使用離屏canvas的技術(shù),離屏canvas放置的是圖片的放大版,而普通canvas則放置圖片的正常版
<canvas id="drawing" >
<p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawingOff" >
<p>The canvas element is not supported!</p>
</canvas>
<script>
if(drawing.getContext){
var cxt = drawing.getContext('2d');
var cxtOff = drawingOff.getContext('2d');
var W,H;
var scale = 1.5;
var img = new Image();
img.src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg";
img.onload = function(){
W = img.width;
H = img.height;
drawing.width = W/scale;
drawing.height = H/scale;
drawingOff.width = W;
drawingOff.height = H;
cxt.drawImage(img,0,0,W/scale,H/scale);
cxtOff.drawImage(img,0,0);
drawing.onmousedown = function(e){
e = e || event;
var x0 = this.offsetLeft;
var y0 = this.offsetTop;
drawMagnifier(e);
drawing.onmousemove = function(e){
drawMagnifier(e);
}
document.onmouseup = function(e){
cxt.clearRect(0,0,W/scale,H/scale);
cxt.drawImage(img,0,0,W/scale,H/scale);
drawing.onmousemove = null;
}
function drawMagnifier(e){
cxt.clearRect(0,0,W/scale,H/scale);
cxt.drawImage(img,0,0,W/scale,H/scale);
var x = (e.clientX-x0);
var y = (e.clientY-y0);
var r = 40;
var dx = x - r;
var dy = y - r;
var sx = x*scale - r;
var sy = y*scale - r;
cxt.save();
cxt.beginPath();
cxt.arc(x,y,r,0,Math.PI*2);
cxt.lineWidth = 4;
cxt.strokeStyle = '#069';
cxt.stroke();
cxt.clip();
cxt.drawImage(drawingOff,sx,sy,2*r,2*r,dx,dy,2*r,2*r);
cxt.restore();
}
}
}
}
</script>
濾鏡
下面利用canvas的getImageData()方法,獲取原始圖像數(shù)據(jù),通過(guò)對(duì)圖像數(shù)據(jù)進(jìn)行修改,然后輸出修改后的圖像數(shù)據(jù)
<canvas id="drawing1" >
<p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawing2" >
<p>The canvas element is not supported!</p>
</canvas>
<br>
<button id="noGreen">無(wú)綠色</button>
<button id="noBlue">無(wú)藍(lán)色</button>
<button id="toGrey">灰度</button>
<button id="toBlackWhite">黑白</button>
<button id="reverse">反色</button>
<script>
if(drawing1.getContext){
var cxt1 = drawing1.getContext('2d');
var cxt2 = drawing2.getContext('2d');
var img = new Image();
img.src="chunfen.jpg";
img.onload = function(){
cxt1.drawImage(img,0,0);
function filter(fn){
var imageData = cxt1.getImageData(0,0,img.width,img.height);
cxt2.clearRect(0,0,drawing2.width,drawing2.height);
var data = imageData.data;
for(var i = 0, len = data.length; i < len; i+=4){
fn(data,i)
}
imageData.data = data;
cxt2.putImageData(imageData,0,0);
}
function fnNoGreen(data,i){
data[i+1] = 0;
}
function fnNoBlue(data,i){
data[i+2] = 0;
}
function fnReverse(data,i){
var red = data[i];
var green = data[i+1];
var blue = data[i+2];
var alpha = data[i+3];
data[i] = 255 - red;
data[i+1] = 255 - green;
data[i+2] = 255 - blue;
}
function fnToGrey(data,i){
var red = data[i];
var green = data[i+1];
var blue = data[i+2];
var alpha = data[i+3];
var average = Math.floor((red+green+blue)/3);
data[i] = data[i+1] = data[i+2] = average;
}
function fnToBlackWhite(data,i){
var red = data[i];
var green = data[i+1];
var blue = data[i+2];
var alpha = data[i+3];
var average = Math.floor((red+green+blue)/3);
if(average > 255/2){
var result = 255;
}else{
var result = 0;
}
data[i] = data[i+1] = data[i+2] = result;
}
toGrey.onclick = function(){
filter(fnToGrey);
}
noGreen.onclick = function(){
filter(fnNoGreen);
}
noBlue.onclick = function(){
filter(fnNoBlue);
}
toBlackWhite.onclick = function(){
filter(fnToBlackWhite);
}
reverse.onclick = function(){
filter(fnReverse);
}
}
}
</script>
馬賽克效果
【普通模糊效果】
普通模糊效果不僅需要使用當(dāng)前像素點(diǎn),還需要使用周?chē)南袼攸c(diǎn),并把這些像素點(diǎn)都賦予平均值
function fnToBlur(n){
cxt2.clearRect(0,0,drawing2.width,drawing2.height);
var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height);
var tempImageData = imageData;
var data = imageData.data;
var tempData = tempImageData.data;
var blurR = n;
var totalnum = (2*blurR + 1)*(2*blurR + 1);
for(var i = blurR; i < drawing2.height - blurR; i++){
for(var j = blurR; j < drawing2.width - blurR; j++){
var totalr = 0, totalg = 0, totalb = 0;
for(var dx = -blurR; dx <= blurR; dx++){
for(var dy = -blurR; dy <= blurR; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
totalr += tempData[p*4+0];
totalg += tempData[p*4+1];
totalb += tempData[p*4+2];
}
}
var p = i*drawing2.width + j;
data[p*4+0] = totalr / totalnum;
data[p*4+1] = totalg / totalnum;
data[p*4+2] = totalb / totalnum;
}
}
imageData.data = data;
cxt2.putImageData(imageData,0,0);
}
【馬賽克效果】
馬賽克效果則是把一塊區(qū)域的值,全部都賦予平均值
function fnToMosaic(n){
cxt2.clearRect(0,0,drawing2.width,drawing2.height);
var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height);
var tempImageData = imageData;
var data = imageData.data;
var tempData = tempImageData.data;
var size = n;
var totalnum = size*size;
for(var i = 0; i < drawing2.height; i+=size){
for(var j = 0; j < drawing2.width; j+=size){
var totalr = 0, totalg = 0, totalb = 0;
for(var dx = 0; dx < size; dx++){
for(var dy = 0; dy < size; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
totalr += tempData[p*4+0];
totalg += tempData[p*4+1];
totalb += tempData[p*4+2];
}
}
var p = i*drawing2.width + j;
var resr = totalr / totalnum;
var resg = totalg / totalnum;
var resb = totalb / totalnum;
for(var dx = 0; dx < size; dx++){
for(var dy = 0; dy < size; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
data[p*4+0]= resr;
data[p*4+1]= resg;
data[p*4+2]= resb;
}
}
}
}
imageData.data = data;
cxt2.putImageData(imageData,0,0);
}
下面是一個(gè)實(shí)例
<canvas id="drawing1" >
<p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawing2" >
<p>The canvas element is not supported!</p>
</canvas>
<br>
<button id="toLightBlur">輕度模糊</button>
<button id="toHeavyBlur">重度模糊</button>
<button id="toLightMosaic">輕度馬賽克</button>
<button id="toHeavyMosaic">重度馬賽克</button>
<script>
if(drawing1.getContext){
var cxt1 = drawing1.getContext('2d');
var cxt2 = drawing2.getContext('2d');
var img = new Image();
img.src="chunfen.jpg";
img.onload = function(){
cxt1.drawImage(img,0,0);
toLightBlur.onclick = function(){
fnToBlur(1);
}
toHeavyBlur.onclick = function(){
fnToBlur(3);
}
toLightMosaic.onclick = function(){
fnToMosaic(4);
}
toHeavyMosaic.onclick = function(){
fnToMosaic(9);
}
function fnToBlur(n){
cxt2.clearRect(0,0,drawing2.width,drawing2.height);
var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height);
var tempImageData = imageData;
var data = imageData.data;
var tempData = tempImageData.data;
var blurR = n;
var totalnum = (2*blurR + 1)*(2*blurR + 1);
for(var i = blurR; i < drawing2.height - blurR; i++){
for(var j = blurR; j < drawing2.width - blurR; j++){
var totalr = 0, totalg = 0, totalb = 0;
for(var dx = -blurR; dx <= blurR; dx++){
for(var dy = -blurR; dy <= blurR; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
totalr += tempData[p*4+0];
totalg += tempData[p*4+1];
totalb += tempData[p*4+2];
}
}
var p = i*drawing2.width + j;
data[p*4+0] = totalr / totalnum;
data[p*4+1] = totalg / totalnum;
data[p*4+2] = totalb / totalnum;
}
}
imageData.data = data;
cxt2.putImageData(imageData,0,0);
}
function fnToMosaic(n){
cxt2.clearRect(0,0,drawing2.width,drawing2.height);
var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height);
var tempImageData = imageData;
var data = imageData.data;
var tempData = tempImageData.data;
var size = n;
var totalnum = size*size;
for(var i = 0; i < drawing2.height; i+=size){
for(var j = 0; j < drawing2.width; j+=size){
var totalr = 0, totalg = 0, totalb = 0;
for(var dx = 0; dx < size; dx++){
for(var dy = 0; dy < size; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
totalr += tempData[p*4+0];
totalg += tempData[p*4+1];
totalb += tempData[p*4+2];
}
}
var p = i*drawing2.width + j;
var resr = totalr / totalnum;
var resg = totalg / totalnum;
var resb = totalb / totalnum;
for(var dx = 0; dx < size; dx++){
for(var dy = 0; dy < size; dy++){
var x = i + dx;
var y = j + dy;
var p = x*drawing2.width + y;
data[p*4+0]= resr;
data[p*4+1]= resg;
data[p*4+2]= resb;
}
}
}
}
imageData.data = data;
cxt2.putImageData(imageData,0,0);
}
}
}
</script>
以上這篇使用canvas進(jìn)行圖像編輯的實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
javascript實(shí)現(xiàn)的動(dòng)態(tài)文字變換
javascript實(shí)現(xiàn)的動(dòng)態(tài)文字變換...2007-07-07
淺析IE10兼容性問(wèn)題(frameset的cols屬性)
主頁(yè)用frameset嵌了兩個(gè)頁(yè)面,左側(cè)為菜單欄,可以通過(guò)改變 frameset的cols來(lái)收縮。別的瀏覽器正常,但I(xiàn)E10卻沒(méi)任何的反應(yīng)2014-01-01
JavaScript中const關(guān)鍵字的用法及特性
該文章講解了JavaScript中const關(guān)鍵字的用法以及它的一些特性,該關(guān)鍵字用于創(chuàng)建常量,即一旦賦值之后就不能再修改,但是,使用?const創(chuàng)建的對(duì)象和數(shù)組卻可以被修改,本文通過(guò)講解“賦值”和“變異”之間的重要區(qū)別,詳細(xì)解釋了這一現(xiàn)象,需要的朋友可以參考下2023-05-05
js或jquery實(shí)現(xiàn)頁(yè)面打印可局部打印
這篇文章主要介紹了js或jquery如何實(shí)現(xiàn)頁(yè)面打印也可局部打印,需要的朋友可以參考下2014-03-03
微信支付如何實(shí)現(xiàn)內(nèi)置瀏覽器的H5頁(yè)面支付
這篇文章主要介紹了微信支付如何實(shí)現(xiàn)內(nèi)置瀏覽器的H5頁(yè)面支付的相關(guān)資料,需要的朋友可以參考下2015-09-09
js判斷一個(gè)對(duì)象是否在一個(gè)對(duì)象數(shù)組中(場(chǎng)景分析)
這篇文章主要介紹了js判斷一個(gè)對(duì)象是否在一個(gè)對(duì)象數(shù)組中,本文通過(guò)場(chǎng)景分析給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-08-08

