import { ref, onScopeDispose, watch, nextTick, unref, computed, watchEffect } from 'vue' import type { Ref } from 'vue' import { isDom } from '@/utils/common' import TintImageWorker from '@/utils/image.worker?worker' import useMainStore from '@/store/main' import { useRoute } from 'vue-router' import analyze from 'rgbaster' export type RGBA = number[] export type Point = [number, number] export interface SetImgBgOption { image?: string | HTMLImageElement | null basePoint?: Point[] distance?: number enableSharpen?: boolean rotate?: number scale?: number } interface InitOption { image: string | HTMLImageElement frontColor?: Ref setFrontColor?: any } function getRgba(canvas: any, that: any) { const imgWidth = that.width const imgHeight = that.height canvas.width = imgWidth canvas.height = imgHeight const context = canvas.getContext('2d') context.drawImage(that, 0, 0, imgWidth, imgHeight) const imgdatas = context.getImageData(0, 0, imgWidth, imgHeight) const imgdata = imgdatas.data const newJson: any = {} const length = imgdata.length console.log('length:' + length) for (let i = 0; i < 250; i++) { if (i % 4 === 0) { const alpha = Math.round((imgdata[i + 3] / 255) * 100) / 100 const rgba = imgdata[i] + ',' + imgdata[i + 1] + ',' + imgdata[i + 2] + ',' + alpha if (!newJson[rgba]) { newJson[rgba] = 1 } else { newJson[rgba]++ } } } let maxNum = 0 let maxVal = '' for (const key in newJson) { if (newJson[key] > maxNum) { maxNum = newJson[key] maxVal = key } } console.log('rgba:', maxVal + ';次数:' + maxNum) return maxVal } function getHex(...value: any) { const r = value[0].toString(16) const g = value[1].toString(16) const b = value[2].toString(16) let hex = r + g + b 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 } interface MessageData { drawing: boolean blob?: Blob } export const useSetImgBg = (option: Ref, frontColor?: Ref, setFrontColor?: any) => { const { fullPath } = useRoute() const mainStore = useMainStore() const userSetColor = computed(() => { return mainStore.userMarkConfig?.[fullPath]?.frontColor }) watchEffect(() => { if (!!userSetColor.value && setFrontColor) { setFrontColor(userSetColor.value) } }) const initImage = async ({ image, frontColor, setFrontColor }: InitOption) => { if (!image) { return console.warn(`return for img define ${image}`) } if (!isDom(image)) { image = await new Promise((resolve, reject) => { const img = new Image() img.src = image as string img.onload = async () => { if (frontColor && setFrontColor) { // console.time() try { const result = await analyze(image, { scale: 0.2 }) const bgColorRgb = result[0].color const bgColorNum = bgColorRgb.split('rgb(')[1].slice(0, -1) const splitArr = bgColorNum.split(',') const hex = getHex(Number(splitArr[0]), Number(splitArr[1]), Number(splitArr[2])) if (!userSetColor?.value) { setFrontColor('#' + hex) } } catch {} // console.timeEnd() // const canvas = document.createElement('canvas') // const maxVal = getRgba(canvas, this) // console.log('maxVal:', maxVal) // const splitArr = maxVal.split(',') // const hex = getHex(Number(splitArr[0]), Number(splitArr[1]), Number(splitArr[2])) // if (!userSetColor?.value) { // setFrontColor('#' + hex) // } } resolve(img) } img.onerror = () => { console.log('img error') reject() } img.onabort = () => { console.log('img aborted') reject() } }) } return image } const imageWorker = new TintImageWorker() const drawing = ref(false) const dataUrl = ref('') imageWorker.addEventListener('message', (e) => { const data = e.data as MessageData drawing.value = data.drawing dataUrl.value = data.blob ? URL.createObjectURL(data.blob) : '' }) watch( [ () => option.value?.image, () => option.value?.distance, () => option.value?.basePoint, () => option.value?.enableSharpen, ], () => { nextTick(() => { const opt = unref(option) if (!opt.image) { drawing.value = false dataUrl.value = '' return } initImage({ image: opt.image, frontColor, setFrontColor }) .then((image) => { if (!image) return createImageBitmap(image).then((imageBitMap) => { imageWorker.postMessage( { type: 'init', imageBitMap, basePoint: opt.basePoint, enableSharpen: opt.enableSharpen, distance: opt.distance, scale: opt.scale, rotate: opt.rotate, }, [imageBitMap] ) }) }) .catch((err: any) => { drawing.value = false dataUrl.value = '' console.log('initImage catch err') }) }) }, { immediate: true } ) watch( () => option.value.scale, () => { imageWorker.postMessage({ type: 'scale', scale: option.value?.scale }) } ) watch( () => option.value.rotate, () => { imageWorker.postMessage({ type: 'rotate', rotate: option.value?.rotate }) } ) watch(dataUrl, (current, prev) => { const imgWrapDom = document.querySelector('.img-wrap') if (imgWrapDom) { setTimeout(() => { imgWrapDom.scrollTop = 0 }, 10) } if (prev) { try { URL.revokeObjectURL(prev) } catch (error) {} } }) onScopeDispose(() => { if (dataUrl.value) { try { URL.revokeObjectURL(dataUrl.value) } catch (error) {} } imageWorker.terminate() }) return { drawing, dataUrl, } }