dataスキームでHTMLファイルやCSSファイルに画像データを埋め込む

細かい画像ファイルをたくさん利用する場合、たくさんサーバーにファイルを要求する事になるため、HTTPヘッダー等のオーバーヘッドが大きくなる。これはそれを回避して、HTMLファイル内に画像データを埋め込む方法。データURIスキームと言う。

性質上、埋め込んだデータ部分だけキャッシュされたりはせず、埋め込み先のファイルをダウンロードするたびに埋め込まれたデータを含んで取得する必要がある。

データ形式

スキームの形式は以下の通り:

data:([MIMEタイプ])?(;charset=[エンコード])?(;base64)?,[データ]

この形式自体は画像だけに限らない。例えばdata:,A%20brief%20noteは、コンテンツタイプがtext/plainでエンコードがUS-ASCIIのA brief noteというテキストデータを示す。

利用方法

imgのsrc属性に指定する、CSSのurl()に指定するといった使い方がある。imgの例:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEREFUeNrVW3uUHFWZ...(省略)">

CSSのurl()の例:

background-image: url(data:image/png;base64,iVBORw0KG3RJTUUH3gMbW3uUHFWZ...(省略))

対応状況

メジャーなブラウザは概ね対応しているが、Edge/Internet Explorerはだいたい画像しか対応していない。

各プログラム言語でBASE64エンコードした画像を埋め込む方法

サーバー側のプログラム言語で6言語ほど、dataスキームで画像をimgで出力する例を示す。処理内容にばらつきがあるのはご了承いただきたい...

Ruby

MIMEタイプの判別にはfilemagicというgemが利用できる。

sudo gem install ruby-filemagic
brew install libmagic
require 'base64'
require 'filemagic'

img_filename = "./example.png"
base64 = nil
File.open(img_filename, 'r') do |img|
  base64 = Base64.strict_encode64(img.read)
end
img_type = FileMagic.new(FileMagic::MAGIC_MIME).file(img_filename).split(';').first
p "<img src='data:#{img_type};base64,#{base64}' alt=''>";

PHP

$img_filename = "https://www.example.com/example.png";
$img = file_get_contents($img_filename);
$img_base64 = base64_encode($img);
$img_type = mime_content_type($img_filename);
echo "<img src='data:${img_type};base64,${img_base64}' alt=''>";

Perl

#! /usr/local/bin/perl

use MIME::Base64;
use MIME::Types;

my $img_filename = "./example.png";

open(IMG1, $img_filename);
binmode(IMG1);
my $img_bin = do { local $/;  };
close $fh;

my $img_base64 = encode_base64($img_bin);
$img_base64 =~ s/(\r\n|\r|\n)//g;
my $mt = MIME::Types->new;
my $type = $mt->mimeTypeOf($img_filename);

print "Content-type: text/html\n\n";
print "<img src='data:${type};base64,${img_base64}' alt=''>";

Python

import base64
import mimetypes

img_filename = "./example.png";
file = open(img_filename, 'rb').read()
img_base64 = base64.urlsafe_b64encode(file)
img_type = mimetypes.guess_type(img_filename)[0]
print("<img src='data:%s;base64,%s' alt=''>" % (img_type, img_base64.decode()))

コマンドライン

macOSの場合、ターミナルから以下コマンドでBase64に変換できる。

uuencode -m img.png < /path/to/image.png|sed -e '1d'|tr -d '\n'

内容はだいたい以下の通り:
-m: Base64で出力するオプション
img.png: ダミーの画像名(なんでもいい)
/path/to/image.png: 画像へのパス(変更してね)
sed -e '1d': 1行目のパーミッションとかファイル名とかを削除
tr -d '\n': 改行コードを削除

JavaScript

一部ブラウザは対応していないが、File APIという便利なAPIがあるので、それを使って比較的簡単に実行できる。

<input type="file" onchange="encodeImage()" id="input-image"><br>
<textarea id="image-base64" cols="100" rows="10">
</textarea>
<script>
function encodeImage() {
var file = document.getElementById('input-image').files[0];
var textarea = document.getElementById('image-base64');
var reader = new FileReader();

reader.addEventListener('load', function () {
textarea.innerHTML = "<img src='" + reader.result + "' alt=''>";
}, false);

if (file) {
reader.readAsDataURL(file);
}
}
</script>

実行結果は以下:


参考