npm i --save colorthief //引入colorthief插件
在iview的Upload上传图片的控件中,当上传成功后,自动吸取图片的主色当做图片的背景色,总结了以下四种方法,第四种是利用colorthief插件,第一种,第二种,第三种是利用的图片取主色原理,至于从rgb转为hsv,在计算是为了提高取出的背景色的饱和度和明亮度,大家可酌情自己进行更改,我最后输出的色值是16进制的。
如图:

<template>
<div class="wrap" :style="wrapStyle">
<div class="jz bgfont" v-html="tips">
{{ this.payload.width }} * {{ this.payload.height }}
</div>
<Upload
class="uploader"
ref="upload"
:format="['jpg', 'jpeg', 'png', 'gif']"
:max-size="4096"
:on-success="handleSuccess"
:on-error="handleError"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload"
with-credentials
multiple
:show-upload-list="false"
action="/General/Upload/Picture/upload"
>
<div :style="wrapStyle" class="wrap bg">
<div class="jz">
<Icon type="ios-cloud-upload" size="36"></Icon>
<p class="tips">点击或者拖拽上传</p>
</div>
</div>
</Upload>
<img
v-show="!!imgUrl"
:src="imgUrl"
class="img"
crossorigin="anonymous"
@load="onload"
/>
<div
style="width: 600px; height: 300px"
:style="{ background: color }"
id="color"
>
<p style="margin-top: 80px">颜色</p>
</div>
</div>
</template>
<style scoped>
.img {
width: 100%;
height: 100%;
position: absolute;
z-index: 3;
top: 0;
left: 0;
}
.wrap {
position: relative;
margin: 0 auto;
background: #fafafa;
}
#color {
position: absolute;
z-index: 1;
top: -20px;
left: -90px;
color: white;
}
.uploader {
position: absolute;
z-index: 4;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.jz {
position: absolute;
width: 140px;
height: auto;
top: 50%;
transform: translate(-50%, -50%);
left: 50%;
/*margin-left: -70px;*/
text-align: center;
color: #fff;
text-shadow: 1px 1px #555;
line-height: 1.4;
}
.bg {
transition: 0.3s ease all;
background: rgba(0, 0, 0, 0.3);
opacity: 0;
}
.bg:hover {
opacity: 1;
}
.bgfont {
color: #ddd;
text-shadow: none;
font-size: 22px;
line-height: 60px;
}
.tips {
font-size: 12px;
}
</style>
<script>
import ColorThief from 'colorthief'
import { encode } from 'blurhash';
const encodeBlurHashOfImage = async (url) => {
// 将图片 url 加载到 img 对象
const loadImg = (url) => new Promise((rs) => {
const img = new Image();
img.onload = () => rs(img);
img.src = url;
});
const img = await loadImg(url);
// 计算合适的 blurhash 尺寸
const blurSize = (img) => {
let {
naturalWidth: width,
naturalHeight: height,
} = img;
const ratio = Math.max(width / 50, height / 50);
return {
width: parseInt(width / ratio),
height: parseInt(height / ratio),
};
};
const size = blurSize(img);
// 创建画板
const cvs = document.createElement('canvas');
cvs.width = size.width;
cvs.height = size.height;
const ctx = cvs.getContext('2d');
ctx.drawImage(img, 0, 0, size.width, size.height);
// 计算 blurhash
await new Promise(rs => setTimeout(rs, 0));
const { data, width, height } = ctx.getImageData(0, 0, size.width, size.height);
const hash = encode(data, width, height, 4, 4);
return {
hash,
size: `${size.width}x${size.height}`,
};
};
export default {
data() {
let type = Object.prototype.toString.call(this.payload),
width,
height,
tips = '';
if (type == '[object Object]') {
width = this.payload.width * this.payload.scale + 'px';
height = this.payload.height * this.payload.scale + 'px';
tips = this.payload.width + ' * ' + this.payload.height;
} else {
width = this.payload[0].width * this.payload[0].scale + 'px';
height = this.payload[0].height * this.payload[0].scale + 'px';
this.payload.forEach((item) => {
tips += item.width + ' * ' + item.height + '、';
});
}
return {
color: '',
imgUrl: '',
blurhashValue: '',
wrapStyle: {
width,
height
},
tips,
};
},
props: {
blurhash: {
type: Boolean,
default: false,
},
value: {
type: String,
default: '',
},
payload: {
type: [Object, Array],
default: () => ({}),
},
},
methods: {
onload() {
//第四种
const img = document.querySelector('.img');
const colorthief = new ColorThief();
let colorImg = colorthief.getColor(img);
let value = `rgb(${colorImg[0]},${colorImg[1]},${colorImg[2]})`
console.log(value)
let aa=this.showHsv(colorImg[0], colorImg[1], colorImg[2])
console.log(aa)
let bb=this.hsvShowRGB(aa[0],aa[1],aa[2])
console.log(bb)
this.color = this.showRGB(bb)
this.$emit('colorValue', this.color)
// 第一种,第二种,第三种
// setTimeout(() => {
// let rgb = this.colorfulImg(img);
// let value = `rgb(${rgb.r},${rgb.g},${rgb.b})`
// this.color = this.showRGB(value)
// this.$emit('colorValue', this.color)
// console.log(this.color, 'pppp')
// }, 500)
},
colorfulImg: function (img) {
const canvas = document.createElement('canvas');
let length,
i = -4,
blockSize = 5,
count = 0,
rgb = { r: 0, g: 0, b: 0 }
canvas.width = this.payload.width;
canvas.height = this.payload.height;
const context = canvas.getContext && canvas.getContext('2d');
console.log(img)
context.drawImage(img, 0, 0);
// 获取像素数据
let data = context.getImageData(0, 0, this.payload.width, this.payload.height).data;
console.log(data)
//第一种
//length = data.length
//while ((i += blockSize * 4) < length) {
// ++count;
// rgb.r += data[i];
// rgb.g += data[i + 1];
// rgb.b += data[i + 2];
//}
//rgb.r = ~~(rgb.r / count);
//rgb.g = ~~(rgb.g / count);
//rgb.b = ~~(rgb.b / count);
//console.log(rgb)
//第二种
// rgb={
// r:data[0],
// g:data[1],
// b:data[2]
// }
//第三种平均值算法(二维的实现)
// rgb = { r: 1, g: 1, b: 1 }
// // 取所有像素的平均值
// for (let row = 0; row < this.payload.height; row++) {
// for (let col = 0; col < this.payload.width; col++) {
// // console.log(data[((img.width * row) + col) * 4])
// if (row == 0) {
// rgb.r += data[((this.payload.width * row) + col)];
// rgb.g += data[((this.payload.width * row) + col) + 1];
// rgb.b += data[((this.payload.width * row) + col) + 2];
// } else {
// rgb.r += data[((this.payload.width * row) + col) * 4];
// rgb.g += data[((this.payload.width * row) + col) * 4 + 1];
// rgb.b += data[((this.payload.width * row) + col) * 4 + 2];
// }
// }
// }
// // 求取平均值
// rgb.r /= (this.payload.width * this.payload.height);
// rgb.g /= (this.payload.width * this.payload.height);
// rgb.b /= (this.payload.width * this.payload.height);
// // 将最终的值取整
// rgb.r = Math.round(rgb.r);
// rgb.g = Math.round(rgb.g);
// rgb.b = Math.round(rgb.b);
return rgb;
},
//rgb转hsv
showHsv(r, g, b) {
r = r / 255;
g = g / 255;
b = b / 255;
let h, s, v;
let min = Math.min(r, g, b);
let max = v = Math.max(r, g, b);
let l = (min + max) / 2;
let difference = max - min;
if (max == min) {
h = 0;
} else {
switch (max) {
case r: h = (g - b) / difference + (g < b ? 6 : 0); break;
case g: h = 2.0 + (b - r) / difference; break;
case b: h = 4.0 + (r - g) / difference; break;
}
h = Math.round(h * 60);
}
if (max == 0) {
s = 0;
} else {
s = 1 - min / max;
}
s = Math.round(s * 100);
v = Math.round(v * 100);
console.log('原始',[h,s,v])
let s1=30+0.5*s
let v1=20+0.4*v
return [h, s1, v1]
},
//hsv转rgb
hsvShowRGB(h, s, v) {
var s = s / 100;
var v = v / 100;
var h1 = Math.floor(h / 60) % 6;
var f = h / 60 - h1;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
var r, g, b;
switch (h1) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
return `rgb(${Math.ceil(r*255)},${Math.ceil(g*255)},${Math.ceil(b*255)})`
},
//rgb转16进制
showRGB(str) {
let hexcode = "#";
let v = str.substring(4, str.length - 1);
let s = v.split(",");
for (let x = 0; x < 3; x++) {
let n = s[x];
if (n === "") n = "0";
let c = "0123456789ABCDEF",
b = "",
a = n % 16;
b = c.substr(a, 1);
a = (n - a) / 16;
hexcode += c.substr(a, 1) + b
}
return hexcode;
},
handleSuccess(res, file) {
if (res.status === 2) {
let type = Object.prototype.toString.call(this.payload);
if (type == '[object Object]') {
if ((this.payload.width && (this.payload.width !== res.data.width)) || (this.payload.height && (this.payload.height !== res.data.height))) {
this.$Notice.warning({
title: '图片尺寸不符合要求',
desc: '标准尺寸为 ' + this.payload.width + ' * ' + this.payload.height
});
} else {
const { url } = res.data;
this.commitValue(url, res);
}
} else if (type == '[object Array]') {
let pass = false,
desc = '';
this.payload.forEach((item) => {
if (item.width === res.data.width && item.height === res.data.height) {
this.$set(this.wrapStyle, 'width', (item.width * item.scale) + 'px');
this.$set(this.wrapStyle, 'height', (item.height * item.scale) + 'px');
pass = true;
}
desc += item.width + ' * ' + item.height + '、';
});
if (pass) {
const { url } = res.data;
this.commitValue(url, {
height: res.data.height,
width: res.data.width,
});
} else {
this.$Notice.warning({
title: '图片尺寸不符合要求',
desc: '标准尺寸为 ' + desc
});
}
}
} else {
this.$Message.error('图片文件上传错误!')
}
},
handleError(res, file) {
this.$Message.error('图片文件上传错误!')
},
handleFormatError(file) {
this.$Message.error('图片文件格式错误!')
// 格式不对
},
handleMaxSize(file) {
this.$Notice.warning({
title: '超出文件大小',
desc: '文件 ' + file.name + ' 太大了, 超出 2M 的文件不被允许。'
});
},
handleBeforeUpload(file) {
this.lastImageLocalUrl = URL.createObjectURL(file);
return true
},
async commitValue(imgUrl, imgStyle) {
let finalUrl = imgUrl;
if (this.blurhash) {
const { lastImageLocalUrl } = this;
if (!lastImageLocalUrl) this.$Notice.warning('BlurHash 处理异常:未找到上传图片的本地链接');
const { hash, size } = await encodeBlurHashOfImage(lastImageLocalUrl);
const sp = imgUrl.indexOf('?') < 0 ? '?' : '&';
const blurParams = `_blurhash=${encodeURIComponent(hash)}&_blursize=${size}`;
finalUrl = finalUrl.concat(`${sp}${blurParams}`);
}
this.$emit('input', finalUrl);
this.$emit('updateStyle', imgStyle);
},
},
mounted: function () {
},
watch: {
value: {
handler(nv, ov) {
this.imgUrl = nv;
},
deep: false,
immediate: true
},
}
}
</script>
该子组件在父组件的引用
<template>
<div class="page-comic-cartoon-contact">
<getImage
v-model="sub_cover_url"
:payload="payloadicon"
@colorValue="colorValue"
></getImage>
</div>
</template>
<script>
import getImage from '~/components/getImage.vue';
export default {
name: 'page-comic-cartoon-contact',
components: { getImage },
data() {
return {
sub_cover_url:'',
payloadicon: {
width: 416,//想传入的图片宽度
height: 242,//想传入图片的高度
scale:1//图片在页面展示缩放大小
},
};
},
methods: {
colorValue(data){
console.log(data)//可得输出的16进制的背景色值
}
},
mounted(){
this.colorValue()
}
}
</script>

该博客介绍了如何在iview的Upload组件中,利用colorthief插件从上传的图片中提取主色,并将其设置为图片背景色。博主提供了四种方法,包括直接使用colorthief,以及三种自定义的图片取色算法。代码示例展示了从RGB到HSV的转换,以增强颜色饱和度和亮度,并最终输出16进制色值。此外,还展示了如何在父组件中监听颜色值的变化。
1147

被折叠的 条评论
为什么被折叠?



