目次
画像をAPIに送るとき、JWTトークンを見るとき、メールの添付ファイルを扱うとき——Base64は至る所で使われている。「なぜわざわざテキストに変換するのか」という理由を理解すると、マルチモーダルAIのAPIの設計思想も見えてくる。
なぜバイナリをテキストに変換するのか
コンピュータのデータはすべてバイナリ(0と1の羅列)だが、テキストを前提に設計されたシステムはバイナリデータを正しく扱えないことがある。
問題の具体例:
- メール(SMTP): 歴史的に7ビットASCIIテキストのみを扱う設計
- JSON/HTTP ヘッダー: テキスト形式のため、バイナリを直接埋め込めない
- URL: 使える文字に制限がある(特殊文字はエスケープ必要)
- データベース: TEXT型のカラムにバイナリを直接格納できない
Base64はバイナリデータを「テキスト安全な文字列」に変換することでこれらの問題を解決する。
Base64の仕組み
Base64は64種類の文字(A-Z, a-z, 0-9, +, /)を使ってバイナリを表現する。
変換プロセス:
1. バイナリデータを6ビットのグループに分割
2. 各6ビット(0〜63)を対応する文字に変換
3. 4文字(=24ビット)が3バイトに対応
4. 余りが出たら = でパディング
# Pythonでの実装確認
import base64
# テキストをBase64エンコード
text = "Hello, AI!"
encoded = base64.b64encode(text.encode('utf-8'))
print(encoded) # b'SGVsbG8sIEFJIQ=='
# デコード
decoded = base64.b64decode(encoded).decode('utf-8')
print(decoded) # Hello, AI!
# ファイル(バイナリ)をBase64に
with open("image.png", "rb") as f:
image_bytes = f.read()
image_b64 = base64.b64encode(image_bytes).decode('utf-8')
print(f"エンコード後: {len(image_b64)} 文字")
print(f"元のサイズ: {len(image_bytes)} バイト")
# Base64後は約33%大きくなる(4/3倍)
サイズのトレードオフ: Base64変換でデータサイズは約33%増加する。3バイトを4文字で表現するため(3×8=24ビット→4×6=24ビット、4文字)。
文字セットのバリアント
| バリアント | 文字 | 用途 |
|---|---|---|
| 標準 Base64 | A-Z a-z 0-9 + / | メール、一般 |
| URL安全 Base64 | A-Z a-z 0-9 - _ | URL、JWT |
| Base64(パディングなし) | 末尾の = を省略 | JWT など |
# URL安全なBase64(+ → -, / → _)
url_safe = base64.urlsafe_b64encode(b"\xfb\xff\xfe")
print(url_safe) # b'----' のような文字列(URLでも安全)
# パディングなし(JWTで使用)
no_pad = base64.urlsafe_b64encode(b"data").rstrip(b'=')
マルチモーダルAI APIでのBase64
GPT-4 Vision, Claude 3, Gemini などのマルチモーダルAIに画像を送る際、Base64が活躍する。
import base64
import anthropic
from pathlib import Path
def image_to_base64(image_path: str) -> tuple[str, str]:
"""画像ファイルをBase64文字列に変換"""
path = Path(image_path)
suffix_to_mediatype = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp',
}
media_type = suffix_to_mediatype.get(path.suffix.lower(), 'image/png')
with open(image_path, 'rb') as f:
image_data = base64.standard_b64encode(f.read()).decode('utf-8')
return image_data, media_type
# Claude APIに画像を送る
client = anthropic.Anthropic()
image_data, media_type = image_to_base64("chart.png")
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": image_data,
},
},
{
"type": "text",
"text": "このグラフを分析して日本語で説明してください。"
}
],
}
],
)
print(message.content[0].text)
URLとBase64の使い分け
# URL方式(画像がWebで公開されている場合)
messages = [{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "url",
"url": "https://example.com/chart.png"
}
},
{"type": "text", "text": "説明してください"}
]
}]
# Base64方式(ローカルファイル・非公開画像)
messages = [{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_b64_string
}
},
{"type": "text", "text": "説明してください"}
]
}]
JWT(JSON Web Token)での使われ方
JWTは3つの部分をドット(.)で連結したもので、各部分がBase64URLエンコードされている。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcxNzAwMDAwMH0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
import base64
import json
def decode_jwt_payload(token: str) -> dict:
"""JWTのペイロード部分をデコード(署名検証なし・学習用)"""
parts = token.split('.')
payload_b64 = parts[1]
# Base64URLのパディングを追加
padding = 4 - len(payload_b64) % 4
if padding != 4:
payload_b64 += '=' * padding
payload_bytes = base64.urlsafe_b64decode(payload_b64)
return json.loads(payload_bytes)
# JWTをデコードして中身を確認
token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiJ9.xxxxx"
payload = decode_jwt_payload(token)
print(payload) # {'user_id': 123, 'role': 'admin'}
注意: JWTの内容は誰でもデコードできる(暗号化ではなくエンコード)。機密情報を含めてはいけない。
Data URL——HTMLに画像を埋め込む
Base64を使うと画像をHTML/CSS内に直接埋め込める。
<!-- 通常: 外部ファイル参照 -->
<img src="logo.png" alt="ロゴ">
<!-- Data URL: Base64埋め込み -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANS..." alt="ロゴ">
def image_to_data_url(image_path: str) -> str:
"""画像をData URL形式に変換"""
with open(image_path, 'rb') as f:
data = base64.b64encode(f.read()).decode('utf-8')
ext = image_path.rsplit('.', 1)[-1].lower()
mime = {'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png'}.get(ext, 'image/png')
return f"data:{mime};base64,{data}"
# HTMLメールやスタンドアロンHTMLに便利
data_url = image_to_data_url("icon.png")
html = f'<img src="{data_url}" alt="アイコン">'
まとめ
Base64は「バイナリデータをテキスト安全な形式に変換する」シンプルだが広く使われる手法だ。
- なぜ必要か: メール・JSON・URLなどテキスト前提のシステムでバイナリを扱うため
- 仕組み: 3バイト→4文字(64種類の文字使用)、サイズは約33%増加
- バリアント: URL安全(JWT用)・パディングあり/なし
- マルチモーダルAI: 画像をBase64でAPIに送るのが標準パターン
- JWT: ヘッダー・ペイロードをBase64URLエンコード(暗号化ではない)
- Data URL: HTMLに画像を直接埋め込む際に利用
「なぜこれが必要か」という背景を理解すると、Base64が登場する場面で迷わずに使えるようになる。
免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。