Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To convert a loaded HTML <img> into PNG Base64 in the browser, draw it onto a canvas sized to its intrinsic dimensions, then call canvas.toDataURL("image/png"). That returns a complete data URL beginning data:image/png;base64,; remove that prefix only if the receiving code needs the Base64 characters alone. For a remote image, the image server must also permit canvas access through CORS.

Convert an existing <img> element to a PNG data URL

Canvas is the browser-native route when the input is an image element and the output must be PNG, regardless of whether the source image was JPEG, WebP, or another supported image format. The following function expects the image to have finished loading:

function imageToPngDataUrl(img) {
  if (!img.complete || img.naturalWidth === 0 || img.naturalHeight === 0) {
    throw new Error("Image is not loaded or has no intrinsic dimensions");
  }

  const canvas = document.createElement("canvas");
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;

  const context = canvas.getContext("2d");
  if (!context) throw new Error("Canvas 2D context is unavailable");

  context.drawImage(img, 0, 0);
  return canvas.toDataURL("image/png");
}

The returned string is a data URL, not merely the Base64 payload. It has this form: data:image/png;base64,iVBORw0KGgo.... Keeping the prefix is usually right for browser features and APIs that accept data URLs.

Use it with an image already in the page

Wait for the load event before calling the conversion function. Also handle the error event so a broken URL does not become a confusing canvas error.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const img = document.querySelector("#source-image");

img.addEventListener("load", () => {
  try {
    const pngDataUrl = imageToPngDataUrl(img);
    document.querySelector("#result").src = pngDataUrl;
  } catch (error) {
    console.error("Could not export image:", error);
  }
}, { once: true });

img.addEventListener("error", () => {
  console.error("The source image could not be loaded");
}, { once: true });

// If the image was already loaded before listeners were attached:
if (img.complete && img.naturalWidth > 0) {
  const pngDataUrl = imageToPngDataUrl(img);
  document.querySelector("#result").src = pngDataUrl;
}

Example markup:

<img id="source-image" src="/images/photo.jpg" alt="Source">
<img id="result" alt="PNG copy">

The function uses naturalWidth and naturalHeight, which are the image’s intrinsic pixel dimensions. The displayed size from CSS or HTML width and height attributes may be different. Using displayed dimensions instead is appropriate only when you intentionally want a resized output.

Load an image created in JavaScript

Attach listeners before assigning src, so a fast response cannot finish loading before the handlers are ready.

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error("Image failed to load"));
    img.src = url;
  });
}

const img = await loadImage("/images/photo.jpg");
const pngDataUrl = imageToPngDataUrl(img);
console.log(pngDataUrl);

In code that needs to support older environments without top-level await, call this from an async function.

Get only the Base64 characters

If an API or storage format specifically asks for raw Base64 rather than a data URL, remove everything through the first comma:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const dataUrl = imageToPngDataUrl(img);
const base64 = dataUrl.slice(dataUrl.indexOf(",") + 1);

Do not strip the prefix by default. A consumer expecting a data URL may require the MIME declaration, while another may require raw Base64 or binary bytes. Check the receiving interface’s expected format before changing the value.

Handle remote images and CORS

An image from another origin can appear normally in an <img> and still be unavailable for canvas export. If the browser draws a cross-origin image without CORS permission, the canvas becomes tainted. Exporting it with toDataURL() or toBlob(), or reading pixels with getImageData(), then fails with a SecurityError.

For an image you create in JavaScript, set crossOrigin before src:

const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
  try {
    const pngDataUrl = imageToPngDataUrl(img);
    console.log(pngDataUrl);
  } catch (error) {
    console.error(error);
  }
};
img.onerror = () => console.error("Image load failed; check URL and CORS response");
img.src = "https://images.example.com/photo.jpg";

This requests a CORS-enabled image load; it does not grant permission by itself. The image host must respond with an appropriate Access-Control-Allow-Origin header allowing your page’s origin. If you control that server, configure its response policy. Otherwise use an image hosted on your own origin or ask the image provider for a permitted access path. Setting the attribute after assigning src is too late for that request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose between canvas, FileReader, and toBlob

Need Method What it returns or changes
Convert an image element to PNG drawImage() then toDataURL("image/png") A PNG data URL; requires readable canvas pixels, so cross-origin CORS applies.
Encode an existing Blob or File without changing its format FileReader.readAsDataURL() A data URL representing the existing file bytes. It does not turn JPEG or WebP into PNG.
Export a rendered image without constructing a Base64 string canvas.toBlob() A Blob, suitable when the next step accepts binary data or a download.

Encode a File or Blob as-is

When the source is already a Blob or File and you only need its existing bytes encoded as a data URL, use FileReader:

function blobToDataUrl(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error || new Error("Could not read file"));
    reader.readAsDataURL(blob);
  });
}

const dataUrl = await blobToDataUrl(file);

The result retains the source format in its MIME type. To transcode a JPEG or WebP file into PNG, first decode and draw it to canvas, then export PNG using toDataURL("image/png").

Use a Blob for large output

toDataURL() creates the entire encoded result as an in-memory string. Base64 representation can be significantly larger than the corresponding binary data, so a large image may use considerable memory and create a long string. MDN recommends preferring toBlob() with URL.createObjectURL() in general when a data URL is not required.

function canvasToPngBlob(canvas) {
  return new Promise((resolve, reject) => {
    canvas.toBlob(blob => {
      if (blob) resolve(blob);
      else reject(new Error("PNG encoding returned no Blob"));
    }, "image/png");
  });
}

const canvas = document.createElement("canvas");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext("2d").drawImage(img, 0, 0);

const pngBlob = await canvasToPngBlob(canvas);
const objectUrl = URL.createObjectURL(pngBlob);
document.querySelector("#result").src = objectUrl;
// When finished with the object URL, release it:
URL.revokeObjectURL(objectUrl);

If the final consumer demands Base64, converting the Blob to a data URL still creates a Base64 string and its associated memory cost. Use the Blob route only when downstream code can consume the Blob, an object URL, or binary data directly.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Resize or preserve the image dimensions

The canvas dimensions determine the exported pixel dimensions. For an unchanged-size copy, use naturalWidth and naturalHeight. To resize deliberately, set the canvas dimensions to the target dimensions and provide destination dimensions to drawImage():

const width = 800;
const height = Math.round(width * img.naturalHeight / img.naturalWidth);
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(img, 0, 0, width, height);
const resizedPng = canvas.toDataURL("image/png");

That example preserves the source aspect ratio. If you choose unrelated width and height values, the image is stretched or compressed to fit. Do not set canvas dimensions to zero: a zero-sized canvas does not produce a usable PNG data URL.

Troubleshoot common conversion failures

  • SecurityError during export: The canvas contains a cross-origin image without the necessary CORS permission. Set crossOrigin = "anonymous" before src and verify the image host sends an allowing CORS response, or use a same-origin image.
  • The image is blank or has zero dimensions: Conversion ran before loading completed, the URL failed, or the image did not decode. Wait for load, check error, and confirm naturalWidth and naturalHeight are nonzero.
  • The result is data:,: MDN documents this result for a canvas with zero dimensions or dimensions exceeding the browser’s canvas limit. Confirm both dimensions are positive and reduce an exceptionally large target canvas.
  • getContext("2d") returns null: Stop before drawing and report the unavailable context; the conversion function cannot proceed without a 2D context.
  • PNG output looks larger than the source: PNG is a lossless format and Base64 adds encoding overhead. If the receiver accepts a Blob, use toBlob(); if it requires Base64, the string size is inherent to that interface.
  • Only part of the image appears: Check whether the source has completed loading and whether you intended to capture the full intrinsic image rather than a CSS-cropped display. drawImage(img, 0, 0) draws the source image at its intrinsic dimensions when the canvas matches them.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo captures a webpage as PNG, JPEG, WebP, or PDF; it is not a replacement for converting an existing <img> element already in your page. It can help when what you need is a screenshot of a page that contains the image. A single request returns the capture:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Its clean-shot flow accepts cookie or consent banners and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; these steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents using Claude, Cursor, or other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Learn more at ScreenshotNeo, or sign up free for 1,000 screenshots a month with no card.

Sources and scope

The browser behavior described here follows MDN Web Docs documentation on using images with canvas, cross-origin images, HTMLCanvasElement.toDataURL(), FileReader.readAsDataURL(), and the HTML image element, checked September 29, 2026. No browser-specific compatibility claim is made; consult current compatibility tables when targeting particular browsers.

Frequently Asked Questions

Does converting an image to Base64 make it encrypted?

No. Base64 is an encoding, not encryption; it does not protect image contents.

Will this preserve animation from an animated GIF?

Canvas exports a rendered image frame, not an animated sequence. If you need the animation, preserve the original file instead of converting a frame to PNG.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.