DevToolBox無料
ブログ

画像をBase64に変換するオンラインガイド:開発者向け完全マニュアル

11分by DevToolBox
TL;DR

Image to Base64 conversion encodes binary image data as ASCII text using the Base64 alphabet. The result is a data URI like data:image/png;base64,iVBORw0KGgo... that can be embedded directly in HTML, CSS, JavaScript, or email — eliminating an HTTP request. Images grow ~33% in size after encoding. Use Base64 for small images under 5 KB; serve larger images as external files for better caching and performance.

Key Takeaways
  • Base64 encodes every 3 bytes as 4 ASCII characters — a ~33% size increase.
  • Data URIs work in img src, CSS url(), JavaScript strings, and email attachments.
  • MIME types determine how browsers decode the data: image/png, image/jpeg, image/svg+xml, image/webp.
  • FileReader API (browser) and fs.readFileSync + Buffer (Node.js) are the two most common conversion paths.
  • Gmail strips data URIs — use CID embedding or external URLs for HTML email.
  • With gzip/brotli, the actual wire overhead drops to ~10–15% instead of 33%.

Converting an image to Base64 means encoding the raw binary pixels as printable ASCII characters so the image can travel inside a text-based payload — an HTML file, a JSON object, a CSS stylesheet, or a MIME email. This guide covers everything you need to know: the data URI format, browser and Node.js conversion code, Python scripts, performance trade-offs, MIME types, email embedding, security considerations, and how to decode Base64 back to an image file.

Try our free Image to Base64 Converter tool →

1. What Is Image to Base64 Conversion?

Base64 is a binary-to-text encoding scheme defined in RFC 4648. It maps every 6 bits of binary data to one of 64 printable ASCII characters (A–Z, a–z, 0–9, +, /). Because most text-based formats (HTTP headers, HTML attributes, CSS strings, JSON values) cannot contain arbitrary binary bytes, Base64 provides a universal way to embed any binary file as plain text.

When you encode an image as Base64, the output is wrapped in a data URI (RFC 2397):

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==

# General syntax:
data:[<mediatype>][;base64],<data>

# Examples by format:
data:image/png;base64,iVBORw0KGgo...
data:image/jpeg;base64,/9j/4AAQSkZJRgAB...
data:image/svg+xml;base64,PHN2ZyB4bWxu...
data:image/webp;base64,UklGRlYAAABXRUJQ...
data:image/gif;base64,R0lGODlhAQABAAAAACH5...

The components are:

  • data: — the URI scheme
  • image/png — the MIME type (tells the browser how to interpret the bytes)
  • ;base64 — the encoding indicator
  • ,iVBORw0KGgo... — the Base64-encoded image bytes

Data URIs are supported by all modern browsers (Chrome, Firefox, Safari, Edge) and can be used anywhere a URL is accepted: src attributes, CSS url(), JavaScript Image objects, Canvas API, and more.

2. Data URLs in HTML and CSS

HTML img src

The most common use of a Base64 image is replacing an src URL on an <img> tag. The browser decodes the data URI inline and renders the image without making a network request:

<!-- Base64 PNG in img src -->
<img
  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmH..."
  alt="App logo"
  width="64"
  height="64"
/>

<!-- Base64 SVG in img src -->
<img
  src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmci..."
  alt="Checkmark icon"
  width="24"
  height="24"
/>

A 1×1 transparent tracking pixel — a classic use case that saves an HTTP round-trip:

<!-- 1x1 transparent GIF tracking pixel -->
<img
  src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
  alt=""
  width="1"
  height="1"
  style="display:none"
/>

<!-- 1x1 transparent PNG (smaller alternative) -->
<img
  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
  alt=""
/>

Accessibility tip: Always include alt text. For purely decorative images use alt="".

CSS background-image

Data URIs work inside the CSS url() function, making them ideal for small icons, gradients, and UI chrome that must load with the stylesheet:

/* Small PNG icon as CSS background */
.notification-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76L...);
  background-size: contain;
  background-repeat: no-repeat;
}

/* WebP hero background */
.hero {
  background-image: url(data:image/webp;base64,UklGRlYAAABXRUJQVlA4IEoA...);
  background-size: cover;
  background-position: center;
  height: 400px;
}

For SVG images embedded in CSS you have two choices:

  • Base64: url(data:image/svg+xml;base64,...) — universal browser support
  • URL-encoded: url("data:image/svg+xml,%3Csvg...") — smaller output because SVG is already text; no binary-to-text overhead
/* SVG as Base64 in CSS */
.arrow-down {
  background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTQgNmw0IDQgNC00IiBmaWxsPSJub25lIiBzdHJva2U9IiM2NjYiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==);
}

/* SVG as URL-encoded in CSS (often 20% smaller) */
.arrow-down-alt {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%23666' stroke-width='2'/%3E%3C/svg%3E");
}

Performance tip: Prefer URL-encoding SVGs over Base64 in CSS — the encoded output is smaller and the browser skips the Base64 decoding step.

JavaScript Image Objects and Canvas

You can set image.src to a data URI just like a regular URL. This is useful for pre-loading images from a data source or an API:

// Preload an image from a Base64 data URI
const image = new Image();
image.src = 'data:image/png;base64,iVBORw0KGgoAAAAN...';
image.onload = () => {
  console.log('Image loaded — dimensions:', image.width, 'x', image.height);
  document.body.appendChild(image);
};

// Use in Canvas
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
image.onload = () => ctx.drawImage(image, 0, 0);

3. Converting Images in JavaScript (Browser)

FileReader API — File Input

The FileReader API is the standard browser way to convert a user-selected file to a Base64 data URI. It is fully asynchronous and works without any server involvement:

// FileReader API: convert file input to Base64 data URI
const fileInput = document.querySelector('input[type="file"]');

fileInput.addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();

  reader.onload = (e) => {
    const dataUri = e.target.result;
    // "data:image/png;base64,iVBORw0KGgoAAAAN..."

    // Preview in an <img>
    document.getElementById('preview').src = dataUri;

    // Extract just the Base64 part (without the prefix)
    const base64Only = dataUri.split(',')[1];

    // Get MIME type from the data URI
    const mimeType = dataUri.match(/data:([^;]+)/)[1]; // "image/png"
    console.log({ mimeType, base64Length: base64Only.length });
  };

  reader.onerror = () => console.error('FileReader error');
  reader.readAsDataURL(file);  // Triggers onload with data URI
});

Promise-based wrapper for modern async/await code:

// Promise wrapper — use with async/await
function fileToDataUri(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload  = (e) => resolve(e.target.result);
    reader.onerror = ()  => reject(new Error('Failed to read file'));
    reader.readAsDataURL(file);
  });
}

// Usage
async function handleImageUpload(event) {
  const file = event.target.files[0];
  try {
    const dataUri = await fileToDataUri(file);
    const img = document.createElement('img');
    img.src = dataUri;
    document.body.appendChild(img);
  } catch (err) {
    console.error(err);
  }
}

Canvas API — Cross-Origin and DOM Images

For images already rendered in the DOM (or loaded from a URL), the Canvas API lets you draw the image and export it as a data URI. The output MIME type and quality are configurable:

// Canvas API: render any image element and export as data URI
function imageElementToBase64(
  imgElement,
  format = 'image/png',   // 'image/jpeg', 'image/webp'
  quality = 0.92           // 0.0–1.0 (only used for JPEG/WebP)
) {
  const canvas = document.createElement('canvas');
  canvas.width  = imgElement.naturalWidth;
  canvas.height = imgElement.naturalHeight;

  const ctx = canvas.getContext('2d');
  ctx.drawImage(imgElement, 0, 0);

  return canvas.toDataURL(format, quality);
}

// Convert a DOM image
const img = document.querySelector('#my-logo');
img.onload = () => {
  const pngUri  = imageElementToBase64(img, 'image/png');
  const jpegUri = imageElementToBase64(img, 'image/jpeg', 0.8);
  const webpUri = imageElementToBase64(img, 'image/webp', 0.8);
  console.log('PNG  length:', pngUri.length);
  console.log('JPEG length:', jpegUri.length);  // Usually much smaller for photos
  console.log('WebP length:', webpUri.length);  // Usually smallest
};

CORS note: Drawing a cross-origin image onto a Canvas taints the canvas and will throw a security error when you call toDataURL(). The remote server must set Access-Control-Allow-Origin: * and you must load the image with crossOrigin="anonymous".

Fetch API — Remote URLs

To convert an image at a remote URL (same-origin or CORS-enabled) to Base64:

// Fetch + ArrayBuffer: convert remote image URL to Base64
async function urlToBase64(imageUrl) {
  const response = await fetch(imageUrl);
  const blob = await response.blob();

  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload  = (e) => resolve(e.target.result);
    reader.onerror = ()  => reject(new Error('Conversion failed'));
    reader.readAsDataURL(blob);  // blob preserves the MIME type
  });
}

// Usage
const dataUri = await urlToBase64('https://example.com/logo.png');
document.getElementById('logo').src = dataUri;

4. Converting Images in Node.js

Synchronous: fs.readFileSync + Buffer

Node.js has built-in Base64 support through Buffer. This is the simplest approach for build scripts and CLI tools:

const fs   = require('fs');
const path = require('path');

// MIME type lookup by extension
const MIME_TYPES = {
  png:  'image/png',
  jpg:  'image/jpeg',
  jpeg: 'image/jpeg',
  gif:  'image/gif',
  svg:  'image/svg+xml',
  webp: 'image/webp',
  avif: 'image/avif',
  ico:  'image/x-icon',
};

function imageToBase64(filePath) {
  const ext      = path.extname(filePath).slice(1).toLowerCase();
  const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
  const data     = fs.readFileSync(filePath);         // Buffer
  const base64   = data.toString('base64');           // Base64 string
  return `data:${mimeType};base64,${base64}`;
}

// Usage
const dataUri = imageToBase64('./logo.png');
console.log(dataUri.substring(0, 60) + '...');
// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAA...

// Extract just the Base64 string (no prefix) for APIs
const base64Only = fs.readFileSync('./logo.png').toString('base64');

Async: fs.promises.readFile

For production servers, prefer the async version to avoid blocking the event loop:

const fs   = require('fs/promises');
const path = require('path');

async function imageToBase64Async(filePath) {
  const ext      = path.extname(filePath).slice(1).toLowerCase();
  const mimeType = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg',
                     gif: 'image/gif', svg: 'image/svg+xml', webp: 'image/webp' }[ext]
                   || 'application/octet-stream';
  const data   = await fs.readFile(filePath);    // Buffer (async)
  const base64 = data.toString('base64');
  return `data:${mimeType};base64,${base64}`;
}

// Express.js endpoint: convert uploaded image to Base64 JSON response
app.post('/api/image-to-base64', upload.single('image'), async (req, res) => {
  const dataUri = await imageToBase64Async(req.file.path);
  res.json({ dataUri, size: req.file.size, mimeType: req.file.mimetype });
});

Converting Back: Base64 to Image File

To decode a Base64 string back to a binary file in Node.js:

const fs = require('fs');

// Input: full data URI like "data:image/png;base64,iVBOR..."
function dataUriToFile(dataUri, outputPath) {
  // Strip the "data:image/png;base64," prefix
  const base64Data = dataUri.replace(/^data:[^;]+;base64,/, '');
  const buffer = Buffer.from(base64Data, 'base64');
  fs.writeFileSync(outputPath, buffer);
  console.log(`Saved ${buffer.length} bytes to ${outputPath}`);
}

// Input: bare Base64 string (no data URI prefix)
function base64ToFile(base64String, outputPath) {
  const buffer = Buffer.from(base64String, 'base64');
  fs.writeFileSync(outputPath, buffer);
}

// Usage
dataUriToFile('data:image/png;base64,iVBORw0KGgo...', './output.png');
base64ToFile('iVBORw0KGgoAAAANSUh...', './icon.png');

5. Converting Images in Python

base64 Module

Python's standard library base64 module handles encoding and decoding with no external dependencies:

import base64
import mimetypes

def image_to_data_uri(file_path: str) -> str:
    """Convert an image file to a Base64 data URI."""
    # Auto-detect MIME type from file extension
    mime_type, _ = mimetypes.guess_type(file_path)
    if mime_type is None:
        mime_type = 'application/octet-stream'

    with open(file_path, 'rb') as f:
        raw_bytes = f.read()

    encoded = base64.b64encode(raw_bytes).decode('utf-8')
    return f'data:{mime_type};base64,{encoded}'


def data_uri_to_file(data_uri: str, output_path: str) -> None:
    """Decode a Base64 data URI back to a binary file."""
    # Split at the first comma: "data:image/png;base64," + "<data>"
    _header, data = data_uri.split(',', 1)
    binary = base64.b64decode(data)
    with open(output_path, 'wb') as f:
        f.write(binary)


# Usage
uri = image_to_data_uri('logo.png')
print(f"MIME: image/png, Length: {len(uri)} chars")
print(uri[:80] + '...')
# data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...

# Decode back
data_uri_to_file(uri, 'logo_copy.png')

Using pathlib for a more modern approach:

from pathlib import Path
import base64, mimetypes

def image_to_base64_pathlib(image_path: str | Path) -> str:
    path = Path(image_path)
    mime_type, _ = mimetypes.guess_type(path.name)
    mime_type = mime_type or 'application/octet-stream'
    encoded = base64.b64encode(path.read_bytes()).decode()
    return f'data:{mime_type};base64,{encoded}'

# Works with Path objects or string paths
print(image_to_base64_pathlib(Path('icons') / 'logo.svg')[:80])

Tip: Use mimetypes.guess_type() to automatically determine the correct MIME type from the file extension instead of hard-coding it.

Batch Processing Multiple Images

Convert an entire directory of images to an inline CSS sprite file:

import base64, mimetypes
from pathlib import Path

def build_css_sprite(image_dir: str, output_css: str, class_prefix: str = 'img') -> None:
    """Convert all images in a directory to a CSS file with Base64 backgrounds."""
    image_dir = Path(image_dir)
    lines = ['/* Auto-generated Base64 CSS sprite */']

    for img_path in sorted(image_dir.glob('*')):
        if img_path.suffix.lower() not in {'.png', '.jpg', '.jpeg', '.svg', '.webp', '.gif'}:
            continue

        mime_type, _ = mimetypes.guess_type(img_path.name)
        mime_type = mime_type or 'application/octet-stream'
        encoded = base64.b64encode(img_path.read_bytes()).decode()
        data_uri = f'data:{mime_type};base64,{encoded}'

        class_name = f'{class_prefix}-{img_path.stem}'
        lines.append(f'.{class_name} {{')
        lines.append(f'  background-image: url({data_uri});')
        lines.append(f'  background-repeat: no-repeat;')
        lines.append(f'  background-size: contain;')
        lines.append(f'}}')
        lines.append('')

    Path(output_css).write_text('\n'.join(lines), encoding='utf-8')
    print(f'Generated {output_css} with {len(lines)} lines')

build_css_sprite('./icons', './dist/icons.css', class_prefix='icon')

6. MIME Types for Common Image Formats

The MIME type in the data URI tells the browser which image decoder to use. Getting it wrong causes the image to silently fail to render:

FormatMIME TypeTransparencyAnimationBest Use Case
PNGimage/pngYesNoIcons, UI elements, screenshots — lossless compression
JPEGimage/jpegNoNoPhotos — avoid Base64 (large file size)
SVGimage/svg+xmlYesYesLogos, icons, illustrations — prefer URL-encoding in CSS
GIFimage/gifYesYesSimple animations, tiny icons
WebPimage/webpYesYesModern PNG/JPEG replacement — smaller at same quality
AVIFimage/avifYesPartialNext-gen format — smallest size but limited Base64 tooling
ICOimage/x-iconYesNoBrowser favicons (legacy support)

Note: For image/svg+xml you do not need Base64 at all in many contexts — you can use a URL-encoded SVG or even an inline <svg> element in HTML. Base64 is required when the value must be a single unbroken string without special characters.

7. CSS Sprites vs. Base64 Inline Images

Before HTTP/2, CSS sprites were the dominant technique for reducing icon HTTP requests. Base64 inline images are an alternative with different trade-offs:

CSS Sprites

/* CSS Sprites — external file, cached by browser */
.icon {
  background-image: url('/sprites/icons.png');
  background-repeat: no-repeat;
  display: inline-block;
  width: 24px;
  height: 24px;
}
.icon-home     { background-position:   0    0; }
.icon-settings { background-position: -24px  0; }
.icon-search   { background-position: -48px  0; }
.icon-user     { background-position: -72px  0; }

Pros: Files are cached by the browser and shared across pages. The combined image is served once and stays in the browser cache indefinitely. Updating one icon does not bust the cache for the others.

Cons: Requires a build step to generate the sprite sheet and update background-position values. Harder to maintain as the icon set grows. Cannot use CSS-only styling (color changes require a new sprite).

Base64 Inline Images

/* Base64 inline — zero HTTP requests, not cached separately */
.icon-home {
  background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggZD0iTTMgOWw5LTcgOSA3djExYTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0yeiIvPjwvc3ZnPg==);
  background-repeat: no-repeat;
  background-size: 24px;
  display: inline-block;
  width: 24px;
  height: 24px;
}

Pros: Zero HTTP requests. Self-contained — no external dependencies. Ideal for single-file HTML documents, email templates, and portable widgets.

Cons: Not cached separately — embedded in HTML/CSS, so each page load re-sends the image bytes. Every page that shares the same icon must include its own copy of the Base64 string.

Verdict: With HTTP/2, both sprites and Base64 are less important because the browser multiplexes many small requests over a single connection. Prefer external files with a CDN for most production cases.

8. Performance: When to Use Base64 vs. External Images

Base64 embedding is a performance trade-off, not a universal optimization:

Use Base64 When:

  • Image is under 5 KB — the saved HTTP request outweighs the 33% size overhead
  • Image is used exactly once — no caching benefit would be lost
  • Self-contained deliverable — email, portable HTML report, single-file widget
  • Critical above-the-fold image — must render before the next paint without waiting for a network round-trip
  • HTTP/1.1 connection overhead — each request carries ~200 B of headers; inlining tiny images avoids this (less relevant under HTTP/2)

Avoid Base64 When:

  • Image is over 10 KB — size overhead exceeds the latency saved by eliminating one request
  • Image is reused across many pages — an external file loads once and stays cached; Base64 is re-transmitted with every HTML/CSS response
  • Image changes frequently — inlining busts the cache for the entire containing file every time the image changes
  • Server-side rendering with many images — enlarges the HTML payload and delays First Contentful Paint
  • HTTP/2 or HTTP/3 context — multiplexing neutralizes most of the request-count advantage of inlining

Rule of thumb: If you would not create a separate file for the image (because it is that small), embed it. Otherwise, serve it externally and leverage the browser cache.

9. File Size Impact: The ~33% Overhead

Base64 encodes 3 bytes of binary data as 4 ASCII characters (each character carries 6 bits, and 4 × 6 = 24 bits = 3 bytes). This ratio produces a 33.33% size increase in the raw encoded string:

# The math behind Base64 size increase:
# Base64 encodes 3 bytes → 4 characters
# Ratio: 4/3 = 1.3333... → 33.33% larger

# Example encoding:
# Input:   3 bytes   [0x48 0x65 0x6C]  (binary: "Hel")
# Binary:  01001000 01100101 01101100
# Split 6: 010010 000110 010101 101100
# Index:   18     6      21     44
# Chars:   S      G      V      s       ("SGVs")

# Padding: if input is not a multiple of 3, = is appended
# 1 remaining byte  → 2 Base64 chars + "=="
# 2 remaining bytes → 3 Base64 chars + "="

Real-world size comparison:

OriginalBase64 SizeOverheadVerdict
1 KB1.37 KB+370 BRecommended — request savings outweigh cost
5 KB6.67 KB+1.67 KBMarginal — evaluate per use case
10 KB13.3 KB+3.3 KBQuestionable — test carefully
50 KB66.7 KB+16.7 KBNot recommended — use external file

With gzip/brotli compression, the actual over-the-wire increase is only around 10–15% rather than the full 33%, because Base64 output (repetitive ASCII patterns) compresses well. Most modern HTTP servers and CDNs apply gzip by default. Factor this into your decision — a 5 KB image at 33% overhead is 6.67 KB uncompressed but closer to 5.5 KB compressed.

Padding: Base64 uses = padding characters to ensure the output length is always a multiple of 4. A 10-byte input produces 16 Base64 characters (14 data + 2 padding). Padding can be stripped in some contexts (like JWT) but must be preserved in data URIs.

10. Email Embedding: Content-Transfer-Encoding

Email is one of the most important use cases for Base64, but the rules are different from HTML. The MIME email standard defines Content-Transfer-Encoding to indicate how a MIME part is encoded:

Approach A: Inline Data URI (Limited Support)

Embedding a Base64 data URI directly in the src attribute works in Apple Mail and Thunderbird but Gmail strips it as a security measure. Outlook support is inconsistent:

<!-- Inline data URI in email (Apple Mail + Thunderbird only) -->
<html>
<body>
  <img
    src="data:image/png;base64,iVBORw0KGgoAAAANSUhEU..."
    alt="Company Logo"
    width="200"
    height="50"
    style="display:block;"
  />
  <p>Thank you for your order!</p>
</body>
</html>

Client support:

Email ClientData URI SupportCID Support
GmailNo (strips all data: URIs)Yes
OutlookPartial (version-dependent)Yes
Apple MailYesYes
ThunderbirdYesYes
Yahoo MailNoYes

Approach B: CID (Content-ID) Embedding — Recommended

The correct approach for production email is CID embedding using a multipart MIME message. The image is attached as a separate MIME part and referenced by a Content-ID:

// Node.js + Nodemailer: CID image embedding (works in all clients)
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({ /* SMTP config */ });

await transporter.sendMail({
  from: 'no-reply@yourcompany.com',
  to: 'customer@example.com',
  subject: 'Your Order Confirmation',
  html: `
    <div style="font-family: Arial, sans-serif;">
      <img
        src="cid:company-logo"
        alt="Company Logo"
        width="180"
        height="45"
        style="display:block; margin-bottom:20px;"
      />
      <h1>Order #12345 Confirmed!</h1>
      <p>Thanks for your purchase. We will ship within 24 hours.</p>
      <img
        src="cid:product-image"
        alt="Your product"
        width="300"
        height="300"
      />
    </div>
  `,
  attachments: [
    {
      filename: 'logo.png',
      path: './assets/logo.png',
      cid: 'company-logo',     // matches src="cid:company-logo"
    },
    {
      filename: 'product.jpg',
      path: './assets/product.jpg',
      cid: 'product-image',    // matches src="cid:product-image"
    },
  ],
});

CID embedding is supported by Gmail, Outlook, Apple Mail, Thunderbird, and virtually every other email client. It is the recommended approach for transactional and marketing email.

11. Security Considerations: Data URL XSS Risks

Data URIs are powerful but come with security implications that every developer should understand:

HTML and JavaScript Injection via data:text/html and data:application/javascript

Data URIs are not restricted to images. A malicious actor can craft a data URI that executes JavaScript:

// Malicious data URI examples — DO NOT execute
// data:text/html,<script>alert('XSS')</script>
// data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=
// data:application/javascript,alert(document.cookie)

// These can be used to steal cookies, perform CSRF, and exfiltrate data
// if injected into an unsanitized innerHTML or href attribute

Modern browsers have progressively restricted data URIs:

  • Chrome 60+: Blocks data:text/html navigations from the top-level address bar
  • Firefox: Blocks cross-origin data: navigations
  • Safari: Restricts data URI usage in iframes
  • Content Security Policy (CSP): The img-src 'self' directive blocks external images but the img-src data: directive is required to allow data URIs

CSP Configuration for Data URIs

In your Content Security Policy header, be explicit about allowing data URIs only for images:

# Nginx: strict CSP allowing data URIs only for images
add_header Content-Security-Policy "
  default-src 'self';
  img-src 'self' data: https:;
  script-src 'self';
  style-src 'self' 'unsafe-inline';
" always;

# Express.js with helmet
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc:  ["'self'"],
    imgSrc:      ["'self'", "data:", "https:"],
    scriptSrc:   ["'self'"],
    styleSrc:    ["'self'", "'unsafe-inline'"],
  },
}));

Avoid default-src data: — this would allow data URIs for scripts, styles, and other resource types, opening XSS vectors.

SVG-Specific Risks

Embedded SVG images can contain <script> tags. When an SVG is loaded via <img src="data:image/svg+xml...">, most browsers sandbox the scripts. However, if you render SVG as inline HTML (via innerHTML), scripts execute. Always sanitize user-supplied SVG content with a library like DOMPurify before rendering.

// UNSAFE: rendering user-supplied SVG as innerHTML
// NEVER do this with untrusted input:
document.getElementById('icon').innerHTML = userSuppliedSvg;
// <svg><script>alert(1)</script></svg>  →  executes!

// SAFE: use DOMPurify to sanitize before rendering
import DOMPurify from 'dompurify';
const cleanSvg = DOMPurify.sanitize(userSuppliedSvg, {
  USE_PROFILES: { svg: true },   // Allow safe SVG elements
  FORBID_TAGS: ['script'],       // Explicit block (also covered by default)
});
document.getElementById('icon').innerHTML = cleanSvg;

// ALSO SAFE: load SVG via <img src="data:image/svg+xml;base64,...">
// Scripts inside SVGs are sandboxed in <img> context (cannot access parent DOM)

Gmail and Data URI Stripping

Gmail deliberately strips all data: URI attributes from emails before rendering. This is a security feature to prevent phishing and XSS attacks via email. Use CID embedding or external HTTPS image URLs for email images.

12. Converting Base64 Back to Image

Browser: Trigger a Download

To decode a Base64 data URI and download it as a file in the browser:

// Browser: trigger download of a Base64 image
function downloadBase64Image(dataUri, filename = 'image.png') {
  const link = document.createElement('a');
  link.href     = dataUri;      // full "data:image/png;base64,..." string
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

// Usage
downloadBase64Image('data:image/png;base64,iVBORw0KGgo...', 'logo.png');
downloadBase64Image('data:image/svg+xml;base64,PHN2Zy...', 'icon.svg');

Browser: Display in an img Tag

Assign the data URI directly to an image element — the browser handles decoding automatically:

// Browser: render decoded image without downloading
const base64String = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAY...';
const mimeType     = 'image/png';

const img = document.getElementById('output');
img.src = `data:${mimeType};base64,${base64String}`;
img.alt = 'Decoded image';

Node.js: Write to Disk

Use Buffer.from() with the "base64" encoding to convert back to binary:

const fs = require('fs');

// From a data URI string
const dataUri = 'data:image/png;base64,iVBORw0KGgoAAAAN...';
const base64  = dataUri.replace(/^data:[^;]+;base64,/, '');
fs.writeFileSync('decoded.png', Buffer.from(base64, 'base64'));

// From a bare Base64 string (no prefix)
const rawBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAY...';
fs.writeFileSync('icon.png', Buffer.from(rawBase64, 'base64'));

console.log('File written:', fs.statSync('decoded.png').size, 'bytes');

Python: Decode with base64.b64decode

Python's standard library handles the decoding in a single function call:

import base64

# Decode from data URI
data_uri = 'data:image/png;base64,iVBORw0KGgoAAAAN...'
header, encoded = data_uri.split(',', 1)
image_bytes = base64.b64decode(encoded)
with open('decoded.png', 'wb') as f:
    f.write(image_bytes)

# Decode from bare Base64 string
raw_base64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAY...'
image_bytes = base64.b64decode(raw_base64)
with open('icon.png', 'wb') as f:
    f.write(image_bytes)

print(f'Decoded {len(image_bytes)} bytes')

Command Line (Linux / macOS)

Decode from a file containing only the Base64 string (no data URI prefix):

# Decode Base64 file to image (Linux / macOS)
base64 --decode < image.b64 > decoded.png

# Or using openssl
openssl base64 -d -in image.b64 -out decoded.png

# If the input has the data URI prefix, strip it first:
# data:image/png;base64,iVBOR... → iVBOR...
sed 's/^data:[^,]*,//' image-with-prefix.txt | base64 --decode > decoded.png

# PowerShell (Windows)
$base64 = Get-Content -Path 'image.b64' -Raw
$bytes = [Convert]::FromBase64String($base64.Trim())
[System.IO.File]::WriteAllBytes('decoded.png', $bytes)

Try our free Image to Base64 Converter tool →

Frequently Asked Questions

What is the difference between Base64 and a data URI?

Base64 is the encoding algorithm. A data URI is a URL scheme that wraps Base64-encoded data with a MIME type prefix. So "data:image/png;base64,iVBOR..." is a data URI containing a Base64-encoded PNG. You cannot use a bare Base64 string in an img src — you need the full data URI including the scheme, MIME type, and encoding indicator.

How do I get the MIME type automatically when converting an image?

In the browser, the FileReader API returns the full data URI including the correct MIME type based on the file's magic bytes — you do not need to guess. In Node.js, use the "mime-types" npm package or "mimetypes" from the standard library in Python. You can also infer the MIME type from the file extension using a lookup table: { "png": "image/png", "jpg": "image/jpeg", "svg": "image/svg+xml", "webp": "image/webp" }.

Can I use Base64 images in React and Next.js?

Yes. In React, use a Base64 data URI as the src prop directly: <img src="data:image/png;base64,..." alt="..." />. In Next.js, the next/image component accepts data URIs in the blurDataURL prop for blur-up placeholder effects. For build-time optimization, import images at build time, convert them to data URIs, and export them as module constants. Avoid embedding large images — Next.js image optimization only works with external files.

Does Base64 embedding affect Core Web Vitals or SEO?

Base64-embedded images are not separately indexable by search engines — they cannot appear in Google Image Search. For LCP (Largest Contentful Paint), inlining a critical hero image as Base64 can actually improve LCP by eliminating the image request, but only if the image is small. Large Base64 images bloat the HTML payload, delay parsing, and hurt FCP and LCP. For SEO purposes, always use external URLs with descriptive filenames and alt text for content images.

What is the maximum size for a Base64 data URI?

RFC 2397 does not define a size limit. Practical browser limits vary: Internet Explorer had a 32 KB limit (legacy). Modern browsers (Chrome, Firefox, Edge, Safari) support data URIs up to several megabytes. However, the performance implications make anything over 10 KB inadvisable. CSS parsers in some older browsers also struggle with very long data URIs embedded in stylesheets.

Why does my Base64 image show as a broken image icon?

Common causes: (1) Wrong MIME type — "data:image/png;base64,..." but the data is actually a JPEG; (2) Truncated Base64 string — the string was cut off; Base64 length must be a multiple of 4 (pad with = if needed); (3) Missing or malformed data URI prefix — the "data:" scheme, MIME type, and ";base64," must all be present; (4) Newlines inside the Base64 string — some encoders insert line breaks every 76 characters; remove all whitespace before using in a data URI; (5) Double-encoding — the Base64 string was encoded a second time.

Is Base64 a form of encryption?

No. Base64 is purely an encoding scheme — it obscures data visually but provides zero security. Anyone can decode a Base64 string instantly. Do not use Base64 to "hide" sensitive information. For actual encryption, use AES-256 or similar cryptographic algorithms. Base64 is sometimes confused with encryption because encoded data looks like random characters, but it is fully reversible without any key.

How can I reduce the file size of a Base64-encoded image?

Optimize the source image before encoding: (1) Use an appropriate format — SVG for vector graphics, WebP or AVIF for photographs; (2) Reduce image dimensions — a 48x48 icon does not need to be 512x512; (3) Compress with tools like Squoosh, ImageOptim, or sharp before encoding; (4) For PNG icons, use indexed color (8-bit) instead of RGBA (32-bit); (5) Consider converting SVGs to URL-encoded format instead of Base64 — it is often 20–30% smaller. Our tool automatically strips unnecessary metadata before encoding.

𝕏 Twitterin LinkedIn
この記事は役に立ちましたか?

最新情報を受け取る

毎週の開発ヒントと新ツール情報。

スパムなし。いつでも解除可能。

Try These Related Tools

🖼️Base64 Image ConverterB64Base64 Encoder/Decoder🖼️SVG to PNG Converter

Related Articles

HTML・CSS・メールにBase64画像を埋め込む:完全ガイドと例

HTML、CSS、メールテンプレートにBase64データURIとして画像を埋め込む方法。メリット・デメリット、サイズ制限、パフォーマンスへの影響。

Base64エンコーディング実践:開発者が知るべき7つの実用例

Base64の7つの実用例:HTML画像埋め込み、Kubernetesシークレット、JWTトークン、Data URI。

Base64エンコード&デコード完全ガイド:コード例付き

無料のBase64エンコーダー&デコーダー。JavaScript、Python、Bash、PowerShellでの変換方法を詳しく解説。

コマンドラインでBase64エンコード&デコード(Linux・Mac・Windows)

あらゆるOSのターミナルでBase64文字列をエンコード・デコードする方法。Linux base64コマンド、macOS openssl、Windows PowerShellの例。