Closed Bug 558188 Opened 14 years ago Closed 14 years ago

context.drawImage with a image source from a data: uri sometimes don't work

Categories

(Core :: Graphics: Canvas2D, defect)

x86
All
defect
Not set
normal

Tracking

()

VERIFIED INVALID

People

(Reporter: alexl, Unassigned)

References

()

Details

User-Agent:       Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8
Build Identifier: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8

The example does basically:

  var img = new Image();
  img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAHklEQVR4AQAHAPj/AP////8AAAEHAPj/AP8A/wD/ADnUBvq4wRz/AAAAAElFTkSuQmCC";
  context.drawImage(img, 0, 0);

And I expect this to always work because no network i/o is necessary to load the data: uri. However, sometimes it fails with an exception like:

[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]"  nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)"  location: "JS frame :: http://people.gnome.org/~alexl/canvas-bug.html :: anonymous :: line 17"  data: no]

This mostly happens the first time. Once its worked once, it will keep working. But if you restart firefox it will happen again the first time.

If you check img.completed the failing time it will return false, and if it succeeds it is true. 

Reproducible: Sometimes

Steps to Reproduce:
1. Load uri


Actual Results:  
Alert with exception

Expected Results:  
no alert, image drawn
In 3.6 and Minefield.  Reproduced on Windows 7 as well.
OS: Linux → All
So, i think it sometimes "working" is cache related.
It fails first time, then works on every reload, but shift-reload makes it break again.
Wait for the onload event on the image before trying to use it.
Yeah, this is one of the icky parts of the web. We load all images asynchronously, even data: urls, so what you're going to have to do is:

  var img = new Image();
  img.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAHklEQVR4AQAHAPj/AP////8AAAEHAPj/AP8A/wD/ADnUBvq4wRz/AAAAAElFTkSuQmCC";
  image.onload = function() { context.drawImage(img, 0, 0); }

(untested)

Basically, you just have to wait until the image is loaded. Once it's loaded, it will be in the cache forever (since you're holding a reference to it in |img|), but until onload is fired you can't be sure it's loaded.
Status: UNCONFIRMED → RESOLVED
Closed: 14 years ago
Resolution: --- → INVALID
> And I expect this to always work because no network i/o is necessary to load
> the data: uri.

Neither is it needed for file:// URIs, but we don't synchronously load those for obvious reasons.

To keep the processing model simple, all URI loads are always async, period.  Otherwise you could never tell when a load is done.
Status: RESOLVED → VERIFIED
You can tell when a load is done by reading image.completed.

I don't expect file:/// uris to be loaded sync, as they do i/o. But decoding data: uris is pure computation and should be possible to do sync. But whatever, i can deal with this pain too, as with all other web development pain.
Additionally i'll add what a gigantic pain this is for canvas developers. The canvas is an immediate mode rendering API, so the order you do matters a lot. 

In normal web stuff the html engine handles the async out of order loading of an image and putting it in place possible under other stuff when its finally loaded. 

However in the canvas you have to suspend all other canvas drawing operation until you get the onload callback, or you cannot guarantee the correct ordering of the drawing primitives. Not having a way to do this synchronously is a pretty big obstacle for canvas rendering.
> You can tell when a load is done by reading image.completed.

For the special case of images, yes, but not for loads in general.  So all loads are async and you watch load events.  While decoding a data: URI is possible to do sync, sending the various resulting notifications sync is NOT expected by either gecko internals or the web at large, for what it's worth.

I'd be fine with having a canvas API that takes image-format data and draws it into the canvas without sticking it into an HTMLImageElement first.  That seems to be the right way to address your use case; I suggest bringing it up with whatwg or public-html.
You need to log in before you can comment on or make changes to this bug.