Any ways to load a SingleTileImageryProvider with an existing image?

I’ve got a use case where I need to show images overlaid directly on terrain, so I’m using a SingleTileImageryProvider for that. However, I’d also like to be able to take that same image and use it elsewhere in the UI. Ideally, I’d like to make sure that the image is only downloaded once, and hand it to both the STIP and my UI. A promise (such as that returned by Cesium.loadImage() ) seems perfect for this. However, SingleTileImageryProvider only accepts a URL, which it ultimately passes to Cesium.loadImage() itself. There’s no way to pass in an existing Image, or promise for an Image, that I can see.

The only workaround I can think of is loading the image myself, paint it to a canvas, convert it to a data URL, then pass that to the STIP. Which, frankly, seems silly.

Are there any other obvious approaches, or is this the only alternative?

Mark Erikson

It would be a straightforward improvement to the SingleTileImageryProvider to allow it to take an Image or a Promise in its constructor.

In the current code, though, you’re right that a data URL is the only public API way to do what you want. Since this is JavaScript, though, if you’re willing to use private functionality with the usual caveats (unsupported, subject to change or removal at any time with no notification) you could load a blank 1x1 png from a data URL, wait for it to become ready, then poke into the internals of the object and change the private properties to use your image instead (_image, _tileWidth, _tileHeight).

We’re currently on Cesium 1.9, and I’m planning to bump us to 1.12 when it releases next week. We’re mostly likely hitting code freeze by the end of August, and will have to stay with that for the duration of the release’s lifespan.

Looking at the source… maybe just adding an “image” field to the options object that could be either an Image or a Promise, and preferring that over the value of the “url” field? Pass that to the when() call instead of loadImage(imageUrl) ?

Hi Mark,

Don’t forget you can easily create your own ImageryProvider within your app code. Copy SingleTileImageryProvider, modify it to fit within your build architecture (e.g. use globals or CommonJS modules instead of AMD modules if necessary), make whatever other modifications you need so that it does what you need it to do, and you’re set. There’s no reason such code needs to live inside Cesium.

In a pinch, you can even define a Cesium imagery provider as an object literal, such as:

var image = …;

var rectangle = …;

var width = …;

var height = …;

var imageryProvider = {

ready: true,

errorEvent: new Cesium.Event(),

hasAlphaChannel: true,

rectangle: rectangle,

tilingScheme: new Cesium.GeographicTilingScheme({

rectangle: rectangle,

numberOfLevelZeroTilesX: 1,

numberOfLevelZeroTilesY: 1


tileWidth: width,

tileHeight: height,

minimumLevel: 0,

maximumLevel: 0,

requestImage: function() { return image; },

getTileCredits: function() { return undefined; },

pickFeatures: function() { return undefined; }


I didn’t try this, but it’s probably pretty close.


That’s a good point. I certainly prefer to have things available in the official version of whatever library I’m using if possible, especially because that way I pick up whatever fixes/improvements show up in future versions of that library. That said, goodness knows I’ve got enough tweaks and stuff in the codebase at the moment. You should see the two files I have for setting up full cross-compatibility between Backbone.Model, Backbone.Collection, and Ampersand.State :slight_smile:

I will certainly look at that as an option in the next day or two. Thanks!

Mark Erikson