microsoft / microsoft/AdaptiveCards

[JS] Allow hosts to download images themselves

Open
#6,366 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Request
Dominant language
C#
Stars
2k
Forks
595
Avg merge
1d 19h
Merged PRs (30d)
1

Description

Problem Statement

Currently, images are entirely handled by the underlying HTML engine; <img> tags are generated with their src property set to the Image's url property. This works great most of the time, unless the host application needs to load images via some sort of proxy service which, for instance, could require authentication.

Proposed solution

The JS SDK should provide an event a host can handle to download an image's bits itself (that includes Image elements as well as background images). The host should be able to download the bits asynchronously without blocking the rendering of the card, and provide those bits back to the SDK so it can finish rendering images.

I propose an API along the following lines:

interface IImageInfo {
    url: string;
    parent: CardElement;
    setImageData(string);
}

class AdaptiveCard extends ContainerWithActions {
    ...
    static onDownloadImageData?: (imageInfo: IImageInfo) => boolean;

    onDownloadImageData?: (imageInfo: IImageInfo) => boolean;
    ...
}

class Image extends CardElement implements IImageInfo {
    ...
    protected internalRender(): HTMLElement {
        ...
        if (raiseDownloadImageDataEvent(this)) {
            // The host says it's downloading the data itself, don't set the <src> property
        }
        else {
            imageElement.src = this.url;
        }
        ...
    }

    setImageData(data: string) {
        // data is expected to be a Base64 encoded string
        this._imageElement.src = "data:" + data;
    }
    ...
}

async function dowloadImageDataAsynchronously(imageInfo: IImageInfo) {
    let data = await actualDownload(imageInfo.url);

    imageInfo.setImageData(Base64Encode(data));
}

function raiseDownloadImageDataEvent(imageInfo: IImageInfo): boolean {
    let card = imageInfo.parent ? imageInfo.parent.getRootElement() as AdaptiveCard : undefined;
    let onDownloadImageDataHandler = (card && card.onDownloadImageData) ? card.onDownloadImageData : AdaptiveCard.onDownloadImageData;

    if (onDownloadImageDataHandler) {
        return onDownloadImageDataHandler(imageInfo);
    }
    else {
        return false;
    }
}

let card = new AdaptiveCard();
card.onDownloadImageData = (imageInfo: IImageInfo) => {
    if (imageShouldBeDownloadedByHost(imageInfo)) {
        downloadImageDataAsynchronously(imageInfo);

        // Return true to let the SDK know we are downloading the bits ourselves
        return true;
    }

    return false;
}

With this model, the host can decide to download image data for specific images only.
The BackgroundImage class would have to plug into the same model by providing its own IImageInfo instance.

Notes:

  • There might be a more efficient way than to serialize the image data to Base64 strings.

Additional capabilities the SDK could provide:

  • Display some sort of a placeholder while the image data is being downloaded by the host
  • Impose a timeout after which the SDK would display another placeholder showing an error occurred
Alternatives or Workarounds

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the JS SDK's AdaptiveCard, Image, and BackgroundImage rendering entry points. Trace how image and background URLs become rendered image sources, then define the host callback and asynchronous completion behavior for both paths. Done means hosts can selectively supply image data without blocking card rendering, while existing URL behavior remains available.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.