Skip to content

Commit

Permalink
feat: add blur hash
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Aug 16, 2024
1 parent 8a4a30f commit 8fbfa66
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 6 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@xterm/addon-fit": "0.10.0",
"@xterm/xterm": "5.5.0",
"ansi_up": "6.0.2",
"blurhash": "2.0.5",
"buffer": "6.0.3",
"canvas-confetti": "1.9.3",
"class-transformer": "0.5.1",
Expand Down Expand Up @@ -127,5 +128,6 @@
"vite-plugin-wasm": "3.3.0",
"vite-tsconfig-paths": "4.3.2",
"windicss": "3.5.6"
}
}
},
"packageManager": "[email protected]"
}
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 44 additions & 2 deletions src/components/drawer/components/image-detail-section.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { decode } from 'blurhash'
import { uniqBy } from 'lodash-es'
import {
NButton,
Expand All @@ -10,11 +11,12 @@ import {
NInput,
NInputNumber,
} from 'naive-ui'
import { getDominantColor } from '~/utils/image'
import { isVideoExt, pickImagesFromMarkdown } from '~/utils/markdown'
import type { Image as ImageModel } from '~/models/base'
import type { PropType } from 'vue'

import { getBlurHash, getDominantColor } from '~/utils/image'
import { isVideoExt, pickImagesFromMarkdown } from '~/utils/markdown'

export const ImageDetailSection = defineComponent({
props: {
images: {
Expand Down Expand Up @@ -57,6 +59,7 @@ export const ImageDetailSection = defineComponent({
width: existImageInfo?.width,
type: existImageInfo?.type,
accent: existImageInfo?.accent,
blurHash: existImageInfo?.blurHash,
} as any
})
.concat(props.images),
Expand Down Expand Up @@ -127,6 +130,7 @@ export const ImageDetailSection = defineComponent({
src: item.src,
type: ext,
accent: getDominantColor($image),
blurHash: getBlurHash($image),
})
})
$image.onerror = (err) => {
Expand Down Expand Up @@ -232,6 +236,14 @@ export const ImageDetailSection = defineComponent({
></NColorPicker>
</NFormItem>

<NFormItem label="Blur Preview">
<div>
{image.blurHash && (
<BlurHashPreview hash={image.blurHash} />
)}
</div>
</NFormItem>

<NFormItem label="操作">
<div class="flex w-full justify-end">
<NButtonGroup>
Expand Down Expand Up @@ -267,3 +279,33 @@ export const ImageDetailSection = defineComponent({
)
},
})

const BlurHashPreview = defineComponent({
props: {
hash: {
type: String,
required: true,
},
},
setup(props) {
const canvasRef = ref<HTMLCanvasElement | null>(null)

onMounted(() => {
const canvas = canvasRef.value!
const ctx = canvas.getContext('2d')!
const pixels = decode(props.hash, 32, 32)
const imageData = ctx.createImageData(32, 32)
imageData.data.set(pixels)
ctx.putImageData(imageData, 0, 0)
})

return () => (
<canvas
ref={canvasRef}
class="bg-cover bg-center"
height={32}
width={32}
></canvas>
)
},
})
1 change: 1 addition & 0 deletions src/models/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Image {
type: string
accent?: string
src: string
blurHash?: string
}

export class BaseModel {
Expand Down
22 changes: 20 additions & 2 deletions src/utils/image.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// @see https://stackoverflow.com/questions/2541481/get-average-color-of-image-via-javascript
// @ts-nocheck

import { encode } from 'blurhash'

export function getDominantColor(imageObject: HTMLImageElement) {
const canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d')
ctx = canvas.getContext('2d')!

canvas.width = 1
canvas.height = 1
Expand All @@ -26,3 +27,20 @@ export function rgbToHex(red: number, green: number, blue: number) {
export function rgbObjectToHex(rgb: { r: number; g: number; b: number }) {
return rgbToHex(rgb.r, rgb.g, rgb.b)
}

export function getBlurHash(imageObject: HTMLImageElement) {
const canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d')!

canvas.width = imageObject.naturalWidth
canvas.height = imageObject.naturalHeight

ctx.drawImage(imageObject, 0, 0)

const imageData = ctx.getImageData(0, 0, 32, 32)
const pixels = new Uint8ClampedArray(imageData.data)
const componentX = 4
const componentY = 4

return encode(pixels, 32, 32, componentX, componentY)
}

0 comments on commit 8fbfa66

Please sign in to comment.