1. Background
In order to make the company's customized app website more diverse in style, a new gradient mode is proposed, which involves the gradient of the picture, and the transparency of the gradient of the picture can also be set
2. The core idea of gradient
- draw the picture to the canvas
- Get the image pixels on the canvas
- Convert the color in hex format to the color in rgba format
- Obtain a list of color gradients based on two colors
- Then assign a value to each pixel according to the direction
- Finally, export the canvas as an image address in png format
3. Code implementation
1. Encapsulate a method for converting hex to rgba
export const hexToRgba = (hex) => {
const rgb = []
for (let i = 1; i < hex.length; i += 2) {
rgb.push(parseInt('0x' + hex.slice(i, i + 2)))
}
return rgb
}
2. Encapsulate a method to get the list of gradient colors
import { hexToRgba } from "@/utils/icon-gradient/hexToRgba";
export const getGradientList = (startColor, endColor, step) => {
const sColor = hexToRgba(startColor)
const eColor = hexToRgba(endColor)
const rStep = (eColor[0] - sColor[0]) / (step - 1)
const gStep = (eColor[1] - sColor[1]) / (step - 1)
const bStep = (eColor[2] - sColor[2]) / (step - 1)
let aStep
// 判断颜色有没有透明度
if (eColor[3] && sColor[3]) {
aStep = (eColor[3] - sColor[3]) / (step - 1)
}
const gradientColorsList = []
for (let i = 0; i < step; i++) {
if (aStep) {
gradientColorsList.push(new Array(Math.round(rStep * i + sColor[0]), Math.round(gStep * i + sColor[1]), Math.round(bStep * i + sColor[2]), Math.round(aStep * i + sColor[3])))
} else {
gradientColorsList.push(new Array(Math.round(rStep * i + sColor[0]), Math.round(gStep * i + sColor[1]), Math.round(bStep * i + sColor[2])))
}
}
return gradientColorsList
}
3. Encapsulate a method to get the address of the image after the gradient
import { getGradientList } from "@/utils/icon-gradient/getGradientList";
export const getImageUrl = (canvasDom, imageUrl, gradientColors, callback) => {
const startColor = gradientColors.colors[0]
const endColor = gradientColors.colors[1]
const angle = gradientColors.angle
const ctx = canvasDom.getContext('2d', { willReadFrequently: true })
const w = canvasDom.width
const h = canvasDom.height
ctx.clearRect(0, 0, w, h)
const image = new Image()
image.src = imageUrl
image.crossOrigin = "Anonymous";
image.onload = () => {
// 将图片绘制到画布上
ctx.drawImage(image, 0, 0, w, h)
// 获取画布上的图像像素
const imgData = ctx.getImageData(0, 0, w, h)
let gradientList
if (angle == 0) {
// 从下到上
gradientList = getGradientList(startColor, endColor, h)
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
imgData.data[((i * (imgData.width * 4)) + (j * 4)) + 0] = gradientList[gradientList.length - 1 - i][0]
imgData.data[((i * (imgData.width * 4)) + (j * 4)) + 1] = gradientList[gradientList.length - 1 - i][1]
imgData.data[((i * (imgData.width * 4)) + (j * 4)) + 2] = gradientList[gradientList.length - 1 - i][2]
if (gradientList[gradientList.length - 1 - i][3]) {
imgData.data[((i * (imgData.width * 4)) + (j * 4)) + 3] = Math.round(imgData.data[((i * (imgData.width * 4)) + (j * 4)) + 3] * gradientList[gradientList.length - 1 - i][3] / 255)
}
}
}
} else if (angle == 90) {
// 从左到右
gradientList = getGradientList(startColor, endColor, w)
for (let i = 0; i < h; i++) {
for (let j = w - 1; j >= 0; j--) {
imgData.data[((j * (imgData.width * 4)) + (i * 4)) + 0] = gradientList[i][0]
imgData.data[((j * (imgData.width * 4)) + (i * 4)) + 1] = gradientList[i][1]
imgData.data[((j * (imgData.width * 4)) + (i * 4)) + 2] = gradientList[i][2]
if (gradientList[i][3]) {
imgData.data[((j * (imgData.width * 4)) + (i * 4)) + 3] = Math.round(imgData.data[((j * (imgData.width * 4)) + (i * 4)) + 3] * gradientList[i][3] / 255)
}
}
}
}
// 将修改后的代码复制回画布中
ctx.putImageData(imgData, 0, 0)
// 图片导出为 png 格式
const imgType = "image/png"
canvasDom.toBlob((blob) => {
callback(URL.createObjectURL(blob))
}, imgType, 1)
}
}
Note: If the address of the picture is a remote address, a cross-domain error will be reported, and the backend needs to change the header to *