吸管工具,canvas模拟吸管工具,吸取图片中的颜色值 vue.js 颜色值 转换
【代码】吸管工具,canvas模拟吸管工具,吸取图片中的颜色值 vue.js 颜色值 转换。
·
canvas-straw.vue :吸取颜色组件
<template>
<div class="color-content" :style="{'--size': boxSize + 'px', '--pix-size': '10px'}" v-if="value">
<div class="close-icon" @click="close">close</div>
<div class="img-box">
<img :src="src" ref="img" crossOrigin @load="initCanvas()" alt="origin-img">
</div>
<div class="pix-box" :style="pixPos">
<div class="center" :style="{'borderColor': `rgb(${color})`}"></div>
<div class="htmls" v-html="innerVal"></div>
</div>
</div>
</template>
<script>
export default {
name: 'canvas-straw',
model: {
event: 'on-change',
prop: 'value'
},
props: {
boxSize: {
type: Number,
default: 100
},
value: {
type: Boolean,
default: false
},
src: {
type: String,
default: ''
}
},
data () {
return {
color: '153, 153, 153',
innerVal: '',
mouseInfo: {
clientY: 0,
clientX: 0,
space: 20,
size: 100
}
}
},
computed: {
pixPos () {
const width = window.innerWidth
const height = window.innerHeight
let {clientY, clientX, space, size} = this.mouseInfo
let left = clientX
let top = clientY
if ((clientY + size) > height) {
top = clientY - size - space
} else {
top += space
}
if ((clientX + size) > width) {
left = clientX - size - space
} else {
left += space
}
return `left: ${left}px; top:${top}px`
}
},
methods: {
close () {
this.$emit('on-change', false)
},
initCanvas () {
let oImg = this.$refs.img
let canvas = this.draw(oImg)
oImg.addEventListener('click', (e) => {
const [r, g, b] = this.color.split(',')
console.log({r, g, b})
this.$emit('on-change', {r, g, b})
})
oImg.addEventListener('mousemove', (e) => {
this.mouseInfo.clientY = e.clientY
this.mouseInfo.clientX = e.clientX
let x = e.offsetX
let y = e.offsetY
this.color = this.getPix(x, y, canvas.ctx)
})
},
// 画图
draw (img) {
let style = window.getComputedStyle(img)
let width = parseInt(style.width)
let height = parseInt(style.height)
img.style.width = width + 'px'
img.style.height = height + 'px'
img.style.maxWidth = width + 'px'
img.style.maxHeight = height + 'px'
let canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
let ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, width, height) // 这里一定要写上获取到图片的宽高,否则生成的图片和原图片大小不一样,吸取到的颜色不准
return {
ctx,
canvas
}
},
// 获取16进制颜色
gethex (r, g, b) {
r = r.toString(16)
g = g.toString(16)
b = b.toString(16)
// 补0
if (r.length === 1) r = '0' + r
if (g.length === 1) g = '0' + g
if (b.length === 1) b = '0' + b
let hex = r + g + b
// 简化处理,如 FFEEDD 可以写为 FED
if (r.slice(0, 1) === r.slice(1, 1) && g.slice(0, 1) === g.slice(1, 1) && b.slice(0, 1) === b.slice(1, 1)) {
hex = r.slice(0, 1) + g.slice(0, 1) + b.slice(0, 1)
}
return hex
},
// 获取像素颜色
getPix (x, y, context) {
const size = 10
const num = this.boxSize / 2 / size // boxSize (必须是偶数 盒子大小) / 一半 / 每个像素大小
x = x - num // 减掉自身像素个数的开始坐标
y = y - num
// 读取图片像素信息
const w = num * 2 + 1 // 图片大小是 像素个数的2倍 (并多一行一列像素 为了视觉上的中心点 所以必须是奇数)
const h = num * 2 + 1
const centerPos = Math.ceil(w / 2) // 获取中心点坐标 向上取整
let imageData = context.getImageData(x, y, w, h) // 截取 当前坐标下 w,h大小画图的数据
const pos = this.getPos(imageData.data, w) // 计算当前截取画布下的像素信息(读取像素长度控制在千万以内 否则易导致浏览器崩溃)
// 生成矩阵数据
let arr = []
Array(w).fill().map((item, index) => {
let tx = index + 1
const inners = Array(h).fill().map((item2, index2) => {
let ty = index2 + 1
const color = pos.get(`${tx},${ty}`)
// 创建 10 * 10 px大小为单位的像素块
arr.push(`<div data-set="${tx},${ty}" style="left:${index * 10}px; top:${index2 * 10}px; background: rgb(${color})"></div>`)
return '#' + color
})
return inners
})
// 更新数据
this.innerVal = arr.join('')
// 返回当前中心坐标的 颜色值
return pos.get(`${centerPos},${centerPos}`)
},
// 计算像素信息并返回
getPos (data, imgWidth) {
let pos = new Map()
let length = data.length
for (let i = 0; i < length; i++) {
if (i % 4 === 0) { // 每四个元素为一个像素数据 r,g,b,alpha
let x = i / 4 % imgWidth + 1 // 横坐标
let y = Math.floor(i / 4 / imgWidth) + 1 // 纵坐标
let alpha = Math.round(data[i + 3] / 255 * 100) / 100 // alpha 值
if (data[i + 3] === 255) { // 没有alpha 值
// let hex = this.gethex(data[i], data[i + 1], data[i + 2])
let hex = `${data[i]}, ${data[i + 1]}, ${data[i + 2]}`
pos.set(`${x},${y}`, hex)
} else if (alpha > 0) { // 有alpha 值
let rgba = `${data[i]}, ${data[i + 1]}, ${data[i + 2]}, ${alpha}`
pos.set(`${x},${y}`, rgba)
}
}
}
return pos
}
}
}
</script>
<style lang='less' scoped>
.color-content {
background-color: rgba(0 , 0, 0, 0.5);
z-index: 9999;
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
text-align: center;
padding: 20px;
.img-box {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
}
img {
cursor: crosshair;
max-width: 100%;
max-height: 100%;
}
}
.close-icon {
position: fixed;
right: 10px;
top: 10px;
cursor: pointer;
transition: ease-in-out 0.3s;
color: #ebebeb;
&:hover{
color: #ff0000;
}
}
</style>
<style lang="less">
@pix-size: 10px;
.pix-box {
z-index: 999;
position: absolute;
// left: 20px;
top: 30px;
width: calc(var(--size) + @pix-size + 2px);
height: calc(var(--size) + @pix-size + 2px);
box-sizing: border-box;
border: #fff solid 1px;
border-radius: 50%;
overflow: hidden;
box-shadow: 0px 0px 5px #999;
div.htmls {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
& > div {
width: @pix-size;
height: @pix-size;
position: absolute;
border: none;
}
}
div.center {
position: absolute;
width: @pix-size;
height: @pix-size;
left: calc(var(--size) / 2);
top: calc(var(--size) / 2);
box-sizing: border-box;
border: #999 solid 1px;
z-index: 10;
filter: invert(100%);
}
background: url('./images/bg-pixel.jpg')
}
</style>
使用方法:
在某个页面中 引入 import canvasStraw from './canvas-straw.vue' 并注册组件
../index.vue
<template>
<div>
<i-button @click="show = !show">打开</i-button>
<canvas-straw src="http:../images/test.jpg" v-model="show"></canvas-straw>
</div>
</template>
<script>
import canvasStraw from './canvas-straw.vue'
export default {
components: {
canvasStraw
},
data () {
return {
show: false
}
}
}
</script>
更多推荐
已为社区贡献12条内容
所有评论(0)