The direct browser solution depends on what you have. For a local image selected with <input type="file">, pass the File to FileReader.readAsDataURL(). For an existing remote URL, fetch it as a Blob first, then use the same reader. Use canvas.toDataURL() when you must resize, crop, composite, or change format.
What a data URL contains
A data URL embeds the media in the URL itself. An image result normally looks like data:image/png;base64,iVBORw0KGgo.... The part before the comma declares the MIME type and encoding; the remainder is Base64-encoded image bytes.
This is different from a raw Base64 string. Keep the complete value when assigning it to img.src, a CSS url(), or an API field documented as a data URL. Remove the data:*/*;base64, prefix only when a service explicitly asks for Base64 without a media declaration.
Convert a selected image file with FileReader
FileReader.readAsDataURL() is the simplest path for a browser File or Blob. The operation is asynchronous, so return a Promise and handle both load and error events.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware match#1 Best Overall
function imageFileToDataURL(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener("load", () => resolve(reader.result));
reader.addEventListener("error", () => reject(reader.error));
reader.readAsDataURL(file);
});
}
const input = document.querySelector("#image-input");
const preview = document.querySelector("#preview");
const output = document.querySelector("#data-url");
input.addEventListener("change", async () => {
const file = input.files[0];
if (!file) return;
try {
const dataURL = await imageFileToDataURL(file);
preview.src = dataURL;
output.value = dataURL;
} catch (error) {
console.error("Could not read image", error);
}
});
The matching markup can be as small as:
<input id="image-input" type="file" accept="image/*">
<img id="preview" alt="Selected image preview">
<textarea id="data-url" readonly></textarea>
The returned value is a string beginning with the file’s detected MIME type, such as data:image/jpeg;base64,. The browser does not upload the file in this example; it reads the selected bytes locally.
Validate the input before reading
Use the file’s metadata for an early check, while remembering that a client-side MIME value is not a security boundary. For an application that accepts uploads, validate and decode the file on a trusted server as well.
const file = input.files[0];
if (!file) return;
if (!file.type.startsWith("image/")) {
throw new Error("Choose an image file");
}
const dataURL = await imageFileToDataURL(file);
Convert a remote image URL
For a URL, fetch the resource as a Blob and reuse the file function:
async function remoteImageToDataURL(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return imageFileToDataURL(await response.blob());
}
remoteImageToDataURL("https://example.com/photo.jpg")
.then(dataURL => {
document.querySelector("#preview").src = dataURL;
})
.catch(console.error);
CORS is required for cross-origin reads
The remote server must permit your page’s origin with an appropriate CORS response header. If it does not, fetch() cannot expose the response body to JavaScript, even when opening the image URL directly in a tab works. You cannot fix a missing permission by changing mode to no-cors; an opaque response cannot be read as a Blob for this purpose. Configure the image host, use a same-origin server proxy that you control, or obtain the image through an endpoint that explicitly allows your origin.
Fetch also follows HTTP behavior: a 404, 500, redirect policy failure, or network interruption must be handled before conversion. Checking response.ok prevents an HTML error page from being treated as an image.
Rank #2
Use canvas when pixels must change
Choose canvas when you need to resize, crop, composite, or encode a different format. Load the image, draw it into a canvas, and serialize the canvas pixels with toDataURL().
function loadImage(src) {
return new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener("load", () => resolve(image));
image.addEventListener("error", () => reject(new Error("Image failed to load")));
image.src = src;
});
}
function canvasToDataURL(image, type = "image/png", quality) {
const canvas = document.createElement("canvas");
canvas.width = image.naturalWidth || image.width;
canvas.height = image.naturalHeight || image.height;
const context = canvas.getContext("2d");
if (!context) throw new Error("Canvas 2D context is unavailable");
context.drawImage(image, 0, 0);
return quality === undefined
? canvas.toDataURL(type)
: canvas.toDataURL(type, quality);
}
const image = await loadImage("/photos/original.jpg");
const dataURL = canvasToDataURL(image, "image/jpeg", 0.82);
When the requested type is omitted or unsupported, toDataURL() falls back to PNG. For formats that support lossy compression, the quality argument is a number from 0 to 1. A value near 1 keeps more detail and generally produces a larger JPEG or WebP; a lower value trades detail for size.
Resize before encoding
Set the canvas dimensions before drawing. This example limits the long edge while preserving aspect ratio:
function resizeImageToDataURL(image, maxEdge = 1600, type = "image/jpeg", quality = 0.82) {
const sourceWidth = image.naturalWidth || image.width;
const sourceHeight = image.naturalHeight || image.height;
const scale = Math.min(1, maxEdge / Math.max(sourceWidth, sourceHeight));
const canvas = document.createElement("canvas");
canvas.width = Math.max(1, Math.round(sourceWidth * scale));
canvas.height = Math.max(1, Math.round(sourceHeight * scale));
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL(type, quality);
}
Canvas and cross-origin images
If an image was loaded from another origin, set image.crossOrigin = "anonymous" before assigning src, and ensure the image server sends compatible CORS headers. Otherwise the canvas becomes tainted and reading it with toDataURL() throws a security error. Drawing a cross-origin image does not grant permission; the server’s CORS policy still controls pixel access.
Choosing the right approach
| Situation | Use | Why |
|---|---|---|
| File from a file input | FileReader.readAsDataURL(file) |
Direct conversion with no pixel redraw |
| Blob already in memory | FileReader.readAsDataURL(blob) |
The same API accepts Blob objects |
| Remote URL you can read | fetch() to Blob, then FileReader |
Fetch supplies bytes; CORS determines whether JavaScript may read them |
| Resize, crop, composite, or re-encode | Canvas plus toDataURL() |
Canvas serializes transformed pixels and accepts type and quality |
| Very large image where a data URL is optional | toBlob() plus URL.createObjectURL() |
Avoids one large in-memory string and is better suited to previews |
Large images, memory, and object URLs
A data URL stores the entire encoded image in a JavaScript string. Base64 also expands binary data, and duplicating that string in state, the DOM, logs, or a request body can multiply memory use. MDN warns that toDataURL() encodes the whole image in memory and can hit URL-length limits when used as an image source; for large images it generally recommends toBlob() with URL.createObjectURL().
canvas.toBlob(blob => {
if (!blob) throw new Error("Encoding failed");
const objectURL = URL.createObjectURL(blob);
preview.src = objectURL;
preview.addEventListener("load", () => URL.revokeObjectURL(objectURL), { once: true });
}, "image/webp", 0.8);
Object URLs are not data URLs: they are temporary browser references to a Blob. Revoke them when no longer needed. If an API specifically requires a data URL, generate it at the boundary where it is needed rather than keeping many copies in application state.
Sending a data URL to an API
Send the complete string when the API documents a data-URL field:
const dataURL = await imageFileToDataURL(file);
const response = await fetch("/api/images", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ image: dataURL })
});
if (!response.ok) throw new Error(`Upload failed: HTTP ${response.status}`);
If the API asks for raw Base64, split only the first comma and transmit the second part:
const [, base64] = dataURL.split(",", 2);
if (!base64) throw new Error("Invalid data URL");
Do not strip the prefix by habit: doing so removes the MIME type that consumers may need to decode the value.
Or skip the browser setup
If your goal is a clean screenshot rather than converting a local image, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. It accepts cookie and consent banners before capture, then removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing result.
Use the API documented at ScreenshotNeo’s documentation:
Rank #4
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every plan includes its capture options, including full-page lazy-image loading, CSS-selector element capture, device presets, custom CSS and JavaScript, waits, request blocking, headers and cookies, geolocation, resizing, caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification.
The Free plan includes 1,000 shots per month without a card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Sign up for the free ScreenshotNeo plan.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting
“Failed to fetch” for a remote image
Usually the host did not grant CORS access, the URL is unreachable, or the page is mixed content. Inspect the browser Network panel, verify the response status and Access-Control-Allow-Origin, and use a permitted proxy or same-origin endpoint when you control the application.
The result is a broken image
Log the first characters of the result and check the MIME type. A valid value starts with data:image/. Confirm that you passed the actual File or Blob, not a file name, and that the remote response was checked with response.ok.
Recommended Free Tools
Canvas throws a security error
The canvas is tainted by a cross-origin image. Set crossOrigin before src and configure CORS on the image server. If you cannot change that server, fetch the bytes through an authorized same-origin service before drawing.
Best Value
The browser becomes slow or crashes
Reduce dimensions before encoding, avoid storing duplicate strings, and prefer toBlob() with an object URL for previews or downloads. Revoke object URLs after use and do not log megabyte-sized data URLs.
The API rejects the value
Check whether it expects a complete data URL, raw Base64, a particular MIME type, or a maximum request size. Preserve the prefix unless the API explicitly says otherwise, and choose JPEG or WebP when transparency is unnecessary and payload size matters.
Practical checklist
- Use FileReader for a local File or Blob.
- Fetch a remote image as a Blob and satisfy CORS before reading it.
- Use canvas only when pixel transformation or format control is required.
- Keep the
data:prefix for URL consumers; remove it only for raw-Base64 fields. - Prefer
toBlob()and object URLs for large previews. - Revoke object URLs and avoid retaining unnecessary copies.
- Validate image content on the server for security-sensitive uploads.
Frequently Asked Questions
Can I convert an image URL without CORS permission?
Not directly in browser JavaScript. The remote server must allow your origin, or an authorized server-side proxy must fetch the image for you.
Free tools Windows power users keep installed
One-click scans. No signup required.
Does FileReader change or compress the image?
No. It encodes the existing File or Blob as a data URL. Use canvas when you need resizing, cropping, or a different format.
Why is my Base64 string larger than the image file?
Base64 representation adds overhead, and the data-URL prefix adds a few more characters. Large images also occupy memory as JavaScript strings.
Which format should I choose in canvas.toDataURL()?
Use PNG when lossless quality or transparency matters. Use JPEG or WebP with a quality value when a smaller lossy image is acceptable and the target supports that format.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitches

