以灰度保存 canvas
Save canvas in grayscale
我想知道是否可以在 HTML5 中添加彩色 canvas,然后在单击保存按钮时将其另存为黑白(灰度)PNG。我已经设法将 canvas 保存为 PNG,太棒了!但我想添加灰度功能,而不必自己用 Illustrator 等程序更改它。
canvas 有移动的粒子顺便说一下。 (虽然我不确定这是否有任何影响)
谢谢~!
function download(){
var dt = c.toDataURL('image/png');
this.href = dt;
};
downloadlink.addEventListener('click', download, false);
可以通过从 canvas 中提取 RGB 数据并计算它们的亮度值来实现。
不过有几个先决条件需要满足,例如 CORS(在这种情况下这似乎不是问题,因为您已经可以保存图像)以及是否希望保留原始数据保存后,您可以将 canvas 上的当前图像复制到临时图像,或者保留需要提取的像素数据的备份。
RGB 转亮度
根据REC 709(或BT.709)公式将RGB数据转换成亮度值(灰度)的公式如下:
luma = Red x 0.2126 + Green x 0.7152 + Blue x 0.0722
或者您可以使用 REC 601 (BT.601) 公式(这在标清视频素材中更常见):
luma = Red x 0.299 + Green x 0.587 + Blue x 0.114
要使用它,只需遍历所有像素,使用这些公式之一获取亮度值,并将目标中的所有通道替换为生成的亮度值。
临时数据
对于临时数据,我们可以执行以下任一操作(单击保存按钮时):
临时canvas
- 创建临时 canvas
- 设置大小等于来源canvas
- 使用
drawImage()
在源 canvas 中绘制
- 使用
getImageData()
提取目标canvas'像素数据
- 迭代像素,使用公式转换,放回数据
- 保存图像然后丢弃临时图像canvas
或
图像数据备份
- 使用
getImageData()
提取图像数据 - 这将作为我们的备份
- 使用
createImageData()
创建相同大小的新 ImageData
- 迭代备份中的像素,但将结果以亮度形式放入创建的
ImageData
- 放回创建的
ImageData
,保存图片
- 放回备份数据
是否需要后一步实际上取决于您如何更新 canvas。如果您正在制作循环动画,则可能不需要放回备份(或保留一个),如果一切都得到更新,但如果是这样并且您看到灰色闪光或某些区域留下灰色,则需要此步骤。
使用 ImageData
方法的示例
var ctx = c.getContext("2d"), img = new Image;
img.onload = setup; img.crossOrigin = "";
img.src = "//i.imgur.com/OrYVGI8.jpg";
function setup() {
c.width = this.naturalWidth; c.height = this.naturalHeight;
ctx.drawImage(this, 0, 0); btn.disabled = false
}
// Main code for demo
btn.onclick = function() {
var idataSrc = ctx.getImageData(0, 0, c.width, c.height), // original
idataTrg = ctx.createImageData(c.width, c.height), // empty data
dataSrc = idataSrc.data, // reference the data itself
dataTrg = idataTrg.data,
len = dataSrc.length, i = 0, luma;
// convert by iterating over each pixel each representing RGBA
for(; i < len; i += 4) {
// calculate luma, here using Rec 709
luma = dataSrc[i] * 0.2126 + dataSrc[i+1] * 0.7152 + dataSrc[i+2] * 0.0722;
// update target's RGB using the same luma value for all channels
dataTrg[i] = dataTrg[i+1] = dataTrg[i+2] = luma;
dataTrg[i+3] = dataSrc[i+3]; // copy alpha
}
// put back luma data so we can save it as image
ctx.putImageData(idataTrg, 0, 0);
demo.src = c.toDataURL(); // set demo result's src url
// restore backup data
ctx.putImageData(idataSrc, 0, 0);
};
<button disabled id=btn>SAVE TO GREY</button> (click then scroll down to see result)<br>
<canvas id=c></canvas><br><img id=demo>
我建议这样计算亮度:
var luma = (11 * obj.data[i] + 16 * obj.data[i + 1] + 5 * obj.data[i + 2]) >> 5;
或者您可以使用 ctx.globalCompositeOperation = 'luminosity'
在白色填充 canvas 上绘制图像之前,虽然不那么有趣但结果相同 (:
我想知道是否可以在 HTML5 中添加彩色 canvas,然后在单击保存按钮时将其另存为黑白(灰度)PNG。我已经设法将 canvas 保存为 PNG,太棒了!但我想添加灰度功能,而不必自己用 Illustrator 等程序更改它。 canvas 有移动的粒子顺便说一下。 (虽然我不确定这是否有任何影响)
谢谢~!
function download(){
var dt = c.toDataURL('image/png');
this.href = dt;
};
downloadlink.addEventListener('click', download, false);
可以通过从 canvas 中提取 RGB 数据并计算它们的亮度值来实现。
不过有几个先决条件需要满足,例如 CORS(在这种情况下这似乎不是问题,因为您已经可以保存图像)以及是否希望保留原始数据保存后,您可以将 canvas 上的当前图像复制到临时图像,或者保留需要提取的像素数据的备份。
RGB 转亮度
根据REC 709(或BT.709)公式将RGB数据转换成亮度值(灰度)的公式如下:
luma = Red x 0.2126 + Green x 0.7152 + Blue x 0.0722
或者您可以使用 REC 601 (BT.601) 公式(这在标清视频素材中更常见):
luma = Red x 0.299 + Green x 0.587 + Blue x 0.114
要使用它,只需遍历所有像素,使用这些公式之一获取亮度值,并将目标中的所有通道替换为生成的亮度值。
临时数据
对于临时数据,我们可以执行以下任一操作(单击保存按钮时):
临时canvas
- 创建临时 canvas
- 设置大小等于来源canvas
- 使用
drawImage()
在源 canvas 中绘制
- 使用
getImageData()
提取目标canvas'像素数据
- 迭代像素,使用公式转换,放回数据
- 保存图像然后丢弃临时图像canvas
或
图像数据备份
- 使用
getImageData()
提取图像数据 - 这将作为我们的备份 - 使用
createImageData()
创建相同大小的新 - 迭代备份中的像素,但将结果以亮度形式放入创建的
ImageData
- 放回创建的
ImageData
,保存图片 - 放回备份数据
ImageData
是否需要后一步实际上取决于您如何更新 canvas。如果您正在制作循环动画,则可能不需要放回备份(或保留一个),如果一切都得到更新,但如果是这样并且您看到灰色闪光或某些区域留下灰色,则需要此步骤。
使用 ImageData
方法的示例
var ctx = c.getContext("2d"), img = new Image;
img.onload = setup; img.crossOrigin = "";
img.src = "//i.imgur.com/OrYVGI8.jpg";
function setup() {
c.width = this.naturalWidth; c.height = this.naturalHeight;
ctx.drawImage(this, 0, 0); btn.disabled = false
}
// Main code for demo
btn.onclick = function() {
var idataSrc = ctx.getImageData(0, 0, c.width, c.height), // original
idataTrg = ctx.createImageData(c.width, c.height), // empty data
dataSrc = idataSrc.data, // reference the data itself
dataTrg = idataTrg.data,
len = dataSrc.length, i = 0, luma;
// convert by iterating over each pixel each representing RGBA
for(; i < len; i += 4) {
// calculate luma, here using Rec 709
luma = dataSrc[i] * 0.2126 + dataSrc[i+1] * 0.7152 + dataSrc[i+2] * 0.0722;
// update target's RGB using the same luma value for all channels
dataTrg[i] = dataTrg[i+1] = dataTrg[i+2] = luma;
dataTrg[i+3] = dataSrc[i+3]; // copy alpha
}
// put back luma data so we can save it as image
ctx.putImageData(idataTrg, 0, 0);
demo.src = c.toDataURL(); // set demo result's src url
// restore backup data
ctx.putImageData(idataSrc, 0, 0);
};
<button disabled id=btn>SAVE TO GREY</button> (click then scroll down to see result)<br>
<canvas id=c></canvas><br><img id=demo>
我建议这样计算亮度:
var luma = (11 * obj.data[i] + 16 * obj.data[i + 1] + 5 * obj.data[i + 2]) >> 5;
或者您可以使用 ctx.globalCompositeOperation = 'luminosity'
在白色填充 canvas 上绘制图像之前,虽然不那么有趣但结果相同 (: