Embedding Local Images using Data URIs
HTML that references local images by file path, such as <img src="C:\Reports\chart-1.png">, only renders correctly on the machine where that file exists. The moment your app needs to move that HTML - store it in a database column, send it by email, or render it on a different machine or server - the local image is unreachable and the picture is simply gone. The WinForms HTML Editor can avoid that failure mode entirely. This page shows how to make an image travel with its HTML instead of depending on a file path that may not exist wherever the HTML ends up.
Making the HTML self-contained
The fix is to fold the image bytes directly into the HTML as a data URI - <img src="data:image/png;base64,iVBORw0K..."> - instead of a file path. After the conversion, the HTML stands alone: store it in a database column, attach it to an email, or copy it to another machine, and the images travel with it because they are part of it.
An <img src=> pointing at a local file path only works on the machine that has that file. Save the HTML to a database, email it, or host it on a server, and the image is gone the moment it leaves the original machine. EmbedLocalImagesAsBase64() rewrites every local image reference into a self-contained data: URI, so the HTML carries its own images and needs no external file at all.
The file path is gone; the image bytes themselves are now part of the markup string returned by DocumentHtml. That string can be stored in a database column, dropped into an HtmlBody on a MailMessage, or written straight to a static file - it renders identically everywhere, with zero dependency on the machine that authored it.
The helper
On editor.Content (an IContentService):
void EmbedLocalImagesAsBase64();The helper walks the document's <img> elements. For each one whose src is a local file path, it reads the bytes, infers the MIME type from the file extension (image/png, image/jpeg, image/gif, image/webp, etc.), Base64-encodes the bytes, and rewrites the src in place to the equivalent data: URI. Remote URLs (http://, https://) are left untouched, so an image hosted elsewhere can sit alongside local screenshots.
The rewrite happens in the editor's in-memory document. After the call returns, editor.Content.GetBodyHtml(true) and editor.Content.GetDocumentHtml() reflect the new state. Read the HTML out of either of those.
The fixed save path
private async Task SaveReportAsync(Guid reportId) { // 1. Fold local images into the HTML in place. // After this call, every <img src="C:\..."> has become // <img src="data:image/...;base64,...">. htmlEditor1.Content.EmbedLocalImagesAsBase64(); // 2. Read the rewritten body HTML out of the editor. string body = htmlEditor1.Content.GetBodyHtml(getInXhtml: true); // 3. Persist. One column. One round trip. await _reports.UpdateBodyAsync(reportId, body); }Private Async Function SaveReportAsync(reportId As Guid) As Task ' 1. Fold local images into the HTML in place. ' After this call, every <img src="C:\..."> has become ' <img src="data:image/...;base64,...">. htmlEditor1.Content.EmbedLocalImagesAsBase64() ' 2. Read the rewritten body HTML out of the editor. Dim body As String = htmlEditor1.Content.GetBodyHtml(getInXhtml:=True) ' 3. Persist. One column. One round trip. Await _reports.UpdateBodyAsync(reportId, body) End FunctionThe saved HTML is self-contained: it renders correctly wherever it is opened, and the rendering machine never needs access to the original image files.

Refinement -- when not to use this
Base64 inflates the bytes by roughly 33 percent: ten 500 KB screenshots become about 6.7 MB of HTML. A document with a handful of screenshots typically stays well under a couple of megabytes, comfortable for a SQL Server column and for page weight. A document with dozens of high-resolution images per page will hit size limits fast; in that case, keep the images as separate blobs and reassemble them at render time instead.
The conversion is one-way at the markup level: after the rewrite, the original file paths are gone from the HTML, and editing an image means editing the embedded data URI, not the source file. If users need to re-author from originals, store the source files separately (for example keyed by a record ID) alongside the converted HTML. If the source images are disposable (screenshots taken once and never edited again), the one-way conversion is fine on its own.
If the destination is an email message
For email, use a different helper: GetEmailMessageWithLocalImagesEmbedded() produces a proper multipart/related MailMessage with CID-referenced linked resources, the format email clients expect. See Embedding Local Images for Email Clients. Using EmbedLocalImagesAsBase64() for an email body works in some clients but bloats the message by 33 percent and trips spam filters; the CID approach is the correct one for email.
