A reliable image preview has two separate jobs: decode the Base64 representation and decode the resulting image format. A string can pass the first step and fail the second because the file is truncated, mislabeled or unsupported by the browser. Show those states separately.
Keep a byte-oriented pipeline
Remove a recognized Data URI wrapper through a parser, validate the Base64, and obtain a Uint8Array. Do not route image bytes through a text decoder. If you want a simple local preview, wrap the bytes in a Blob and create an object URL. That avoids assembling another large Base64 string just to display the result.
// bytes is a validated Uint8Array; type comes from checked raster metadata.
async function previewRaster(bytes, type, imageElement) {
const allowed = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];
if (!allowed.includes(type)) throw new Error('Unsupported raster preview type');
const url = URL.createObjectURL(new Blob([bytes], { type }));
try {
imageElement.src = url;
await imageElement.decode();
return { width: imageElement.naturalWidth, height: imageElement.naturalHeight,
dispose: () => URL.revokeObjectURL(url) };
} catch (error) {
URL.revokeObjectURL(url);
imageElement.removeAttribute('src');
throw error;
}
}
Keep the object URL only as long as needed
Call the returned dispose function when replacing or removing the preview. Repeated previews without cleanup retain browser resources. Do not revoke a URL before an image has loaded, and do not reuse a disposed URL for a later download. If downloads need to remain available, manage their lifetime separately.
Use real image-decoder feedback
A file signature is only an initial hint. The image element's decode step checks whether the browser can actually load it and exposes its dimensions. An error here should say that image decoding failed while retaining the original bytes for inspection or download. It should not overwrite the input or report that the Base64 alphabet was invalid.
Apply byte and dimension limits before expensive rendering where possible. A small compressed file can describe a very large image. Avoid treating SVG as an ordinary raster payload: it is structured markup with different security considerations. Never inject unknown SVG or HTML directly into the page to make a preview work.
Finally, distinguish previewing from converting. Displaying a JPEG in an image element does not create a PNG. Conversion requires drawing a decoded image to a canvas and exporting the chosen format, with explicit quality and transparency choices. The Data URI wrapper is described in MDN: data URLs; preview success remains a browser-format check, not a general safety certification.