How to reference this preloaded image - javascript

How would I reference an image preloaded from this javascript? This code comes from the question at
stackoverflow: preload hidden CSS images
<script language="JavaScript">
function preloader()
{
// create object
imageObj = new Image();
// set image list
images = new Array();
images[0]="image1.jpg"
imageObj.src=images[0];
}
</script>

It's a logical error in your code as pointed out by Matt H.
Instead creating a separate Image object for each individual images. You are just creating one object and keep changing the src of that object.
function preloader() {
// counter
var i = 0;
// set image list
images = new Array();
images[0] = "image1.jpg"
images[1] = "image2.jpg"
images[2] = "image3.jpg"
images[3] = "image4.jpg"
//create an array to hold all the Image objects
imageObjs = [];
// start preloading
for (i = 0; i <= 3; i++) {
var imageObj = new Image(); //create new Image object for each image
imageObj.src = images[i]; //set the src of new Image object to current image
imageObjs.push(imageObj); //add the current Image object to the array
}
}

In your code, you are depending on the browser cache as the "preloader". Only the last images[i] source is actually held in the imageObj variable. Just setting the src value of an image will pull it from the browser cache.
A proper method of preload would be to create an array of imageObj image objects. You still reference through `.src', but now you have image objects in Javascript memory rather than the browser cache.

Related

Reduce File Size Of An Image In A File Upload Preview, Without Affecting The Size Of The File To Be Uploaded - JavaScript

I have some image preview functionality as part of a file uploader that shows the images prior to upload. Within this process the image previews use a htmlImageElement.decode() method that returns a promise so various frontend validations etc can happen on the images. This decode() method is run within a function that is called in a forEach() loop in relation to the files from a file <input> element.
The context
Even though I am limiting the number of files per upload to 10, because large files are allowed, if a user attaches 10 (large) files the image previewer is laggy, both in terms of image render, and also when any images are deleted from the previewer.
The Question
Is there anyway to reduce the file size of the image preview, without affecting the file size of the image to be uploaded?
You can add width and height parameters to the new Image() constructor, i.e. new Image(300,300), but these only affect the display size, not the file size, and if you alter the naturalHeight and naturalWidth properties, this changes the size of the file itself that is being uploaded, whereas what I want is just the preview file size to be smaller?
// this function is invoked in a forEach loop as part of a wider code block related to the individual files from a file <input> element
function showFiles(file) {
let previewImage = new Image();
// Set <img> src attribute
previewImage.src = URL.createObjectURL(file);
// get the original width and height values of the thumbnail using the decode() method
previewImage.decode().then((response) => {
// get image dimensions for validations
let w = previewImage.naturalWidth;
let h = previewImage.naturalHeight;
let imgs = document.querySelectorAll('img') // redeclare under new var name inside promise
}).catch((encodingError) => {
// Do something with the error.
});
} // end of showfiles(file)
A canvas can be used to create a resized clone of the original image, then use the canvas blob as source for preview:
// this function is invoked in a forEach loop as part of a wider code block related to the individual files from a file <input> element
function showFiles(file) {
let previewImage = new Image();
// Set <img> src attribute
previewImage.src = URL.createObjectURL(file);
// get the original width and height values of the thumbnail using the decode() method
previewImage.decode().then(() => {
// get image dimensions for validations
let w = previewImage.naturalWidth;
let h = previewImage.naturalHeight;
const W = w * 0.3, H = h * 0.3;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = W, canvas.height = H;
ctx.drawImage(previewImage, 0, 0, W, H);
canvas.toBlob((blob) => {
previewImage.src = URL.createObjectURL(blob);
document.body.append(previewImage);
});
}).catch((encodingError) => {
// Do something with the error.
});
} // end of showfiles(file)
images.addEventListener('change', (e) => {
[...e.target.files].forEach(showFiles);
});
<input id="images" type="file" multiple>

Javascript canvas how to drawImage a lot of images

How i can draw a lot of image in canvas?
I have a lot of images url array and need output it. How to do with good perfomance.
me example code (jsfiddle: http://jsfiddle.net/6sunguw4/):
$(document).ready(function () {
var bgCanvas = document.getElementById("bgCanvas");
var bgCtx = bgCanvas.getContext("2d");
bgCanvas.width = window.innerWidth;
bgCanvas.height = window.innerHeight + 200;
var array = new Array();
array[1] = 'https://developer.chrome.com/webstore/images/calendar.png';
array[2] = 'http://www.w3schools.com/html/html5.gif';
array[3] = 'http://www.linosartele.lt/wp-content/uploads/2014/08/images-9.jpg';
img0 = new Image();
img0.onload = function() {
bgCtx.drawImage(img0, 0,0, 100, 100);
}
img0.src = array[1];
img2 = new Image();
img2.onload = function() {
bgCtx.drawImage(img2, 100,0, 100, 100);
}
img2.src = array[2];
img3 = new Image();
img3.onload = function() {
bgCtx.drawImage(img3, 200,0,100,100);
}
img3.src = array[3];
});
Here's code to load all images from the URLs you put into your array without having to hand code 2000 times new Image/.onload/.drawImage (I call the array imageURLs in the example code below):
// image loader
// put the paths to your images in imageURLs[]
var imageURLs=[];
// push all your image urls!
imageURLs.push('https://developer.chrome.com/webstore/images/calendar.png');
imageURLs.push('http://www.w3schools.com/html/html5.gif');
imageURLs.push('http://www.linosartele.lt/wp-content/uploads/2014/08/images-9.jpg');
// the loaded images will be placed in imgs[]
var imgs=[];
var imagesOK=0;
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
function start(){
// the imgs[] array now holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
bgCtx.drawImage(imgs[0], 000,0, 100, 100);
bgCtx.drawImage(imgs[1], 100,0, 100, 100);
bgCtx.drawImage(imgs[2], 200,0, 100, 100);
}
For better loading performance:
Browsers typically download only 6-8 files at a time from one domain. So your 2000 images would require 2000/8 == 250 separate sequential calls to your domain to load.
You can combine your 2000 into one or more spritesheets (preferably 6 or less spritesheets). That way the browser can download the 1-6 spritesheets containing your 2000 images in one trip.
You can use the extended version of context.drawImage to pull any desired image from the spritesheet. For example, assume an image you need is located at [200,200] on your spritesheet and is 100x100 in size. You can draw that image on your canvas like this:
bgCtx.drawImage(spritesheet,
200,200,100,100 // clip the image from the spritesheet at [200,200] with size 100x100
125,250,100,100 // draw the clipped image on the canvas at [125,250]
);
There's not much you can do with the code itself. drawImage seems pretty optimized, and it's the raw amount of images what could slow things down.
One thing you can maybe do, depending on your goal, is to prepare composite images. For example, those 3 images could be easily converted into a single PNG image, and then it would require only one drawImage call. However, if you plan to shift their places or some effects, I'm afraid you're stuck with what you have.

Extract images from PDF file with JavaScript

I want to write JavaScript code to extract all image files from a PDF file, perhaps getting them as JPG or some other image format. There is already some JavaScript code for reading a PDF file, for example in the PDF viewer pdf-js.
window.addEventListener('change', function webViewerChange(evt) {
var files = evt.target.files;
if (!files || files.length === 0)
return;
// Read the local file into a Uint8Array.
var fileReader = new FileReader();
fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
var buffer = evt.target.result;
var uint8Array = new Uint8Array(buffer);
PDFView.open(uint8Array, 0);
};
var file = files[0];
fileReader.readAsArrayBuffer(file);
PDFView.setTitleUsingUrl(file.name);
........
Can this code be used to extract images from a PDF file?
If you open a page with pdf.js, for example
PDFJS.getDocument({url: <pdf file>}).then(function (doc) {
doc.getPage(1).then(function (page) {
window.page = page;
})
})
you can then use getOperatorList to search for paintJpegXObject objects and grab the resources.
window.objs = []
page.getOperatorList().then(function (ops) {
for (var i=0; i < ops.fnArray.length; i++) {
if (ops.fnArray[i] == PDFJS.OPS.paintJpegXObject) {
window.objs.push(ops.argsArray[i][0])
}
}
})
Now args will have a list of the resources from that page that you need to fetch.
console.log(window.args.map(function (a) { page.objs.get(a) }))
should print to the console a bunch of <img /> objects with data-uri src= attributes. These can be directly inserted into the page, or you can do more scripting to get at the raw data.
It only works for embedded JPEG objects, but it's a start!
Here is link to working example of getting images from pdf and adding alpha channel to Uint8ClampedArray to be able to display it. It displays images in canvas.
Example in codepen: https://codepen.io/allandiego/pen/RwVGbyj
Getting data url from canvas to be able to display it in img tag:
const canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
const ctx = canvas.getContext('2d');
ctx!.putImageData(imageData, 0, 0);
const dataURL = canvas.toDataURL();

Internet Explorer 9 sometimes draws blank images on canvas

I have a web application that generates images on the fly and then renders (segments of) them on the client using canvas - the general code looks something like this (simplified)...
var width = ...
var height = ...
var img = new Image();
img.onload = function(){ // Set onload before setting image source ;)
var canvas = document.createElement("canvas");
canvas.setAttribute('width',width);
canvas.setAttribute('height',height);
var context = canvas.getContext("2d");
context.drawImage(this,0,0,width,height,0,0,width,height);
}
img.src = ...
In firefox and chrome, this works fine. In IE9 (and sometimes IE10), this sometimes results in a blank image. As a workaround, I put in...
var width = ...
var height = ...
var img = new Image();
img.onload = function(){
var canvas = document.createElement("canvas");
canvas.setAttribute('width',width);
canvas.setAttribute('height',height);
var context = canvas.getContext("2d");
window.setTimeout(function(){
context.drawImage(img,0,0,width,height,0,0,width,height);
}, 10); // 10 millisecond delay here seems to give IE time to make sure the image is actually ready
}
img.src = ...
Obviously, putting in random delays is making me nervous - I would much rather figure out why this happens. Is there another event type / method / property on images that may be used? Could there perhaps be something in the http headers sent down with the images / the encoding / transfer method that is causing this?
Since drawing images on the canvas seems to be something that trips up new users a lot, searches mostly yield instances where the developer set the source before the onload method. The closest other question / reply I was able to find was this : https://stackoverflow.com/a/15186350/470062
Edit:
I have updated the examples to include width and height definitions at the start
Edit 29/Apr/2013:
The 10 millisecond delay is not always sufficient - I have changed the code to check the canvas pixels to determine if anything has been drawn - This feels like such an ugly hack though - I would love to know if there is a better way :
... snip - this is at the end of the image load callback..
if((navigator.appVersion.indexOf("MSIE")) >= 0){
function checkAndRedraw(){
context.clearRect(0,0,width,height);
context.drawImage(img, 0, 0, width, height);
var imageData = context.getImageData(0, 0, width, height),
data = imageData.data,
len = data.length;
for (var i = 0; i < len; i += 4){
if(data[i] || data[i+1] || data[i+2]){
scheduleRedraw = null; // prevent memory leak
return; // A pixel contained some non empty value so something was drawn - done.
}
}
scheduleRedraw();
}
var redrawHackTimeout;
function scheduleRedraw(){
window.clearTimeout(redrawHackTimeout);
redrawHackTimeout = window.setTimeout(checkAndRedraw, 500);
}
scheduleRedraw();
}
//END IE9 Hack
I have the same issue in IE9, what I had to do is this too:
theImage = new Image();
theImage.onload = function() {
that = this;
setTimeout(function() {
that.onload2();
}, 100);
};
theImage.onload2 = function(){
#your old load function code
}
theImage.src = 'http://....';
I don't understand why ie9 triggers load image function when it's not actually loaded or not "usable" yet in a canvas. it makes me pull my hair out.
var img = new Image();
img.src = ...
img.onload = function(){ // Set onload before after setting image source ;)
var canvas = document.createElement("canvas");
canvas.setAttribute('width',width);
canvas.setAttribute('height',height);
var context = canvas.getContext("2d");
context.drawImage(this,0,0,width,height,0,0,width,height);
}
You must set the src, then wait for the image to load.

Create an Image object from scratch? (Javascript)

I want to create an image object from scratch. Here is the idea:
var image = new Image();
var image2 = new Object();
/* heres where the magic is
\\\\\\\\\\\\\\\\\\\\\\\\\\\
\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
if image = image2
alert('sucess');
The goal is that I need to edit the Image object to accept video files. I suppose the solution could also be prototypical if it changed the structure of the Image object appropriately.
function videotr(){
media = document.createElement('video');
media.preload = true;
//media.controls = true;
media.className = 'c1';
media.id = 'it';
document.getElementById('crop').appendChild(media);
//media.loop = true;
//media.autoplay = true;
return media;
}
this works

Categories