Load an image for canvas in Firefox Addon SDK - javascript

I am writing an extension using the Pale Moon Addon SDK which is basically the exact same as Firefox's Addon SDK. I am trying to write an extension which notifies users when they have new messages on the social network deviantArt, but I'm running into a problem. I want the icon of the extension to change to show the number of messages the user has, so I created an empty document like this:
var {window: {document}} = require('sdk/addon/window');
Then I take that document and add to it an HTML5 canvas like so:
var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
So far so good, but the problem comes in when I try and add an image to that canvas. It says that Image is not defined.
if (is_core) {
img = new Image();
img.onload = function() {
image = ctx.drawImage(img, 6, 30, 32, 32);
}
img.src = self.data.url("h_core-status.png");
The problem, of course, is that I havn't loaded any module containing the Image object I need to create in order to add it to the canvas. However, I need that canvas to dynamically generate the icon for the extension. I considered adding a hidden iframe to the document and editing the canvas there, but it seems like a dirty solution.
Is there any Firefox Addon SDK module which contains an object like Image I can use, is there a better method to do what I'm trying to accomplish or am I going about this all wrong?

I solved this problem myself by realizing that JavaScript's new Image() just creates an img tag that we then set the src to and when it loads, using that img tag in the canvas. So by doing this explicitly rather than using new Image() we can avoid problems with the Image object not being defined.
Just replace:
img = new Image();
with
img = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
document.documentElement.appendChild(img);
Leave the rest of the code alone, it'll work.

Related

Once an image has failed loading, how can I make the browser retry?

I'm making a Chrome extension which in order to reduce bandwidth usage it stops all outcoming requests which are images.
I want to provide functionality where if the user clicks on the image (or technically a layer on top of that image) it would try to reload the image, this time not being blocked by the extension.
How can I tell the browser to retry loading the image? And if there isn't a straightforward way to do it, what would be a work around? Deleting the old image from the DOM and adding it again?
Any help is appreciated. :)
EDIT 1:
To answer #CBroe's question:
Using the chrome.webRequest.onBeforeRequest API in a background script.
To answer #jfriend00's question:
The usual placeholder "couldn't load image" icon, I guess also known as "broken file" icon:
See all those broken images?
That screenshot also illustrates the point of a layer on top of another image. Should those images not be broken, the loaded image would be there but that layer (the one in a dark grey which shows the image's dimensions) still remains there.
The desired href still exists there in the img tag:
If simply assigning the same src value to the img element is not enough¹, then create a new Image object in JavaScript, and assign the value to its src property.
¹ It might not be, if the browser just goes, “oh hey, that is the same value for the src attribute that the img already had, so I don’t have to do anything” – creating a new JS Image object however should make the browser request that resource again if he realizes he does not have it cached already.
What I would do instead is replace the URLs of the images with an image from your extension. A 1x1 pixel transparent GIF or PNG.
When you do this, add an attribute to all of the elements you replaced... something like data-yourextension-originalurl, with the URL of the original image. If the user then wants to load images, it's easy enough to go back and fix those image elements.
While I'm not too familiar with the Chrome API, a quick glance seems to suggest that there's no way to get the specific img element from each onBeforeRequest, which you'd need to know in order to figure out where to attach custom code.
This may be better accomplished with native JavaScript of some sort. For example, if Chrome lets you inject code on load, you could apply a function like the one below to all img elements after document load but before image load.
// Given an img element, replaces its src with a placeholder URL,
// and sets its click action to load its original src
function makePlaceholder(elem){
elem["data-oldtitle"] = elem.title;
elem["data-oldhref"] = elem.href;
elem["data-oldsrc"] = elem.src;
elem["data-oldonclick"] = elem.onClick;
elem.title = "Click to load the blocked image.";
elem.href = '';
elem.src = "http://example.com/placeholder.png";
elem.onClick = function(){
this.src = this["data-oldsrc"];
this.title = this["data-oldtitle"];
this.href = this["data-oldhref"];
this.onClick = this["data-oldonclick"];
};
}
The simple way to force reloading an image in JavaScript is:
var img = document.getElementById("myImage");
img.src = img.src.replace(/\?.+/,"") + "?" + new Date().getTime();
This adds a unique QueryString to the image which basically forces the browser to not use a cached version of the image.

Javascript Preloading Images: Add to DOM, or not?

Is it necessary to add an <img> to the DOM in order to preload it?
$(function whenDOMIsHappy(){
var $img = $('<img />')
.load(loadHandler)
.error(errorHandler)
.attr({src:"squatchordle-squashgarden.jpg"});
$img.appendTo('body .preloads'); // is this at all necessary?
});
// assuming <div class="preloads" style="display:none;"></div> exists in <body>.
I've seen mixed messages about this technique. I'm using jQuery, but the question applies to vanilla-people too.
I am interested in keeping this working in all major browsers.
All browsers I've tested do load images even if they're not in the DOM. You can test this with https://jsfiddle.net/84tu2s9p/.
const img = new Image();
img.src = "https://picsum.photos/200/300";
img.onload = () => console.log("loaded");
img.onerror = err => console.error(err);
Safari 13, 11.1, 10.1
Edge 18
Firefox 72, 70, 62
Chrome 78, 71
Opera 64
IE11
(Not meant to be an exhaustive list. I just tried a variety of versions and browsers.)
There's also the new image.decode() API that is intended for this use case of preloading images and avoids potential dropped frames when actually decoding the image to render it. Edge doesn't support it yet (Chromium-based Edge will though).
Given that HTML Canvas can use images without them being in the DOM, I think they have to load images.
as opposed to creating and then appending elements to the dom, why not just initialize a new image in javascript, then set its source to your images URL. this method should load your image without actually applying it to an element or rendering it on the dom - YET... take a peek:
someImageArray[0] = new Image();
someImageArray[0].src = "http://placehold.it/700x200/";
from here you are free to do what you wish with that image using javascript - render it directly in canvas or create an element out of it. however you might not even have to do anything. say if its already being referenced in other ajax based content. provided the URL is identical, the browser should use the cached version to draw the dom.
hope this helps here is a reference to a decent article about pre-loading with a few more options...
There is no guarantee that Images will be preloaded if you don't add it to the DOM! If you don't add it, the JavaScript Compiler can aggressively garbage collect the Image before it tries to load, because the element is not used at all.
This currently happens in firefox! There your images will not be preloaded if you don't add them to the DOM! - So be on the safe side and add them.

Phonegap: How to save a HTML5 canvas as image to device photo gallery/library

Hey I am developing an app that could tag an image with the geolocation and the time stamp, using Phonegap. I have been able to tag the image by editing the image as a canvas. Now I need to save that edited image to the device Photo gallery/library as a new image or replace the image selected to be tagged. The purpose of using phonegap is that the application must function cross-platform. Is there any way this could be achieved ?
The following code edit the image as canvas and converts the image back to a Data URI.
var canvas = document.getElementById("canvasPnl");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function(){
context.drawImage(imageObj,0,0,300,300 );
context.fillStyle="#FFFFFF";
context.fillText('Latitude: '+ lat.toString()+' Longitude: '+ lon.toString(), 0, 10);
context.fillText(new Date(), 0, 20);
};
imageObj.src=imageURI;
dataURI= canvas.toDataURL();
Can this be converted to an image object and saved to phone gallery???
https://github.com/devgeeks/Canvas2ImagePlugin apparently does what you want, although I've not tried it.
I don't think you can make the image save in the gallery using just JavaScript but you can send the user to the image or display the image where the user can manually save it.
Maybe you could try the plugin I wrote for IOS (If you want to save a canvas element to photogallery, you could get the dataURI of the canvas the use the downloadWithUrl method below). Hope it works for you.
here is the git link: https://github.com/Nomia/ImgDownloader
Short Example:
document.addEventListener("deviceready",onDeviceReady);
//google logo url
url = 'https://www.google.com/images/srpr/logo11w.png';
onDeviceReady = function(){
cordova.plugins.imgDownloader.downloadWithUrl(url,function(){
alert("success");
},function(){
alert("error");
});
}
//also you can try dataUri like: 1px gif
//url = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
you can also save a local file to image gallery use the download method

Javascript slowly "flush" DOM Tree

I have really strange problem. I'm trying to get width and height of an image using following way:
Create a image tag and add .src to it.
add this image tag to document.body.
making this image tag visible (display:inline).
getting .offsetWidth and .offsetHeight of element.
hidding image tag(display:none);
all this is done using JS and it all work really well on my localhost, but when I uploaded a site to my client hosting provider I was amazed. offsetWidth and .offsetHeight was 0 in step 4. Why do that happen? I think that I need some kind of "flush" after step 3 before step 4, but I'm not exactly sure. Any suggestions ? Thank you.
You have to wait for the image to actually load over the network. You don't need to add the thing to the DOM either:
var img = new Image();
img.onload = function() {
handleImageSize(this.width, this.height);
};
img.src = "http://whatever.com/your/img.jpg";
Here, "handleImageSize" would be a function you write to do whatever it is you need to do with the image dimensions.
This was probably caused by the image not being loaded yet. Try something like this:
img.onload = function() {
// get the offsetWidth and offsetHeight
}
As other answers suggest, is due to the image not being fully loaded by the DOM. This was working fine on your local server as I suspect you were loading images locally, meaning they were almost instantaneous; however after moving them to the server there is a slight delay. It's an easily overlooked problem, that is easily fixed.
Other answers will do the trick; but here's the jQuery version for sake of argument
var img = $('<img>', {
src: 'http://dummyimage.com/150/000/fff.gif'
}).one('load', function() {
var offsets = $(this).offset();
});
$('body').append(img);
jsFiddle

Preloading image gracefully in Javascript (without any JS library)?

I have an image with set src attribute.
I would like to replace image, but connection with the server is slow and time that it takes to load a new image is not negligible.
Is there possibility to create internal Image object, set kind of "onLoadListener" on it, load an image and then set it to original image src attribute?
You can pre-load images in JavaScript like this...
myImage = new Image();
myImage.onload = function () { alert("Loaded"); };
myImage.src = "logo.gif";
You can put the logic to pop the image on the page instead of alert-ing.

Categories

Resources