如何在Deno中获取Base64图片的宽高?
在Deno边缘函数中从Base64提取图片宽高(无依赖方案)
问题背景
需要在Deno边缘函数中实现从Base64编码的图片里读取宽高的功能,Deno不支持浏览器的new Image()方法,且要尽可能减少依赖。之前尝试的两个方案都有问题:
- skia_canvas:边缘环境不允许其所需的写入权限
- ImageScript:不清楚对应的Deno导入地址
无依赖原生实现方案
可以直接解析Base64对应的二进制数据,读取图片文件头里的宽高信息,无需任何第三方依赖。以下是针对常见PNG、JPG格式的解析代码:
步骤1:Base64转Uint8Array
先把Base64字符串转换成二进制数组:
function base64ToUint8Array(base64: string): Uint8Array { const binaryString = atob(base64.replace(/^data:image\/(png|jpeg|jpg);base64,/, '')); const len = binaryString.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; }
步骤2:解析PNG宽高
PNG的宽高存储在文件头后的IHDR块中,是4字节大端整数:
function getPngDimensions(bytes: Uint8Array): { width: number, height: number } | null { // 验证PNG签名(前8字节) const pngSignature = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]); if (!bytes.slice(0, 8).every((b, i) => b === pngSignature[i])) { return null; } // IHDR块从第16字节开始,宽高各占4字节(大端) const width = (bytes[16] << 24) | (bytes[17] << 16) | (bytes[18] << 8) | bytes[19]; const height = (bytes[20] << 24) | (bytes[21] << 16) | (bytes[22] << 8) | bytes[23]; return { width, height }; }
步骤3:解析JPG宽高
JPG采用分段结构,宽高存储在SOF0(0xC0)或SOF2(0xC2)段中:
function getJpgDimensions(bytes: Uint8Array): { width: number, height: number } | null { let i = 0; // 验证JPG签名(前2字节) if (bytes[i] !== 0xFF || bytes[i+1] !== 0xD8) { return null; } i += 2; // 遍历所有段 while (i < bytes.length) { if (bytes[i] !== 0xFF) { return null; // 无效的JPG结构 } const marker = bytes[i+1]; // 跳过SOI(0xD8)和EOI(0xD9)以外的段 if (marker === 0xC0 || marker === 0xC2) { // SOF0或SOF2段包含宽高 // 段长度占2字节,跳过长度和其他字段(共5字节) i += 5; // 高度是2字节大端 const height = (bytes[i] << 8) | bytes[i+1]; // 宽度是2字节大端 const width = (bytes[i+2] << 8) | bytes[i+3]; return { width, height }; } else { // 计算当前段的长度,跳过整个段 const segmentLength = (bytes[i+2] << 8) | bytes[i+3]; i += 2 + segmentLength; } } return null; }
整合函数
把上面的函数整合,自动判断图片格式并返回宽高:
function getImageDimensionsFromBase64(base64: string): { width: number, height: number } | null { const bytes = base64ToUint8Array(base64); // 先尝试PNG解析 const pngDim = getPngDimensions(bytes); if (pngDim) return pngDim; // 再尝试JPG解析 const jpgDim = getJpgDimensions(bytes); if (jpgDim) return jpgDim; // 不支持的格式 return null; }
可选:使用ImageScript(如果环境允许)
ImageScript的Deno导入地址为https://deno.land/x/imagescript@1.2.15/mod.ts,示例代码如下:
import { Image } from "https://deno.land/x/imagescript@1.2.15/mod.ts"; async function getDimensionsWithImageScript(base64: string) { const binary = atob(base64.replace(/^data:image\/(png|jpeg|jpg);base64,/, '')); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i); const image = await Image.decode(bytes); return { width: image.width, height: image.height }; }
内容的提问来源于stack exchange,提问作者Alita
相关产品推荐
相关产品推荐

