马黑黑 发表于 2024-4-21 08:32

canvas画布:大白兔变大红兔

本帖最后由 马黑黑 于 2024-4-21 08:33 编辑 <br /><br /><style>
.papa { font: normal 18px/24px sans-serif; }
.papa p { margin: 12px 0; }
.iMid { text-align: center; }
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>

<div class="papa">
        <p>canvas画布是HTML的一个特殊的图像处理标签,它以像素为操作单位,每一个像素的颜色都可以标记为 rgba 四个颜色单元,r 代表红色、g 代表绿色、b 代表蓝色、a 代表Alpha通道,四个颜色值的取值范围都是 0~255,其中 a 为 0 表示完全透明、255表示完全不透明。</p>
        <p>canvas通过JS操纵画笔,假设画布标识为 ctx,现在我们想拿到画布上每一个像素的数据,可以使用 ctx.getImageData() 方法达成:</p>
<div class='mum'>
<cl-cd data-idx="1"><span class="tBlue">var</span> imageData = ctx.<span class="tRed">getImageData</span>(x, y, width, height);</cl-cd>
</div>
        <p>getImageData需要四个参数,x、y 为要获取数据的画布起始点xy坐标,width、height为获取数据的宽高尺寸,它将返回一个对象,里面包含了丰富的信息,其中,data 将是我们感兴趣的:</p>
<div class='mum'>
<cl-cd data-idx="1"><span class="tBlue">var</span> data = imageData.<span class="tRed">data</span>;</cl-cd>
</div>
        <p>等号左边的 data 是我们声明的变量,等号右边的 data 是前面获取到的对象的 imageData 的数组数据,它记录了所有像素的 rgba 数值,我们只需对其进行逐一操作便可更改图像的颜色构成。需要注意的是,data 数组元素由 r、g、b、a 四个单元构成,换句话说,每一个像素从头到尾对应 data 数组的四个数据单元,为此,我们在遍历 data 数组时,步进步幅应为 4,这样恰好每一次循环处理一个像素。一个图像的像素量都是庞大的,以下是一张大白兔的图片,其尺寸为 658*528=347424(像素),在画布中的 data 数据则达 347424*4=1389696 之多:</p>
        <p class="iMid"><img src="https://638183.freep.cn/638183/t24/webp/rabbit.webp" alt="" /></p>
        <p>我们就拿这只可爱的大白兔开刀——哦不,给它染毛,让它变成一只大红兔是不是更可爱?先上效果:</p>
        <p class="iMid"><canvas id="canv"></canvas></p>
        <p>我去,这是怎么做到的?看一下代码吧:</p>
<div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span>&gt;&lt;<span class="tDarkRed">/canvas</span>&gt;</cl-cd>
<cl-cd data-idx="2">&nbsp;</cl-cd>
<cl-cd data-idx="3">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="4">&nbsp;</cl-cd>
<cl-cd data-idx="5"><span class="tBlue">var</span> ctx = canv.getContext(<span class="tMagenta">"2d"</span>);</cl-cd>
<cl-cd data-idx="6"><span class="tBlue">var</span> img = <span class="tBlue">new</span> Image();</cl-cd>
<cl-cd data-idx="7">img.crossOrigin = <span class="tMagenta">'anonymous'</span>; <span class="tGreen">//跨域</span></cl-cd>
<cl-cd data-idx="8">img.src = <span class="tMagenta">'https://638183.freep.cn/638183/t24/webp/rabbit.webp'</span>;</cl-cd>
<cl-cd data-idx="9">&nbsp;</cl-cd>
<cl-cd data-idx="10">img.onload = <span class="tBlue">function</span>() {</cl-cd>
<cl-cd data-idx="11">&nbsp; &nbsp; <span class="tBlue">var</span> w = canv.width = img.width, h = canv.height = img.height;</cl-cd>
<cl-cd data-idx="12">&nbsp; &nbsp; ctx.drawImage(img, 0, 0);</cl-cd>
<cl-cd data-idx="13">&nbsp; &nbsp; <span class="tBlue">var</span> imageData = ctx.getImageData(0, 0, w, h);</cl-cd>
<cl-cd data-idx="14">&nbsp; &nbsp; <span class="tBlue">var</span> data = imageData.data;</cl-cd>
<cl-cd data-idx="15">&nbsp; &nbsp; console.log(data.length);</cl-cd>
<cl-cd data-idx="16">&nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">var</span> i = 0; i &lt; data.length; i += 4) {</cl-cd>
<cl-cd data-idx="17">&nbsp; &nbsp; &nbsp; &nbsp; data = 0; <span class="tGreen">//拿掉绿色</span></cl-cd>
<cl-cd data-idx="18">&nbsp; &nbsp; &nbsp; &nbsp; data = 0; <span class="tGreen">//拿掉蓝色</span></cl-cd>
<cl-cd data-idx="19">&nbsp; &nbsp; };</cl-cd>
<cl-cd data-idx="20">&nbsp; &nbsp; ctx.putImageData(imageData, 0, 0); <span class="tGreen">//将更改后的数据写入画布</span></cl-cd>
<cl-cd data-idx="21">};</cl-cd>
<cl-cd data-idx="22">&nbsp;</cl-cd>
<cl-cd data-idx="23">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>
        <p>道理很简单:通过 getImageData 拿到画笔绘制的初始图像数据集合,然后将每一个像素里的颜色构成中的蓝色和绿色设置为 0 ,再用 putImageData() 方法将修改过的图像数据写回画布替换了原先的图像。这里的 putImageData() 方法语法结构很简单:数据集合,开始绘制的位置xy坐标。</p>
        <p>可以将上述完整代码存为本地 .html 文档,或将代码拿到 <a href="http://mhh.52qingyin.cn/api/pcode/" target="_blank">pencil code</a>,通过修改相关数据以查看更多的效果。提示:红色的读写,data[ i ],Alpha 的读写,data,这是一一对应的。</p>
</div>

<script>

var ctx = canv.getContext("2d");
var img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://638183.freep.cn/638183/t24/webp/rabbit.webp';

img.onload = function() {
        var w = canv.width = img.width, h = canv.height = img.height;
        ctx.drawImage(img, 0, 0);
        var imageData = ctx.getImageData(0, 0, w, h);
        var data = imageData.data;
        console.log(data.length);
        for(var i = 0; i < data.length; i += 4) {
                data = 0;
                data = 0;
        };
        ctx.putImageData(imageData, 0, 0);
};

</script>

愤怒的葡萄 发表于 2024-4-21 08:33

来这里学习了,感谢马版的无私分享。

马黑黑 发表于 2024-4-21 08:43

愤怒的葡萄 发表于 2024-4-21 08:33
来这里学习了,感谢马版的无私分享。

愤怒的葡萄 发表于 2024-4-21 08:45

马黑黑 发表于 2024-4-21 08:43


马版你也早啊,我得好好努力了,我有事情先下了,有机会再聊吧。

马黑黑 发表于 2024-4-21 08:58

愤怒的葡萄 发表于 2024-4-21 08:45
马版你也早啊,我得好好努力了,我有事情先下了,有机会再聊吧。

好的

南无月 发表于 2024-4-21 09:33

PS里的通道知识。。。。通道用代码去掉两个色,剩下的红色绝对无比纯正,毫无任何杂色。。{:4_199:}最科学的去色方法。。

南无月 发表于 2024-4-21 09:43

本帖最后由 南无月 于 2024-4-21 09:51 编辑

红的是0,绿的是0+1,蓝的是0+2,
         

data = 0; //拿掉红色
data = 0; //拿掉绿色
data = 0; //拿掉蓝色

这三个随意保留一到两条,就可以看到,红兔,绿兔,蓝兔,黄兔,紫兔,青兔
https://642303.freep.cn/642303/za/%E5%85%94%E5%AD%90.png

南无月 发表于 2024-4-21 09:44

{:4_170:}彩色果子加彩色兔子,最近的贴子都五彩缤纷的

红影 发表于 2024-4-21 09:46

去试了一下,也能变成绿色和蓝色,这个有趣{:4_173:}

红影 发表于 2024-4-21 09:47

data能设置么?我去设置成0.5但什么都看不到了{:4_173:}

红影 发表于 2024-4-21 09:50

https://pic.imgdb.cn/item/662470d30ea9cb14037a302e.png

愤怒的葡萄 发表于 2024-4-21 09:51

马黑黑 发表于 2024-4-21 08:58
好的

马版也天天来论坛报到啊,我前段时间上来的少。

红影 发表于 2024-4-21 09:51

红兔子的红眼睛好鲜艳啊{:4_173:}
只能弄出纯色的来么?

马黑黑 发表于 2024-4-21 11:11

红影 发表于 2024-4-21 09:51
红兔子的红眼睛好鲜艳啊
只能弄出纯色的来么?

rgba,恰当修改,无限可能

马黑黑 发表于 2024-4-21 11:12

愤怒的葡萄 发表于 2024-4-21 09:51
马版也天天来论坛报到啊,我前段时间上来的少。

我现在有时间

马黑黑 发表于 2024-4-21 11:20

南无月 发表于 2024-4-21 09:33
PS里的通道知识。。。。通道用代码去掉两个色,剩下的红色绝对无比纯正,毫无任何杂色。。最科学 ...

PS也是用代码写出来的一个巨无霸软件

马黑黑 发表于 2024-4-21 11:21

红影 发表于 2024-4-21 09:50


也是很漂亮的样纸{:4_170:}

马黑黑 发表于 2024-4-21 11:22

红影 发表于 2024-4-21 09:47
data能设置么?我去设置成0.5但什么都看不到了

rgb中,对原图像至少保留一项。

另外,取值范围是 0~255,你 0.5 差不多就是不要红色了。

马黑黑 发表于 2024-4-21 11:24

红影 发表于 2024-4-21 09:47
data能设置么?我去设置成0.5但什么都看不到了
rgb,红蓝绿, r 的下标是 0, g 的下标是 1, b 的下标是 2,下标是 4 时 指向 Alpha 通道

南无月 发表于 2024-4-21 12:15

马黑黑 发表于 2024-4-21 11:20
PS也是用代码写出来的一个巨无霸软件

原来如此。。。
三原色红绿蓝,三间色青品黄。。去掉两色得到三原色,去掉一色得到三间色。。
现在看到老师用纯代码实现了。。
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: canvas画布:大白兔变大红兔