123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- 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<string>
- 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<SetImgBgOption>, frontColor?: Ref<string>, 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<HTMLImageElement>(image)) {
- image = await new Promise<HTMLImageElement>((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<boolean>(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,
- }
- }
|