js实现图片方向渐变

1. 背景

        为了让本公司的定制app网站更加具有样式多样性,提出了新增渐变模式,其中就涉及到了图片的渐变,同样也可以设置图片渐变的透明度

2. 渐变核心思路

  1. 将图片绘制到画布上
  2. 获取画布上的图像像素
  3. 把hex格式的颜色转成rgba格式的颜色
  4. 根据两种颜色获取到颜色渐变列表
  5. 再根据方向给每一个像素点赋值
  6. 最后将画布导出为png格式的图片地址

3. 代码实现

1. 封装一个方法用于hex转成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. 封装一个方法用于获取渐变色列表

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. 封装一个方法用于获取渐变后的图片地址

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)
    }
}

注意:如果图片的地址是远程地址,那么就会报一个跨域的错误,需要后端把标头改成*

猜你喜欢

转载自blog.csdn.net/m0_68349563/article/details/128442392