Base64转图片转换器

粘贴 Data URL 或纯 base64,先 atob 解码成字节,再用魔术字节嗅探真实类型后预览——声明的 MIME 与实际不符会直接报错。

本页用 Ctrl / Cmd + Enter 触发也可以;下方魔数对照表默认 12 行,「加载更多」展开其余行。

尚未解码
魔术字节对照表(嗅探按表内顺序短路匹配)
格式魔术字节(十六进制)说明
JPEGFF D8 FF前 3 字节即可判定,JFIF/EXIF 共用
PNG89 50 4E 47 0D 0A 1A 0A8 字节签名,含 CR LF 与退出符
GIF47 49 46 38即 ASCII「GIF8」,GIF87a/GIF89a 共用
BMP42 4D即 ASCII「BM」
WebP52 49 46 46 … 57 45 42 50RIFF 容器,第 8-11 字节才是「WEBP」
ICO00 00 01 00图标格式,浏览器 <img> 可直接显示
TIFF(小端)49 49 2A 00即 ASCII「II*\0」,浏览器普遍不显示
TIFF(大端)4D 4D 00 2A即 ASCII「MM\0*」,与字节序有关
AVIF66 74 79 70 + 偏移 8 处 avifftyp box,品牌名决定具体格式
HEIC66 74 79 70 + 偏移 8 处 heic同为 ftyp box,多数浏览器不支持
PDF25 50 44 46即「%PDF」,不是图片,本页拒绝
SVG文本 <svg 开头文本格式没有魔术字节,本页不处理

使用方法

  1. 把 base64 内容粘进输入框。两种形态都认:完整的 Data URL(以 data:image/png;base64, 开头),或不含前缀的纯 base64 字符串。打开页面时已预置一张 10×10 的示例 PNG,点「解码预览」直接出图。
  2. 点「解码预览」或按 Ctrl / Cmd + Enter。Base64转图片转换器会在右侧显示图片,信息栏给出嗅探类型、解码后 78 字节、base64 长 104 字符这三组数。
  3. 点「下载图片」把解码结果存成 .png 文件——嗅探出什么类型就存什么扩展名,与 Data URL 里声明的是什么无关。
  4. 解码失败时看红色错误区:会指出第一个非法字符的位置、缺没缺补位 =、或者声明 MIME 与魔术字节是否矛盾。
  5. 想核对一个串是什么格式但不需要预览,直接看下方魔术字节对照表,前几个十六进制字节对上哪行就是哪行。

Base64转图片转换器能解决什么问题

第一个场景是调试内嵌图片。CSS 里 background-image:url(data:image/png;base64,…) 或接口返回的 base64 字段到底是不是一张合法图、是什么格式,粘进来立刻见分晓——尤其当声明的 MIME 是猜的、复制时丢了尾巴的时候,本页会明确告诉你哪一环断了。

第二个场景是恢复图片文件。手里只有一段 base64(日志、数据库字段、前端传参)需要还原成 .png/.jpg 文件时,下载按钮按嗅探结果给正确的扩展名,而不是盲信来源标注。

第三个场景是校验「声明与内容一致」。把 Content-Type 标成 image/png 实际塞了 HTML 的响应是常见的安全问题,本页按字节而不是按声明判定类型,声明与嗅探不符会直接报错。

本页只做「base64 → 图片」这一个方向。要把图片编码成 base64,走反方向的图片转Base64转换器;只做文本与 base64 互转的走Base64URL编码解码,那页处理的是文本编码不是二进制图片。

原理与规则说明

Data URL 的结构由 RFC 2397 定义:data:image/png;base64, 三段——「data:」协议头、MIME 类型、「;base64」编码标记,逗号之后才是数据。缺逗号、缺 base64 标记都会被逐条拦截;URL 编码形态(data:,xxx)属于另一套语法,本页不处理。

解码链路是 atob → 二进制字符串 → Uint8Array。atob() 的返回值是「每个字符码位 0-255 的字符串」,不是字节数组,直接把它当图片数据用必然出错。必须经 Uint8Array.from(bin, c => c.charCodeAt(0)) 逐字符取码位转成字节数组,再包进 Blob。字符数等于字节数这一步可以用来核对:示例载荷 104 字符,解码后正好 78 字节。

字节量按 RFC 4648 换算:字节数 = base64 长度 × 3/4 − 补位「=」个数。每 3 个字节编码成 4 个字符,这就是 base64 体积恒定膨胀 4/3 ≈ 133.33% 的来源——示例 78 字节膨胀成 104 字符,104/78 = 1.3333,分毫不差。

类型判定靠魔术字节嗅探,不信任声明。PNG 前 8 字节固定是 89 50 4E 47 0D 0A 1A 0A(十进制 137 80 78 71 13 10 26 10),JPEG 是 FF D8 FF,示例串解码后前 8 字节正好是这组数,所以判定为 image/png。PNG 的宽高也不要解析器猜:IHDR 块的第 16-19 字节是宽、20-23 字节是高,按大端序(network byte order)读,这是 PNG 规范强制的字节序,示例读出 10×10。

预览用 Blob URL:URL.createObjectURL(new Blob([bytes], { type: 嗅探结果 })) 生成 blob: 链接交给 <img>。每次解码都会新建一个 Blob 占住内存,所以本页在下次解码和换示例时对上一次的 URL 调 revokeObjectURL 释放。

完整示例(数值仅作演示)

预置示例是一张真实的 10×10 像素 PNG,整条 Data URL 已写在输入框里:

这三个数字(104、78、10×10)与解码后的图片三处互相咬合:字符数、字节数、像素宽高,换任何一张 PNG 都能用同一套公式验算。

输入范围与对照表

本页接受两种输入形态;载荷长度必须是 4 的倍数(RFC 4648 的填充规则),字符集限 A-Z a-z 0-9 + / 与末尾补位 =。解码结果超过 2 MB(对应 base64 长 2796204 字符)直接拒绝——atob 处理兆级字符串会卡住标签页数秒。嗅探按下方表序短路匹配,前两字节就足够区分 JPEG/PNG/GIF/BMP 这四类高频格式:

格式前几字节(十进制)十六进制
PNG137 80 78 7189 50 4E 47
JPEG255 216 255FF D8 FF
GIF71 73 70 5647 49 46 38
BMP66 7742 4D
WebP82 73 70 70 …(偏移 8)52 49 46 46 … 57 45 42 50
ICO0 0 1 000 00 01 00

完整 14 行对照表在工具区,含 TIFF 双字节序、AVIF/HEIC 的 ftyp box 与「看着像图但被拒绝」的 PDF/PSD,默认 12 行、可加载更多、可导出 CSV。

输入范围、边界与精度说明

声明 MIME 与嗅探结果不一致是硬报错,不是警告。data:image/png 声明后面跟一段 JPEG 字节,说明这条串在生成或传输中被动过手脚;直接预览等于替坏数据背书。本页的报错会同时给出两个值让你自查来源。

URL-safe base64 不认。Base64URL 变体把 + 换成 -、/ 换成 _(RFC 4648 第 5 节),用于 URL 场景。本页按标准字母表校验,遇到 - 或 _ 会指出第几个字符非法并提示先替换回 + 和 /——因为图片数据的来源通常是标准编码,静默兼容两种字母表反而掩盖「串被 URL 处理污染」的事实。

补位的两种病:长度不是 4 的倍数(漏抄字符),或 = 出现在中间(复制时混入换行处理错误)。atob 对前者直接抛 InvalidCharacterError,本页把它翻译成「检查是否漏抄了末尾的 =」。空白字符(换行、空格)会被静默剥除——邮件、JSON 里折行的 base64 很常见,这不算脏数据。

2 MB 上限的依据:解码结果 2097152 字节对应 base64 长 2796204 字符。这是交互体验阈值不是能力上限——V8 的字符串上限远高于此,但 atob 是同步操作,兆级输入会冻结页面主线程。更大的图片请走「图片压缩」类工具先缩小再编码。

内存释放:每个 Blob URL 都占用解码后的完整字节,图片反复解码会累积。本页在覆盖预览前 revoke 上一个 URL;如果你在自己的代码里做同样的事,记得 blob: 链接不会因为 img 被移除而自动释放。

常见问题

为什么我声明的 image/png,本页却说它是 JPEG?

因为类型判定看字节不看声明。Data URL 的 MIME 部分是写入时的标注,复制粘贴、接口转手时经常被默认值污染。PNG 签名是 89 50 4E 47 开头,JPEG 是 FF D8 FF 开头,两者不可能混淆。本页以嗅探为准并报错提醒,图片该存成什么扩展名也以嗅探结果为准。

atob 直接返回的不就是字节数组吗?为什么还要转 Uint8Array?

atob 返回的是 JavaScript 字符串,每个字符的码位恰好 0-255,看起来像字节但类型是 string。Blob 构造函数收到字符串时会按 UTF-8 重新编码,码位大于 127 的字符会被拆成多字节,图片数据就此损坏。必须用 Uint8Array.from(bin, c => c.charCodeAt(0)) 把码位原样转成字节。这是 base64 解码最常见的踩坑点,没有之一。

base64 为什么会让图片变大三分之一?有没有办法避免?

base64 把每 3 字节(24 位)重排成 4 个字符(也是 24 位信息),但字符在存储里各占 1 字节,所以 3 字节变 4 字节,恒定 +33.33%。这是编码机制的数学下限,任何工具都绕不开。避免办法是别内嵌:把图片当独立文件传输。小图标内嵌省一次请求、大图内嵌纯亏,分界线通常在几 KB。

解码成功但图片显示不出来,是什么问题?

先看嗅探结果:如果是 TIFF、HEIC 这类浏览器不渲染的格式,字节是好的、<img> 不认,下载后用本地看图软件能打开。如果嗅探也不认识,前 4 字节不在魔数表里,多半是损坏或被二次编码过的数据。另外 SVG 是文本格式没有魔术字节,本页按设计不处理它。

带换行的 base64(邮件里那种每 76 字符一折)能直接解吗?

能。本页在解码前剥除所有空白字符,RFC 4648 本身也要求解码器容忍换行。剥除后重新校验长度是否为 4 的倍数与字符集合法性,所以折行不会导致误判——但折行处如果被邮件客户端插入了别的文字,第一个非法字符的报错会精确指出位置。

URL-safe base64 的 - 和 _ 为什么不直接兼容?

因为两种字母表的混用是错误信号。标准 base64 里的 + / 在 URL 里有特殊含义,所以出现了替换版;一段数据用了哪种字母表取决于编码方。如果解码器静默兼容,被 URL 传输污染过的串(+ 变空格等)会被错误地「修复」,你拿到的是一张坏图还以为没问题。本页选择报错并告诉你替换规则,30 秒就能手动修好。

解码后怎么知道图片的宽高?要真的显示出来才能知道吗?

PNG 不需要。IHDR 块固定紧跟在 8 字节签名后,宽是第 16-19 字节、高是 20-23 字节,按大端序读。示例在第 16-19 字节读到 0,0,0,10 即 10。JPEG 的宽高藏在 SOF0 帧里,要按 0xFF 0xC0 标记扫段,逻辑复杂一些,本页对 JPEG 直接用浏览器解码后的自然尺寸显示。

这个工具和站内的图片转 Base64、Base64URL 编码解码是什么关系?

三个页面方向和对象都不同。本页是「二进制图片 ← base64 字符串」的还原与嗅探,Base64转图片转换器的核心价值就在「按字节判定」这四个字上;图片转Base64转换器是反向,从本地图片文件生成 Data URL;Base64URL编码解码处理的是文本而非二进制,字母表也不同。要还原图片回本页,要生成 Data URL 去图片转 Base64 那页。

相关工具