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

如何在Deno/TypeScript生成的JPEG图片上添加尺寸标记?

在生成的图片上添加尺寸标记的方案(基于你的Deno/TypeScript代码)

由于你当前使用的jpegts库仅提供基础JPEG编码功能,没有内置文本渲染API,我们需要通过手动操作像素数组的方式绘制尺寸标记。下面是修改后的完整代码,实现了在图片右下角添加W×H格式的尺寸文本:

// Import jpeg encoder
import { encode as pixelsToBin } from "https://deno.land/x/jpegts@1.1/mod.ts";
// Import std base64 encoder
import { encode as binTob64 } from "https://deno.land/std/encoding/base64.ts";

// Material Design Colors | Range 500
const COLORS = {
  RED: "#f44336",
  GREEN: "#4caf50",
  BLUE: "#2196f3",
};

// 简单的8x8单色字体:仅包含数字和×符号
const FONT_8X8 = {
  '0': [0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x63, 0x3E, 0x00],
  '1': [0x1C, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00],
  '2': [0x3E, 0x63, 0x03, 0x1E, 0x60, 0x63, 0x3F, 0x00],
  '3': [0x3E, 0x63, 0x03, 0x1E, 0x03, 0x63, 0x3E, 0x00],
  '4': [0x06, 0x0E, 0x16, 0x36, 0x7F, 0x06, 0x06, 0x00],
  '5': [0x3F, 0x60, 0x60, 0x3E, 0x03, 0x63, 0x3E, 0x00],
  '6': [0x3E, 0x63, 0x60, 0x3E, 0x63, 0x63, 0x3E, 0x00],
  '7': [0x3F, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x00],
  '8': [0x3E, 0x63, 0x63, 0x3E, 0x63, 0x63, 0x3E, 0x00],
  '9': [0x3E, 0x63, 0x63, 0x3F, 0x03, 0x03, 0x3E, 0x00],
  '×': [0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00],
};

// Convert HEX color to RGB color
function hexToRgb(cHex: string): [number, number, number] {
  const r = parseInt(cHex.slice(1, 3), 16);
  const g = parseInt(cHex.slice(3, 5), 16);
  const b = parseInt(cHex.slice(5, 7), 16);
  return [r, g, b];
}

// 在像素数组中绘制8x8字体的文本
function drawText(
  pixels: number[],
  width: number,
  height: number,
  text: string,
  textColor: [number, number, number],
  x: number,
  y: number
) {
  // 遍历每个字符
  for (let charIndex = 0; charIndex < text.length; charIndex++) {
    const char = text[charIndex];
    const charData = FONT_8X8[char];
    if (!charData) continue;

    // 遍历字符的每个像素行
    for (let row = 0; row < 8; row++) {
      const rowData = charData[row];
      // 遍历行内的每个像素
      for (let col = 0; col < 8; col++) {
        // 判断当前像素是否需要绘制(字体数据中对应位为1)
        if (rowData & (1 << (7 - col))) {
          const pixelPos = ((y + row) * width + (x + charIndex * 8 + col)) * 4;
          // 确保像素位置在图片范围内
          if (pixelPos + 3 < pixels.length) {
            pixels[pixelPos] = textColor[0];     // R
            pixels[pixelPos + 1] = textColor[1]; // G
            pixels[pixelPos + 2] = textColor[2]; // B
            pixels[pixelPos + 3] = 1;            // Alpha(JPEG忽略)
          }
        }
      }
    }
  }
}

async function saveJpeg(w: number, h: number, cHex: string, fileName: string) {
  const jpegWidth = w;
  const jpegHeight = h;
  const jpegArea = jpegWidth * jpegHeight;
  const bgColor = hexToRgb(cHex);
  // 文本用白色,和深色背景对比明显;如果背景是浅色,可改成黑色[0,0,0]
  const textColor: [number, number, number] = [255, 255, 255];

  // 初始化背景像素数组
  let jpegPixels: number[] = [];
  for (let i = 0; i < jpegArea; i++) {
    jpegPixels.push(bgColor[0]);
    jpegPixels.push(bgColor[1]);
    jpegPixels.push(bgColor[2]);
    jpegPixels.push(1);
  }

  // 绘制尺寸文本到右下角,预留10像素边距
  const text = `${w}×${h}`;
  const textX = jpegWidth - text.length * 8 - 10;
  const textY = jpegHeight - 8 - 10;
  drawText(jpegPixels, jpegWidth, jpegHeight, text, textColor, textX, textY);

  // 编码并保存图片
  const jpegImage = {
    width: jpegWidth,
    height: jpegHeight,
    data: new Uint8Array(jpegPixels)
  };
  const jpegRaw = pixelsToBin(jpegImage, 100);
  await Deno.writeFile(`${fileName}.jpg`, jpegRaw.data);
}

// 示例调用
await saveJpeg(640, 360, COLORS.RED, "red-500");
await saveJpeg(640, 360, COLORS.GREEN, "green-500");
await saveJpeg(640, 360, COLORS.BLUE, "blue-500");

关键说明

  • 字体定义:用8x8二进制数据定义了数字和×符号的像素图案,每个字节代表一行的像素状态
  • 文本绘制逻辑:drawText函数遍历文本字符,将字体像素数据覆盖到背景像素数组的对应位置
  • 位置控制:尺寸文本固定绘制在右下角,通过计算预留10像素边距,避免超出图片范围
  • 颜色适配:默认用白色文本,若使用浅色背景,直接修改textColor为黑色即可保证可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:48:20