[РУКОВОДСТВО] Как сделать предварительный просмотр Base64-изображений в браузере
Пять проверенных способов отобразить Base64-изображение на странице — прямое присваивание src, FileReader, canvas, конвертация в blob и паттерны под конкретные фреймворки. С советами по отладке.
// ОТВЕТ ЗА 30 СЕКУНД
Если у вас есть Base64-кодированная строка изображения и вы просто хотите увидеть её на странице, кратчайший путь — присвоить её как data: URI к img.src. Три строки JavaScript:
const img = new Image();
img.src = 'data:image/png;base64,' + base64String;
document.body.appendChild(img);
// If the string already starts with 'data:image/...;base64,'
// — just assign it directly without prepending anything:
img.src = base64StringWithDataUriPrefix;
// СПОСОБ 1: img.src — ПРЯМОЙ ПОДХОД
Любой элемент <img> воспринимает data URI как обычный URL. Присвойте URI свойству src, и браузер сам займётся декодированием, определением формата и отрисовкой.
Это работает для любого формата, который браузер поддерживает нативно: PNG, JPEG, GIF (анимированный и статический), WebP, SVG, BMP, ICO. Base64-строка может прийти откуда угодно — из ответа API, localStorage, вставки из буфера обмена, строки в БД.
MIME-тип в data URI важен для старых браузеров и некоторых встроенных WebView. Если у вас только сырая Base64-полезная нагрузка (без префикса data:) и вы не знаете формат, можно либо проверить магические байты (см. Способ 5), либо по умолчанию использовать image/png — большинство браузеров «принюхаются» и восстановятся, даже если MIME-тип неверен.
// Plain HTML — no JavaScript needed if the string is static
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="preview">
// Dynamic JavaScript — load from a variable, fetch, or input field
function renderBase64Image(base64, mimeType = 'image/png', containerId = 'preview') {
const container = document.getElementById(containerId);
const img = new Image();
img.onload = () => {
container.innerHTML = '';
container.appendChild(img);
};
img.onerror = () => {
container.textContent = 'Invalid image data';
};
// Tolerate both raw Base64 and full data: URIs
img.src = base64.startsWith('data:')
? base64
: `data:${mimeType};base64,${base64}`;
}
renderBase64Image(myBase64String, 'image/jpeg');
// СПОСОБ 2: FILEREADER ДЛЯ ФАЙЛОВ, ЗАГРУЖЕННЫХ ПОЛЬЗОВАТЕЛЕМ
Если пользователь загружает изображение через <input type="file">, вам не нужно вручную кодировать его в Base64. FileReader.readAsDataURL() отдаёт готовый data URI, который можно сразу же подставить в img.src:
<input type="file" id="fileInput" accept="image/*">
<img id="preview" alt="">
<script>
document.getElementById('fileInput').addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
// event.target.result is a complete data URI
// e.g. 'data:image/png;base64,iVBORw0KGgo...'
document.getElementById('preview').src = event.target.result;
};
reader.onerror = () => {
console.error('FileReader failed:', reader.error);
};
reader.readAsDataURL(file);
});
</script>
// СПОСОБ 3: CANVAS ДЛЯ СГЕНЕРИРОВАННЫХ ИЛИ ИЗМЕНЁННЫХ ИЗОБРАЖЕНИЙ
Когда вы рисуете или обрабатываете изображение на <canvas>, canvas.toDataURL() экспортирует результат в data URI одним вызовом. Полезно для: скриншотов диаграмм, полей подписи, QR-кодов, водяных знаков и всего, что генерируется на стороне клиента и должно быть отображено или скачано как изображение.
// 1. Draw on canvas
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#00FF41';
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = '#000';
ctx.font = '20px monospace';
ctx.fillText('Hello, Base64!', 20, 100);
// 2. Export to data URI
const pngDataURL = canvas.toDataURL('image/png');
// pngDataURL === 'data:image/png;base64,iVBORw0KGgo...'
// 3. Display directly
const img = new Image();
img.src = pngDataURL;
document.body.appendChild(img);
// JPEG with quality control (0–1)
const jpegDataURL = canvas.toDataURL('image/jpeg', 0.85);
// WebP if supported
const webpDataURL = canvas.toDataURL('image/webp', 0.9);
// СПОСОБ 4: FETCH + BLOB ДЛЯ УДАЛЁННЫХ BASE64-ПОЛЕЗНЫХ НАГРУЗОК
Если Base64-полезная нагрузка большая (более 50 КБ) или вы будете отображать её много раз, конвертация в Blob URL через URL.createObjectURL() экономнее по памяти, чем держать полный data URI в DOM. blob URL короткий (blob:https://example.com/12345-abcde), его можно отозвать, когда он больше не нужен, и он избавляет от 33% накладных расходов Base64 в строках DOM.
// Convert a Base64 string to a Blob, then to a blob: URL
function base64ToBlobURL(base64, mimeType = 'image/png') {
// Strip the data: prefix if present
const payload = base64.includes(',') ? base64.split(',')[1] : base64;
// Decode Base64 to binary string
const binary = atob(payload);
// Convert binary string to Uint8Array
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
// Wrap in a Blob and create an object URL
const blob = new Blob([bytes], { type: mimeType });
return URL.createObjectURL(blob);
}
// Usage
const blobURL = base64ToBlobURL(myBase64, 'image/jpeg');
const img = new Image();
img.src = blobURL;
document.body.appendChild(img);
// IMPORTANT: free the memory when you're done with the image
img.onload = () => URL.revokeObjectURL(blobURL);
// СПОСОБ 5: АВТО-ОПРЕДЕЛЕНИЕ ФОРМАТА ПО МАГИЧЕСКИМ БАЙТАМ
Если вы получаете сырую Base64-полезную нагрузку (без префикса data:) и не знаете, PNG это, JPEG, GIF или WebP, загляните в первые декодированные байты — у каждого формата уникальная сигнатура.
function detectImageFormat(base64) {
// Look at the first ~12 characters of the Base64 string
const head = base64.replace(/^data:[^,]+,/, '').slice(0, 16);
if (head.startsWith('iVBORw0KGgo')) return 'image/png';
if (head.startsWith('/9j/')) return 'image/jpeg';
if (head.startsWith('R0lGOD')) return 'image/gif';
if (head.startsWith('UklGR')) return 'image/webp';
if (head.startsWith('PHN2Zy') ||
head.startsWith('PD94bWw')) return 'image/svg+xml';
if (head.startsWith('Qk')) return 'image/bmp';
if (head.startsWith('AAABAA')) return 'image/x-icon';
return 'application/octet-stream'; // unknown
}
// Build a correct data URI even when the user only gave us the payload
function toDataURI(base64) {
if (base64.startsWith('data:')) return base64; // already complete
const mime = detectImageFormat(base64);
return `data:${mime};base64,${base64}`;
}
// REACT — ОТОБРАЖЕНИЕ BASE64-ИЗОБРАЖЕНИЙ В КОМПОНЕНТАХ
В React относитесь к data URI как к любой другой строковой prop. Мемоизируйте конвертацию, если вход меняется редко:
import { useMemo } from 'react';
function Base64Image({ base64, mimeType = 'image/png', alt }) {
const src = useMemo(() => {
if (!base64) return '';
return base64.startsWith('data:')
? base64
: `data:${mimeType};base64,${base64}`;
}, [base64, mimeType]);
if (!src) return <div>No image</div>;
return <img src={src} alt={alt} loading="lazy" />;
}
// Usage
<Base64Image
base64={apiResponse.avatar}
mimeType="image/jpeg"
alt="User avatar"
/>
// For large images, prefer blob URLs (Method 4) and useEffect for cleanup:
function LargeBase64Image({ base64 }) {
const [blobURL, setBlobURL] = useState('');
useEffect(() => {
const url = base64ToBlobURL(base64, 'image/png');
setBlobURL(url);
return () => URL.revokeObjectURL(url); // cleanup on unmount
}, [base64]);
return blobURL ? <img src={blobURL} alt="" /> : null;
}
// VUE 3 — ПРИМЕР НА COMPOSITION API
Та же идея, синтаксис Vue:
<script setup>
import { computed } from 'vue';
const props = defineProps({
base64: String,
mimeType: { type: String, default: 'image/png' },
alt: { type: String, default: '' }
});
const src = computed(() => {
if (!props.base64) return '';
return props.base64.startsWith('data:')
? props.base64
: `data:${props.mimeType};base64,${props.base64}`;
});
</script>
<template>
<img v-if="src" :src="src" :alt="alt" loading="lazy" />
<div v-else>No image</div>
</template>
// SVELTE — РЕАКТИВНОЕ ВЫРАЖЕНИЕ
<script>
export let base64 = '';
export let mimeType = 'image/png';
export let alt = '';
$: src = base64
? (base64.startsWith('data:') ? base64 : `data:${mimeType};base64,${base64}`)
: '';
</script>
{#if src}
<img {src} {alt} loading="lazy" />
{:else}
<div>No image</div>
{/if}
// ОБРАБОТКА ОШИБОК — ЧТО ЛОМАЕТСЯ И ПОЧЕМУ
Изображение загружается как иконка-заглушка «битой картинки». Base64-полезная нагрузка обрезана, содержит пробелы внутри строки или использует URL-safe-символы (-_) внутри стандартного data URI. Удалите пробелы через str.replace(/\s+/g, ''); конвертируйте URL-safe обратно в стандартный через str.replace(/-/g, '+').replace(/_/g, '/'); и проверьте корректность длины (длина Base64 должна быть кратна 4 с правильным padding-ом =).
Изображение отрисовывается, но в неверном формате. Префикс data:image/png;base64, говорит, что это PNG, но реальные байты — JPEG. Браузер «принюхивается» к магическим байтам и всё равно отрисовывает корректно — но некоторые headless-браузеры и встроенные WebView так не делают. Используйте Способ 5, чтобы определить реальный формат по байтам.
Изображение огромно в DOM, и страница ощутимо тормозит. Base64-строка в 1 МБ внутри React-компонента ререндерится при каждом обновлении состояния. Переключитесь на blob: URL (Способ 4) — это строка из 50 символов в DOM независимо от размера изображения.
Изображение работает в Chrome, но не работает в Safari. У Safari более строгие настройки CSP по умолчанию, и он отвергает data: URI в некоторых контекстах (<a download>, fetch внутри service worker). Тестируйте в Safari и при необходимости откатывайтесь на blob: URL.
Сама Base64-строка некорректна. Иногда получаемый «Base64» оказывается дважды закодированным, hex-кодированным или просто повреждённым. Сначала вставьте его в наш декодер Base64 в изображение, чтобы убедиться в корректности данных, прежде чем отлаживать свой код.
// ПРОИЗВОДИТЕЛЬНОСТЬ: data: URI VS blob: URL — БЫСТРЫЙ БЕНЧМАРК
Для JPEG в 500 КБ, отображённого в <img>:
• data: URI в src: 668 КБ строки в DOM (33% накладных расходов Base64). Браузер парсит URI, декодирует Base64, декодирует JPEG. ~80 мс до first paint на ноутбуке среднего уровня.
• blob: URL через URL.createObjectURL: строка из 56 символов в DOM. Браузер забирает blob из памяти, декодирует JPEG. ~40 мс до first paint. ~50% экономии памяти.
Для иконки в 5 КБ разница незаметна — оба отрисовываются за < 5 мс. Вывод: до ~50 КБ — используйте то, что удобнее. Выше — предпочитайте blob URL.
// ИЗОЛИРОВАННОЕ ТЕСТИРОВАНИЕ ВАШЕГО ПРЕДВАРИТЕЛЬНОГО ПРОСМОТРА
Если вы подозреваете баг, сначала изолируйте Base64-строку от кода вашего приложения. Три быстрые проверки:
1. Вставьте её в наш онлайн-инструмент. Бросьте строку в конвертер Base64 в изображение. Если изображение там отрисовывается корректно — данные в порядке, и баг в вашем коде. Если и там не отрисовывается — данные повреждены вверх по потоку.
2. Откройте её как URL в новой вкладке. Скопируйте data URI (включая префикс data:image/png;base64,), вставьте в новую вкладку браузера, нажмите Enter. Современные браузеры отобразят изображение напрямую. (Некоторые блокируют data: в адресной строке — в этом случае пользуйтесь встроенным тестом из шага 1.)
3. Проверьте длину. Корректная Base64-строка имеет длину, кратную 4 (после удаления пробелов). Padding (=) добивает разницу: от 0 до 2 завершающих символов =. Если ваша длина не кратна 4, строка обрезана или растянута.
// Quick validation snippet
function looksLikeValidBase64(str) {
const cleaned = str.replace(/^data:[^,]+,/, '').replace(/\s+/g, '');
if (cleaned.length === 0) return false;
if (cleaned.length % 4 !== 0) return false;
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(cleaned)) return false;
return true;
}
// 30-СЕКУНДНАЯ ШПАРГАЛКА
Самый быстрый путь: присвойте data URI к img.src. Готово.
Из загрузки файла: FileReader.readAsDataURL(file).
Из canvas: canvas.toDataURL('image/png').
Для больших или повторяющихся изображений: сконвертируйте в blob и используйте URL.createObjectURL(blob).
Неизвестный формат: определите магические байты (iVBORw0KGgo = PNG, /9j/ = JPEG и т.д.) перед сборкой data URI.
Отладка: сначала вставьте в конвертер Base64 в изображение — это сразу исключит данные как источник проблемы.
Связанные материалы: Разбираем data URI · встраивание изображений в Base64 · Base64 в JavaScript: браузер и Node