Vue和Canvas:如何实现图片的颜色调整和滤镜效果

1. Vue和Canvas介绍

Vue.js是一个轻巧、高效的JavaScript框架,广受开发者欢迎,并且被用于构建一系列单页面应用程序。

Canvas是HTML5中定义的一个画布元素,可以用来绘制2D图形和动态图像。

2. 实现图片的颜色调整功能

2.1 图片预览

首先需要使用Vue.js实现图片的预览功能,可以通过Vue.js自带的<input type="file"><img>标签来达到目的。

将图片显示在canvas上需要两个步骤:使用drawImage()方法将图片画在canvas上,将图片转换为canvas可处理的颜色值。

new Vue({

el: "#app",

data: {

imageSrc: "",

canvas: null,

ctx: null,

imageData: null,

},

mounted() {

this.initCanvas();

},

methods: {

initCanvas() {

this.canvas = document.getElementById("canvas");

this.ctx = this.canvas.getContext("2d");

},

previewImage(event) {

const file = event.target.files[0];

const reader = new FileReader();

reader.onload = () => {

const image = new Image();

image.onload = () => {

this.canvas.width = image.width;

this.canvas.height = image.height;

this.drawImage(image);

};

image.src = reader.result;

this.imageSrc = reader.result;

};

reader.readAsDataURL(file);

},

drawImage(image) {

this.ctx.drawImage(image, 0, 0);

this.imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);

},

},

});

这里使用了Vue.js的data属性管理图片链接和canvas对象,使用drawImage()绘制图片到canvas并使用getImageData()获取图像数据。

2.2 调整图片颜色

接下来,实现调整图片颜色的功能。调整图片颜色的方法有很多,这里采用简单的调整亮度、对比度、饱和度的方法。

2.2.1 调整亮度

调整亮度的方法很简单,将所有像素值加上一个指定数值即可。具体实现代码如下:

changeBrightness(value) {

for (let i = 0; i < this.imageData.data.length; i += 4) {

this.imageData.data[i] += value;

this.imageData.data[i + 1] += value;

this.imageData.data[i + 2] += value;

}

this.ctx.putImageData(this.imageData, 0, 0);

}

这里使用了value指定亮度,将每个像素的RGB值都加上value即可。

2.2.2 调整对比度

要调整对比度,可以用下面这个公式:

C = f( C ? 0.5) + 0.5

其中f(x) = (1 + factor) * Math.pow(x - 0.5, 3) + 0.5

下面是具体实现代码:

changeContrast(value) {

const factor = (259 * (value + 255)) / (255 * (259 - value));

for (let i = 0; i < this.imageData.data.length; i += 4) {

this.imageData.data[i] = factor * (this.imageData.data[i] - 128) + 128;

this.imageData.data[i + 1] = factor * (this.imageData.data[i + 1] - 128) + 128;

this.imageData.data[i + 2] = factor * (this.imageData.data[i + 2] - 128) + 128;

}

this.ctx.putImageData(this.imageData, 0, 0);

}

这里使用了value指定对比度,使用公式计算RGB值的新值。

2.2.3 调整饱和度

饱和度每个像素的RGB值都是另一个值的加权平均值。使用下面的公式计算权重:

gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

其中r、g、b分别是像素的红、绿、蓝通道值。

然后使用下面的公式计算新的RGB值:

r = gray + saturation * (r - gray)

g = gray + saturation * (g - gray)

b = gray + saturation * (b - gray)

其中saturation是在0到1之间的值。

changeSaturation(value) {

const grayScaleLuminance = [0.2989, 0.5870, 0.1140];

const maxRGB = 255;

for (let i = 0; i < this.imageData.data.length; i += 4) {

const r = this.imageData.data[i];

const g = this.imageData.data[i + 1];

const b = this.imageData.data[i + 2];

const gray = r * grayScaleLuminance[0] + g * grayScaleLuminance[1] + b * grayScaleLuminance[2];

this.imageData.data[i] = Math.round(gray + (r - gray) * value);

this.imageData.data[i + 1] = Math.round(gray + (g - gray) * value);

this.imageData.data[i + 2] = Math.round(gray + (b - gray) * value);

}

this.ctx.putImageData(this.imageData, 0, 0);

}

3. 实现图片滤镜效果

本节将实现几个常见的图片滤镜效果。

3.1 模糊滤镜

模糊滤镜可以通过计算每个像素的周围像素的平均值来实现。具体代码如下:

blurImage() {

const weights = [1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9];

const side = Math.round(Math.sqrt(weights.length));

const halfSide = Math.floor(side / 2);

const src = this.imageData.data;

const dest = new Uint8ClampedArray(src.length);

const width = this.canvas.width;

const height = this.canvas.height;

let alphaFac = 0;

for (let i = 0; i < weights.length; i++) {

const f = weights[i];

alphaFac += f;

}

for (let y = 0; y < height; y++) {

for (let x = 0; x < width; x++) {

const sy = y;

const sx = x;

const dstOff = (y * width + x) * 4;

let r = 0;

let g = 0;

let b = 0;

let a = 0;

for (let cy = 0; cy < side; cy++) {

for (let cx = 0; cx < side; cx++) {

const scy = sy + cy - halfSide;

const scx = sx + cx - halfSide;

if (scy >= 0 && scy < height && scx >= 0 && scx < width) {

const srcOff = (scy * width + scx) * 4;

const wt = weights[cy * side + cx];

r += src[srcOff] * wt;

g += src[srcOff + 1] * wt;

b += src[srcOff + 2] * wt;

a += src[srcOff + 3] * wt;

}

}

}

dest[dstOff] = r / alphaFac;

dest[dstOff + 1] = g / alphaFac;

dest[dstOff + 2] = b / alphaFac;

dest[dstOff + 3] = a;

}

}

this.imageData.data.set(dest);

this.ctx.putImageData(this.imageData, 0, 0);

}

3.2 反色滤镜

反色滤镜可以将每个像素的颜色取反实现。代码如下:

invertImage() {

for (let i = 0; i < this.imageData.data.length; i += 4) {

this.imageData.data[i] = 255 - this.imageData.data[i];

this.imageData.data[i + 1] = 255 - this.imageData.data[i + 1];

this.imageData.data[i + 2] = 255 - this.imageData.data[i + 2];

}

this.ctx.putImageData(this.imageData, 0, 0);

}

3.3 灰度滤镜

灰度滤镜可以通过将每个像素的R、G、B值取平均值实现。具体代码如下:

grayscaleImage() {

for (let i = 0; i < this.imageData.data.length; i += 4) {

const avg = (this.imageData.data[i] + this.imageData.data[i + 1] + this.imageData.data[i + 2]) / 3;

this.imageData.data[i] = avg;

this.imageData.data[i + 1] = avg;

this.imageData.data[i + 2] = avg;

}

this.ctx.putImageData(this.imageData, 0, 0);

}

3.4 调整色温

如果想要通过滤镜调整图片的色温,可以使用下面的代码:

adjustTemperature(value) {

const newRedMatrix = [

1 + 0.10 * value, 0.0, 0.0,

0.0, 1.0, 0.0,

0.0, 0.0, 1.0 - 0.10 * value,

];

for (let i = 0; i < this.imageData.data.length; i += 4) {

const [r, g, b] = [this.imageData.data[i], this.imageData.data[i + 1], this.imageData.data[i + 2]];

this.imageData.data[i] = Math.round(r * newRedMatrix[0] + g * newRedMatrix[1] + b * newRedMatrix[2]);

this.imageData.data[i + 1] = Math.round(r * newRedMatrix[3] + g * newRedMatrix[4] + b * newRedMatrix[5]);

this.imageData.data[i + 2] = Math.round(r * newRedMatrix[6] + g * newRedMatrix[7] + b * newRedMatrix[8]);

}

this.ctx.putImageData(this.imageData, 0, 0);

}

这里使用的是一个线性变换newRedMatrix,可以将红色通道的值增加或减少一定比例。如果想要增加色温,则增加红色通道的值,同时减少蓝色通道的值,反之则亦然。

4. 结语

本文介绍了如何使用Vue.js和Canvas实现图片的颜色调整和滤镜效果。使用Canvas可以轻松实现常见的图像处理操作,不仅能够提供更好的用户体验、更加直观的操作,而且还能够显著提高网站的性能。