åç´ æä½
å°ç®å为æ¢ï¼æä»¬å°æªæ·±å ¥äºè§£ Canvas ç»å¸çå®åç´ çåçï¼äºå®ä¸ï¼ä½ å¯ä»¥ç´æ¥éè¿ ImageData 对象æçºµåç´ æ°æ®ï¼ç´æ¥è¯»åæå°æ°æ®æ°ç»åå ¥è¯¥å¯¹è±¡ä¸ãç¨åæä»¬ä¹å°æ·±å ¥äºè§£å¦ä½æ§å¶å¾åä½¿å ¶å¹³æ»ï¼åé¯é½¿ï¼ä»¥åå¦ä½ä» Canvas ç»å¸ä¸ä¿åå¾åã
ImageData 对象
ImageData对象ä¸åå¨ç canvas 对象çå®çåç´ æ°æ®ï¼å®å
å«ä»¥ä¸å 个åªè¯»å±æ§ï¼
width-
å¾ç宽度ï¼å使¯åç´
height-
å¾çé«åº¦ï¼å使¯åç´
data-
Uint8ClampedArrayç±»åçä¸ç»´æ°ç»ï¼å å«ç RGBA æ ¼å¼çæ´åæ°æ®ï¼èå´å¨ 0 è³ 255 ä¹é´ï¼å æ¬ 255ï¼ã
data 屿§è¿åä¸ä¸ª Uint8ClampedArrayï¼å®å¯ä»¥è¢«ä½¿ç¨ä½ä¸ºæ¥çåå§åç´ æ°æ®ãæ¯ä¸ªåç´ ç¨ 4 个 1bytes å¼ (æç
§çº¢ï¼ç»¿ï¼èåéæå¼ç顺åº; è¿å°±æ¯"RGBA"æ ¼å¼) æ¥ä»£è¡¨ãæ¯ä¸ªé¢è²å¼é¨ä»½ç¨ 0 è³ 255 æ¥ä»£è¡¨ãæ¯ä¸ªé¨ä»½è¢«åé
å°ä¸ä¸ªå¨æ°ç»å
è¿ç»çç´¢å¼ï¼å·¦ä¸è§åç´ ç红è²é¨ä»½å¨æ°ç»çç´¢å¼ 0 ä½ç½®ãåç´ ä»å·¦å°å³è¢«å¤çï¼ç¶åå¾ä¸ï¼éåæ´ä¸ªæ°ç»ã
Uint8ClampedArray å
å« height à width à 4 åèæ°æ®ï¼ç´¢å¼å¼ä» 0 å° (heightà width à 4)-1
ä¾å¦ï¼è¦è¯»åå¾çä¸ä½äºç¬¬ 50 è¡ï¼ç¬¬ 200 åçåç´ çèè²é¨ä»½ï¼ä½ ä¼å以ä¸ä»£ç ï¼
const blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2];
æ ¹æ®è¡ãå读åæåç´ ç¹ç R/G/B/A å¼çå ¬å¼ï¼
imageData.data[50 * (imageData.width * 4) + 200 * 4 + 0 / 1 / 2 / 3];
ä½ å¯è½ç¨ä¼ä½¿ç¨ Uint8ClampedArray.length 屿§æ¥è¯»ååç´ æ°ç»ç大å°ï¼ä»¥åè为åä½ï¼ï¼
var numBytes = imageData.data.length;
å建ä¸ä¸ª ImageData 对象
å»å建ä¸ä¸ªæ°çï¼ç©ºç½ç ImageData 对象ï¼ä½ åºè¯¥ä¼ä½¿ç¨createImageData() æ¹æ³ãæ 2 ä¸ªçæ¬ç createImageData() æ¹æ³ã
var myImageData = ctx.createImageData(width, height);
ä¸é¢ä»£ç å建äºä¸ä¸ªæ°çå
·ä½ç¹å®å°ºå¯¸ç ImageData å¯¹è±¡ãææåç´ è¢«é¢è®¾ä¸ºéæé»ã
ä½ ä¹å¯ä»¥å建ä¸ä¸ªè¢« anotherImageData 对象æå®çç¸ååç´ ç ImageData 对象ãè¿ä¸ªæ°ç对象åç´ å
¨é¨è¢«é¢è®¾ä¸ºéæé»ãè¿ä¸ªå¹¶éå¤å¶äºå¾çæ°æ®ã
var myImageData = ctx.createImageData(anotherImageData);
å¾å°åºæ¯åç´ æ°æ®
为äºè·å¾ä¸ä¸ªå
å«ç»å¸åºæ¯åç´ æ°æ®ç ImageData 对象ï¼ä½ å¯ä»¥ç¨ getImageData() æ¹æ³ï¼
var myImageData = ctx.getImageData(left, top, width, height);
è¿ä¸ªæ¹æ³ä¼è¿åä¸ä¸ª ImageData 对象ï¼å®ä»£è¡¨äºç»å¸åºåçå¯¹è±¡æ°æ®ï¼æ¤ç»å¸çå个è§è½åå«è¡¨ç¤ºä¸º (left, top), (left + width, top), (left, top + height), 以å (left + width, top + height) å个ç¹ãè¿äºåæ ç¹è¢«è®¾å®ä¸ºç»å¸åæ 空é´å
ç´ ã
夿³¨ï¼ä»»ä½å¨ç»å¸ä»¥å¤çå
ç´ é½ä¼è¢«è¿åæä¸ä¸ªéæé»ç ImageData 对象ã
è¿ä¸ªæ¹æ³ä¹ä¼å¨æç« ç¨ç»å¸æä½è§é¢ä¸å±ç¤ºã
é¢è²éæ©å¨
å¨è¿ä¸ªä¾åéé¢ï¼æä»¬ä¼ä½¿ç¨ getImageData() å»å±ç¤ºé¼ æ å
æ ä¸çé¢è²ã为æ¤ï¼æä»¬è¦å½åé¼ æ çä½ç½®ï¼è®°ä¸º layerX å layerYï¼ç¶åæä»¬å»æ¥è¯¢ getImageData() ç»æä»¬æä¾çå¨é£ä¸ªä½ç½®çåæ°æ°ç»éé¢çåç´ æ°æ®ãæåæä»¬ä½¿ç¨æ°ç»æ°æ®å»è®¾ç½®èæ¯é¢è²å <div> çæåå»å±ç¤ºé¢è²å¼ã
var img = new Image();
img.crossOrigin = "anonymous";
img.src = "./assets/rhino.jpg";
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
img.onload = function () {
ctx.drawImage(img, 0, 0);
img.style.display = "none";
};
var hoveredColor = document.getElementById("hovered-color");
var selectedColor = document.getElementById("selected-color");
function pick(event, destination) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
const rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`;
destination.style.background = rgba;
destination.textContent = rgba;
return rgba;
}
canvas.addEventListener("mousemove", function (event) {
pick(event, hoveredColor);
});
canvas.addEventListener("click", function (event) {
pick(event, selectedColor);
});
å¨åºæ¯ä¸åå ¥åç´ æ°æ®
ä½ å¯ä»¥ç¨ putImageData() æ¹æ³å»å¯¹åºæ¯è¿è¡åç´ æ°æ®çåå
¥ã
ctx.putImageData(myImageData, dx, dy);
dx å dy åæ°è¡¨ç¤ºä½ å¸æå¨åºæ¯å å·¦ä¸è§ç»å¶çåç´ æ°æ®æå¾å°ç设å¤åæ ã
ä¾å¦ï¼ä¸ºäºå¨åºæ¯å
å·¦ä¸è§ç»å¶ myImageData 代表çå¾çï¼ä½ å¯ä»¥åå¦ä¸ç代ç ï¼
ctx.putImageData(myImageData, 0, 0);
å¾çç°åº¦ååç¸é¢è²
å¨è¿ä¸ªä¾åéï¼æä»¬éåææåç´ ä»¥æ¹åä»ä»¬çæ°å¼ãç¶åæä»¬å°è¢«ä¿®æ¹çåç´ æ°ç»éè¿putImageData() æ¾åå°ç»å¸ä¸å»ãinvert 彿°ä»
ä»
æ¯å»åæé¢è²çæå¤§è²å¼ 255ãgrayscale 彿°ä»
ä»
æ¯ç¨çº¢ç»¿åèçå¹³åå¼ãä½ ä¹å¯ä»¥ç¨å æå¹³åï¼ä¾å¦ x = 0.299r + 0.587g + 0.114b è¿ä¸ªå
¬å¼ãæ´å¤èµæè¯·åèç»´åºç¾ç§çGrayscaleã
var img = new Image();
img.crossOrigin = "anonymous";
img.src = "./assets/rhino.jpg";
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
var original = function () {
ctx.drawImage(img, 0, 0);
};
var invert = function () {
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // red
data[i + 1] = 255 - data[i + 1]; // green
data[i + 2] = 255 - data[i + 2]; // blue
}
ctx.putImageData(imageData, 0, 0);
};
var grayscale = function () {
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
const inputs = document.querySelectorAll("[name=color]");
for (const input of inputs) {
input.addEventListener("change", function (evt) {
switch (evt.target.value) {
case "inverted":
return invert();
case "grayscale":
return grayscale();
default:
return original();
}
});
}
缩æ¾ååé¯é½¿
å¨drawImage() æ¹æ³ï¼ç¬¬äºä¸ªç»å¸åimageSmoothingEnabled 屿§ç帮å©ä¸ï¼æä»¬å¯ä»¥æ¾å¤§æ¾ç¤ºæä»¬çå¾çåçå°è¯¦æ
å
容ã
æä»¬å¾å°é¼ æ çä½ç½®å¹¶è£åªåºè·å·¦åä¸ 5 åç´ ï¼è·å³åä¸ 5 åç´ çå¾çãç¶åæä»¬å°è¿å¹ å¾å¤å¶å°å¦ä¸ä¸ªç»å¸ç¶åå°å¾çè°æ´å°æä»¬æ³è¦ç大å°ãå¨ç¼©æ¾ç»å¸éï¼æä»¬å° 10Ã10 åç´ ç对åç»å¸çè£åªè°æ´ä¸º 200Ã200ã
zoomctx.drawImage(
canvas,
Math.abs(x - 5),
Math.abs(y - 5),
10,
10,
0,
0,
200,
200,
);
å 为åé¯é½¿é»è®¤æ¯å¯ç¨çï¼æä»¬å¯è½æ³è¦å
³éå®ä»¥çå°æ¸
æ¥çåç´ ãä½ å¯ä»¥éè¿åæ¢å¾éæ¡æ¥çå° imageSmoothingEnabled 屿§çææï¼ä¸åæµè§å¨éè¦ä¸ååç¼ï¼ã
缩æ¾ç¤ºä¾
<canvas id="canvas" width="300" height="227"></canvas>
<canvas id="zoom" width="300" height="227"></canvas>
<div>
<label for="smoothbtn">
<input type="checkbox" name="smoothbtn" checked="checked" id="smoothbtn" />
Enable image smoothing
</label>
</div>
var img = new Image();
img.src = "rhino.jpg";
img.onload = function () {
draw(this);
};
function draw(img) {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
img.style.display = "none";
var zoomctx = document.getElementById("zoom").getContext("2d");
var smoothbtn = document.getElementById("smoothbtn");
var toggleSmoothing = function (event) {
zoomctx.imageSmoothingEnabled = this.checked;
zoomctx.mozImageSmoothingEnabled = this.checked;
zoomctx.webkitImageSmoothingEnabled = this.checked;
zoomctx.msImageSmoothingEnabled = this.checked;
};
smoothbtn.addEventListener("change", toggleSmoothing);
var zoom = function (event) {
var x = event.layerX;
var y = event.layerY;
zoomctx.drawImage(
canvas,
Math.abs(x - 5),
Math.abs(y - 5),
10,
10,
0,
0,
200,
200,
);
};
canvas.addEventListener("mousemove", zoom);
}
ä¿åå¾ç
HTMLCanvasElement æä¾ä¸ä¸ª toDataURL() æ¹æ³ï¼æ¤æ¹æ³å¨ä¿åå¾ççæ¶åé常æç¨ãå®è¿åä¸ä¸ªå
å«è¢«ç±»ååæ°è§å®çå¾åè¡¨ç°æ ¼å¼çæ°æ®é¾æ¥ãè¿åçå¾çåè¾¨çæ¯ 96 dpiã
canvas.toDataURL('image/png')-
é»è®¤è®¾å®ãå建ä¸ä¸ª PNG å¾çã
canvas.toDataURL('image/jpeg', quality)-
å建ä¸ä¸ª JPG å¾çãä½ å¯ä»¥æéæ©å°æä¾ä» 0 å° 1 çåè´¨éï¼1 表示æå¥½åè´¨ï¼0 åºæ¬ä¸è¢«è¾¨æä½ææ¯è¾å°çæä»¶å¤§å°ã
å½ä½ ä»ç»å¸ä¸çæäºä¸ä¸ªæ°æ®é¾æ¥ï¼ä¾å¦ï¼ä½ å¯ä»¥å°å®ç¨äºä»»ä½ <image> å
ç´ ï¼æè
å°å®æ¾å¨ä¸ä¸ªæ download 屿§çè¶
龿¥éç¨äºä¿åå°æ¬å°ã
ä½ ä¹å¯ä»¥ä»ç»å¸å建ä¸ä¸ª Blob 对象ã
canvas.toBlob(callback, type, encoderOptions)-
è¿ä¸ªå建äºä¸ä¸ªå¨ç»å¸ä¸ç代表å¾çç
Blob对象ã