You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在TypeScript Deno中将ReadableStream<Uint8Array>转为Uint8ClampedArray

解决方案

首先要明确:你通过fetch获取到的ReadableStream<Uint8Array>是图片文件的原始二进制数据(比如JPG/PNG格式的字节),并非BlurHash所需的像素数组(RGBA格式,长度为宽×高×4)。直接将其传入BlurHash会因尺寸不匹配报错,必须先解码图片得到像素数据,再转换为Uint8ClampedArray。

由于Deno无浏览器document环境,无法使用原生Canvas,可通过以下两种方式解决:


方法一:使用Deno第三方Canvas库(通用方案)

借助deno.land/x/canvas实现类似浏览器的图片解码与像素提取,步骤如下:

1. 实现流转Uint8Array工具函数

先将ReadableStream合并为完整的图片二进制数组:

async function streamToUint8Array(stream: ReadableStream<Uint8Array>): Promise<Uint8Array> {
  const reader = stream.getReader();
  const chunks: Uint8Array[] = [];
  let result;
  while (!(result = await reader.read()).done) {
    chunks.push(result.value);
  }
  // 合并所有分片
  const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
  const merged = new Uint8Array(totalLength);
  let offset = 0;
  for (const chunk of chunks) {
    merged.set(chunk, offset);
    offset += chunk.length;
  }
  return merged;
}

2. 解码图片并获取像素数据

通过Canvas库加载图片,提取RGBA格式的Uint8ClampedArray:

import { createCanvas, loadImage } from "https://deno.land/x/canvas@v1.4.1/mod.ts";

async function getImagePixels(stream: ReadableStream<Uint8Array>): Promise<{
  width: number;
  height: number;
  data: Uint8ClampedArray;
}> {
  const imageBuffer = await streamToUint8Array(stream);
  const image = await loadImage(imageBuffer);
  
  const canvas = createCanvas(image.width, image.height);
  const ctx = canvas.getContext("2d");
  if (!ctx) throw new Error("无法获取Canvas上下文");
  
  ctx.drawImage(image, 0, 0);
  const imageData = ctx.getImageData(0, 0, image.width, image.height);
  
  return {
    width: image.width,
    height: image.height,
    data: imageData.data // 这就是所需的Uint8ClampedArray
  };
}

3. 生成BlurHash

将获取到的像素数据传入BlurHash编码函数:

import { encode } from "https://deno.land/x/blurhash@v1.1.2/mod.ts";

// 假设你已获取到图片流
const imageStream = (await fetch("你的图片URL")).body!;
const { width, height, data } = await getImagePixels(imageStream);
const blurhash = encode(data, width, height, 4, 4); // 最后两个参数为组件数量,可按需调整

方法二:针对特定图片格式解码(轻量方案)

如果仅处理单一格式(如JPG),可使用专用解码库,避免引入Canvas依赖。以JPG为例:

import { decode } from "https://deno.land/x/jpeg_decoder@v0.1.2/mod.ts";
import { streamToUint8Array } from "./你的工具文件.ts";

async function getJpegPixels(stream: ReadableStream<Uint8Array>): Promise<{
  width: number;
  height: number;
  data: Uint8ClampedArray;
}> {
  const buffer = await streamToUint8Array(stream);
  const decoded = decode(buffer);
  
  // 将JPG的RGB数据转换为RGBA格式(添加Alpha通道,默认不透明)
  const rgbaData = new Uint8ClampedArray(decoded.width * decoded.height * 4);
  for (let i = 0; i < decoded.data.length; i += 3) {
    const rgbaIndex = (i / 3) * 4;
    rgbaData[rgbaIndex] = decoded.data[i];     // R
    rgbaData[rgbaIndex + 1] = decoded.data[i + 1]; // G
    rgbaData[rgbaIndex + 2] = decoded.data[i + 2]; // B
    rgbaData[rgbaIndex + 3] = 255;            // Alpha(不透明)
  }
  
  return {
    width: decoded.width,
    height: decoded.height,
    data: rgbaData
  };
}

关于Uint8Array转Uint8ClampedArray

如果你的Uint8Array已经是像素数据(而非图片二进制),可直接转换:

const uint8Array = new Uint8Array([255, 0, 0, 255]);
const uint8Clamped = new Uint8ClampedArray(uint8Array);

但此操作仅适用于已解码的像素数组,不能直接用于图片文件的二进制数据。

内容的提问来源于stack exchange,提问作者progNewbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:15:01