Skip to content

Pixelate 像素化

基于 Canvas 的图片像素化组件。可将任意图片转换为像素风格,支持可配置的像素块大小、灰度模式以及自定义调色板映射。

灵感来源:Pixelium DesignPixel-UI Pixelit

NOTE

示例图片没有特别含义,仅作为展示像素化效果的彩色样本。

名称分类说明类型默认值
pixelSize? 风格像素块大小(值越大越像素化)number8
grayscale? 风格启用灰度模式booleanfalse
width? 尺寸组件宽度number | string
height? 尺寸组件高度number | string
palette? 颜色自定义调色板(十六进制字符串或 RGB 元组)string[] | number[][]
background? 颜色透明区域的背景色string'#FFFFFF'
src? 内容图片源地址或 base64string
rendered? 事件像素化渲染完成后触发() => void
error? 事件图片加载失败时触发(event: Event) => void
canvasRef? 暴露Canvas 元素引用HTMLCanvasElement
originRef? 暴露隐藏的原始图片元素引用HTMLImageElement
render()? 方法手动触发重新渲染() => void
getSize()? 方法获取渲染后的画布尺寸() => { width: number; height: number }
getImageData()? 方法获取像素化后的 ImageData() => ImageData | null

基础用法

传入图片 src 即可使用默认像素大小(8)进行像素化处理。

<template>
  <div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end">
    <px-pixelate src="/images/pixelate/001.png" :width="400" />
  </div>
</template>

像素大小

通过 pixel-size 控制像素化程度。值越大,像素块越大,像素化效果越明显。

<template>
  <div>
    <div style="margin-bottom: 12px">
      <label>Pixel Size: {{ pixelSize }}</label>
      <input type="range" v-model.number="pixelSize" min="1" max="32" style="margin-left: 8px" />
    </div>
    <px-pixelate src="/images/pixelate/001.png" :pixel-size="pixelSize" :width="400" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const pixelSize = ref(8);
</script>

灰度模式

启用 grayscale 属性,可将像素化输出转换为灰度图像(使用 ITU-R BT.601 亮度公式)。

<template>
  <div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end">
    <div>
      <p style="margin-bottom: 8px">Original</p>
      <px-pixelate src="/images/pixelate/002.jpg" :pixel-size="4" :width="300" />
    </div>
    <div>
      <p style="margin-bottom: 8px">Grayscale</p>
      <px-pixelate src="/images/pixelate/002.jpg" :pixel-size="4" grayscale :width="300" />
    </div>
  </div>
</template>

自定义调色板

通过 palette 属性将像素颜色映射到有限的颜色集合。支持十六进制字符串(如 '#FF0000')或 RGB 元组(如 [255, 0, 0])。每个像素块会映射到 RGB 空间中欧几里得距离最近的调色板颜色。

<template>
  <div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end">
    <div>
      <p style="margin-bottom: 8px">Original</p>
      <px-pixelate src="/images/pixelate/001.png" :pixel-size="4" :width="260" />
    </div>
    <div>
      <p style="margin-bottom: 8px">Game Boy Palette</p>
      <px-pixelate src="/images/pixelate/001.png" :pixel-size="4" :palette="gameboyPalette" :width="260" />
    </div>
    <div>
      <p style="margin-bottom: 8px">Sunset Palette</p>
      <px-pixelate src="/images/pixelate/001.png" :pixel-size="4" :palette="sunsetPalette" :width="260" />
    </div>
  </div>
</template>

<script setup lang="ts">
// Classic Game Boy green palette
const gameboyPalette = ['#0f380f', '#306230', '#8bac0f', '#9bbc0f'];

// Warm sunset palette
const sunsetPalette = ['#2b0f3e', '#5c2d82', '#c0392b', '#e67e22', '#f1c40f', '#ecf0f1'];
</script>

尺寸控制

使用 widthheight 属性控制渲染尺寸。接受数值(像素)或字符串(CSS 单位如 '50%')。

<template>
  <div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end">
    <div>
      <p style="margin-bottom: 8px">100 × 100</p>
      <px-pixelate src="/images/pixelate/002.jpg" :pixel-size="4" :width="100" :height="100" />
    </div>
    <div>
      <p style="margin-bottom: 8px">200 × 150</p>
      <px-pixelate src="/images/pixelate/002.jpg" :pixel-size="4" :width="200" :height="150" />
    </div>
    <div>
      <p style="margin-bottom: 8px">400 (auto height)</p>
      <px-pixelate src="/images/pixelate/002.jpg" :pixel-size="4" :width="400" />
    </div>
  </div>
</template>

暴露方法

通过模板引用访问组件实例,调用 render()getSize()getImageData() 方法。

<template>
  <div>
    <div style="margin-bottom: 12px; display: flex; gap: 8px; flex-wrap: wrap">
      <px-button type="primary" @click="reRender">Re-render</px-button>
      <px-button @click="showSize">Get Size</px-button>
      <px-button @click="showImageData">Get ImageData</px-button>
    </div>
    <p v-if="info" style="margin-bottom: 8px; font-family: monospace">{{ info }}</p>
    <px-pixelate ref="pixelateRef" src="/images/pixelate/001.png" :pixel-size="pixelSize" :width="400" />
  </div>
</template>

<script setup lang="ts">
import type { PixelateInstance } from 'sakana-element';
import { ref } from 'vue';

const pixelateRef = ref<PixelateInstance>();
const info = ref('');
const pixelSize = ref(8);

function reRender() {
  pixelSize.value = Math.max(1, Math.floor(Math.random() * 16) + 1);
  info.value = `Re-rendered with pixelSize = ${pixelSize.value}`;
}

function showSize() {
  const size = pixelateRef.value?.getSize();
  info.value = size ? `Canvas size: ${size.width} × ${size.height}` : 'Not rendered yet';
}

function showImageData() {
  const data = pixelateRef.value?.getImageData();
  info.value = data
    ? `ImageData: ${data.width} × ${data.height} (${data.data.length} bytes)`
    : 'No ImageData available';
}
</script>