Base64 を BMP に変換する方法
- Base64 か
data:image/bmp;base64,...形式の URI 全体を貼り付けるか、文字列の入った.txtファイルを開きます。ビットマップなら数 MB の文字列も普通なので、ここでも問題なく扱えます。 - ステータス行の 検出 に BMP と表示されるはずです。プレビューには画像とピクセルサイズが表示され、サイズ にはデコード後のファイルサイズがバイト単位で表示されます。
- ファイルをダウンロード を押して
.bmpを保存します。
ブラウザは <img> で BMP をデコードでき、1 ビットのモノクロ、8 ビットのパレット、24 ビット、ほとんどの 32 ビットのファイルに対応しています。
幅と高さから分かる BMP のファイルサイズ
BMP は、14 バイトのファイルヘッダー、情報ヘッダー(一般的なバージョンで 40 バイト)、省略可能なパレット、そしてピクセルの行で構成されます。各行は 4 バイトの倍数になるよう埋められます。パレットのない 24 ビット画像なら次のとおりです。
file size = 54 + height × (width × 3, rounded up to a multiple of 4)
| 画像 | 1 行のサイズ | BMP ファイル | Base64 の長さ |
|---|---|---|---|
| 33×10、24 ビット | 99 → 100 バイト | 1,054 バイト | 1,408 文字 |
| 100×100、24 ビット | 300 バイト | 30,054 バイト | 40,072 文字 |
| 800×600、24 ビット | 2,400 バイト | 1,440,054 バイト | 1,920,072 文字 |
| 1920×1080、24 ビット | 5,760 バイト | 6,220,854 バイト | 8,294,472 文字 |
| 1920×1080、1 ビット | 240 バイト | 259,262 バイト | 345,684 文字 |
1 ビットの行には、8 バイトの 2 色パレットが加わります。数値が決まっているので、ビットマップは簡単に検証できます。ファイルヘッダーの 2~5 バイト目に合計サイズが入っていて、100×100 の例の 16進ダンプでは 66 75 00 00 となっています。リトルエンディアンの数値として読むと 0x7566 = 30,054 です。サイズ がそれより小さければ、Base64 が途中で切れています。BMP の行はデフォルトで下から上の順に格納されるので、途中で切れたビットマップは画像の上の部分が失われます。
BMP の Base64 の見た目
BMP はどれも BM という文字で始まるので、Base64 は Qk で始まります。3 文字目はファイルサイズによって 0、1、2、3 のいずれかになり、Qk02 や Qk1m がよく見られます。検出処理では 14 バイト目にある情報ヘッダーのサイズも確認するので、たまたま BM で始まるランダムなデータをビットマップと誤認することはありません。
ヘッダーのないビットマップ(DIB)
ファイルヘッダー BM のないビットマップを渡してくる場合もあります。これは DIB と呼ばれ、Windows のクリップボード(CF_DIB)、ICO ファイル内の画像、一部のデバイス SDK で使われる形式です。Base64 は KAAAA で始まります。これは 40 バイトの情報ヘッダーのサイズ 28 00 00 00 をエンコードしたものです。
ファイルヘッダーがないとバイト列は有効な画像ファイルにならないため、ツールはプレビューできず、バイナリデータと報告します。解決するには、足りない 14 バイトを前に付けます。
import base64, struct
def dib_to_bmp(dib: bytes) -> bytes:
header_size, = struct.unpack_from("<I", dib, 0)
bpp, = struct.unpack_from("<H", dib, 14)
compression, colors = struct.unpack_from("<I", dib, 16)[0], struct.unpack_from("<I", dib, 32)[0]
if bpp <= 8 and colors == 0:
colors = 1 << bpp
masks = 12 if header_size == 40 and compression == 3 else 0
offset = 14 + header_size + masks + colors * 4
return b"BM" + struct.pack("<IHHI", 14 + len(dib), 0, 0, offset) + dib
b64 = open("dib.txt").read()
with open("image.bmp", "wb") as f:
f.write(dib_to_bmp(base64.b64decode(b64)))
ヘッダーには、ファイルの合計サイズと、ピクセルデータのオフセットが必要です。ピクセルデータは情報ヘッダー、16 ビットと 32 ビットのビットフィールド画像のカラーマスク、パレットの後に続きます。テキストとして必要なら、結果を BMP を Base64 に変換 で再エンコードするか、ここで確認してください。ICO ファイルから取り出した DIB は特殊で、透過マスクの分だけ高さが 2 倍になっています。バイナリデータのデコードについては Python での Base64 で詳しく解説しています。
よくある問題
- 「これは BMP ではなく PNG のようです。」 送信側ですでに画像が変換されているか、システム上でビットマップと呼んでいるだけです。.png としてダウンロード で PNG として保存してください。サイズが小さく、どのプログラムでも読めます。
- 別のプログラムで色が入れ替わって見える、または画像が上下逆になる。 BMP はピクセルを青・緑・赤の順で、通常は下から上に格納します。ヘッダーの高さが負の値なら、行は上から下の順です。ブラウザはこれらをすべて処理しますが、簡易的な独自リーダーでは対応していないことがあります。
- デバイスがデコードしたファイルを受け付けない。 デバイスが受け取ったものと SHA-256 を比べてから、16進ダンプでビット深度とヘッダーのバージョンを確認してください。古いリーダーは 40 バイトのヘッダー(オフセット 14 に
28 00 00 00)で、アルファチャンネルがないことを前提にしています。
よくある質問
ビットマップの Base64 文字列がこんなに長いのはなぜですか?
BMP は生のピクセルを無圧縮で保存するからです。1920×1080 の 24 ビットビットマップは、何が写っていても 6,220,854 バイト、Base64 にすると 8,294,472 文字になります。
Base64 が Qk ではなく KAAAA で始まっています。これは何ですか?
14 バイトのファイルヘッダーがないビットマップで、DIB と呼ばれます。Windows のクリップボード、一部のデバイス SDK、ICO ファイルから出てきます。このページの Python スニペットでヘッダーを付ければ、通常の .bmp になります。
BMP の文字列が完全かどうかを確かめるには?
ファイルの 2~5 バイト目に合計サイズが入っています。16進ダンプを表示 を開き、その値をリトルエンディアンの数値として読んで、サイズ の行と比べてください。デコード後のサイズのほうが小さければ、文字列が途中で切れています。
BMP ではなく PNG で受け取れますか?
このページはビットマップをそのまま保存します。変換したい場合は、ダウンロードしたファイルを BMP を Base64 に変換 にドロップし、変換先 を PNG にしてください。PNG は可逆圧縮で、たいていはずっと小さくなります。