Images and clipboard

Documentation index ยท Security

Image references versus file imports

An existing durable image URL can be inserted directly. A pasted bitmap, dropped file, or file-picker selection must first be stored somewhere. The editor handles the insertion, progress/error state and URL replacement; the host owns the storage operation.

Images are currently block objects inserted in Visual mode, not arbitrary inline objects embedded in table cells. Their references serialize as Markdown image syntax or supported HTML. No image bytes are automatically embedded as base64 in the saved text.

editor.execute('insertImage', {
  src: '/editor-assets/example.png', alt: 'System diagram'
});
await editor.InsertImageAsync("https://assets.example.com/diagram.png", "System diagram");

The URL must be accepted by the image URL rules. Loading it also depends on the origin policy; a valid URL can be stored yet blocked from display. Prefer application-controlled HTTPS URLs or appropriate relative URLs. Do not insert local machine file paths as portable asset references.

Browser import callback

Provide onImageImport at creation. It receives a File, source label, cancellation signal and image ID, and must return an object with a durable src. The endpoint below is illustrative host code; the included ASP.NET sample supplies an /editor-assets endpoint with this general role.

const editor = CODEEditor.create(element, {
  format: 'markdown', mode: 'rich',
  imageOrigins: [location.origin],
  async onImageImport({ file, signal }) {
    const response = await fetch('/editor-assets', {
      method: 'POST', body: file,
      headers: { 'Content-Type': file.type }, signal
    });
    if (!response.ok) throw new Error('The image could not be stored.');
    const result = await response.json();
    return { src: result.src, assetId: result.assetId, alt: file.name };
  }
});
// With a File obtained from an <input type="file">:
// await editor.importImage(file, 'picker');

source distinguishes picker, drop, paste and retry paths. The callback may upload, write through a native bridge, or use another host service. Do not return a temporary browser object URL as durable storage.

WinForms import event

Assign e.Result to your storage Task. The control transports and validates file bytes; it does not require a storage service interface or DI container.

editor.ImageImportRequested += (_, e) =>
{
    e.Result = SaveImageAsync(e.Bytes, e.MimeType, e.CancellationToken);
};

Here SaveImageAsync is an application method returning Task<ImageImportResult>. It should store the bytes under an application-generated name, honor cancellation, and return new ImageImportResult(src, assetId, alt). File names supplied by a browser are display metadata; do not use them directly as trusted filesystem paths.

A local-folder example, configured before initialization:

string imageFolder = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    "MyApplication", "EditorImages");
Directory.CreateDirectory(imageFolder);
editor.LocalImageFolder = imageFolder;
editor.Options.ImageOrigins = [TextEditor.LocalImageOrigin];
editor.ImageImportRequested += (_, e) =>
    e.Result = StoreLocalAsync(e.Bytes, e.MimeType, e.CancellationToken);

async Task<ImageImportResult> StoreLocalAsync(
    ReadOnlyMemory<byte> bytes, string mime, CancellationToken token)
{
    string extension = mime switch
    {
        "image/png" => ".png", "image/jpeg" => ".jpg",
        "image/gif" => ".gif", "image/webp" => ".webp",
        _ => throw new InvalidOperationException("Unsupported image type.")
    };
    string name = Guid.NewGuid().ToString("N") + extension;
    await File.WriteAllBytesAsync(Path.Combine(imageFolder, name), bytes.ToArray(), token);
    return new ImageImportResult($"{TextEditor.LocalImageOrigin}/{name}", name);
}

That URL works only where the same virtual origin maps the appropriate asset folder. A Markdown file copied to another machine or displayed on a website will not automatically carry its assets. For Olympus content shared across hosts, an application asset service with stable IDs/URLs is usually the better integration. Save As is not an asset-bundling operation.

There is no public .NET method that accepts an arbitrary file's bytes for import. Native paste/drop uses the event. For a host-owned file picker, store/upload the selected file through your application and insert its returned URL with InsertImageAsync.

External images in pasted HTML

externalImages / ExternalImages governs images referenced by pasted HTML:

Value Behavior
Reference (default) Keep a permitted external URL reference
Reject Omit external image references from that import path
Import Ask onExternalImageImport / ExternalImageImportRequested to obtain a durable replacement URL

The external callback receives a URL and cancellation, not file bytes. The host must decide which remote resources it is willing to fetch and how to authenticate. This setting is separate from allowRemoteImages / AllowRemoteImages, which controls display resource permission. An external reference can therefore remain in the document while its display is blocked.

Lifecycle and limits

The default file size limit is 10 MiB; allowed types are PNG, JPEG, GIF and WebP. JavaScript permits up to eight concurrent imports, with a bounded retry-file cache. WinForms validates bounded transport and file signatures; PNG/JPEG/GIF decoding also enforces a 40-million-pixel limit. WebP receives signature validation, not equivalent decoding. Native MaxImageBytes permits at most 100 MiB and native pending transport has an aggregate bound.

An insertion starts pending. Success resolves it to a ready URL without creating a separate user-facing upload undo step. Failure leaves a failed image that can be retried or removed. Pending and failed images block saveable-value retrieval and validated snapshots. They also block view switching until resolved or removed.

Undo, removal, load and disposal can cancel work. Late results do not reinsert removed content. The JavaScript assetAbandoned event tells a host that an uploaded result no longer belongs to the current document; the host decides whether and when to garbage-collect it. Never immediately delete a shared asset merely because a user undoes a reference. Retry can fail if its retained original file has been evicted; the user must choose the file again.

Clipboard behavior

Source copy exports plain text. Visual copy can export supported HTML and plain text. Complete tables can retain structure; partial table selections are flattened for clipboard output. HTML paste passes through the supported importer and feature policy. File items from paste/drop route to image imports in Visual mode; file import in Source requires switching views.

CopyAsync, CutAsync, and PasteAsync are currently native plain-text helpers. Keyboard copy/paste inside the editor can carry rich HTML and image files. Use PasteHtmlAsync for host-supplied HTML and PasteTsvAsync for explicitly prepared tabular text. PasteHtmlAsync is intended for Visual mode; it is not an HTML-source insertion helper.

Current PasteAsync passes an empty string when the system clipboard has no text, which can replace an existing selection with nothing. A host toolbar should check Clipboard.ContainsText() before enabling/invoking that helper. CopyAsync with an empty selection does not overwrite the clipboard. Real clipboard combinations and ordering from Word, Outlook and browser applications remain an acceptance test area.