Can not load images from cache - javascript

Trying to build a gallery with thumbnails.
You click a thumbnail, the main image container will show it.
It seems that when I change the URL of the container, it will ALWAYS reload the image from the Internet and not cache it.
I tried 2 approaches both have the same result.
First :
//save to cache right when script is loaded
var cacheImages =[];
preloadimgs();
function preloadimgs(){
for(var k=0;k<5;k++) {
var img = new Image();
img.src = currentStore.product.media.photos[k];
cacheImages.push(img);
}
}
//load
function thumb(arg){
var prvimgShow = cacheImages[arg].src;
var finalurl="url("+prvimgShow+")";
$("#preview").stop().animate({opacity: 0.7},100,function(){
$(this).css({'background-image': finalurl})
.animate({opacity: 1},{duration:200});
});
}
Which will result in a VERY slow reloading of that photo whenever I click a thumb.
Second(which I asked about here already):
Here I get the photo FROM the thumbnail background as a source :
//get a thumb's background photo
var prvimgShow = document.getElementById("thumb0").style.backgroundImage;
//show it
$('#thumb0').on('click', () => {
$("#preview").stop().animate({
opacity: 0.7
}, 100, function() {
$(this).css({
'background-image': prvimgShow
})
.animate({
opacity: 1
}, {
duration: 200
});
});
})
BOTH RESULT IN RELOADING OF THE IMAGE WHICH TAKES 2 SECONDS.
The images are very small (300k), and for a gallery this is a bad UX.

While I don't know internals of browser and why it is not caching, One of the solution I can think of is:
Don't use the direct url and instead download the file and make it into a blob url. Keep the reference of the blob url instead in cacheImages just as you are doing. Then use the blog url else where and resource will not be downloaded again.
You can refer How to get a File() or Blob() from an URL in javascript? for how to fetch image and convert it to a blob url.

If you want the browser to load the images from the cache, you have to configure this on the server. You can use Etag-Header or Cache-Control Header. This will let the browser know that it can load these assets from the cache.

Related

How to cache an image array?

I'm trying to make an Image sequence scrolling website, something like Apple Airpod Pro.
I'm facing an issue with images loading, each image will load once it displays only.
It appears that I have to preload all images on dom to cache it out so it'll look smooth when scrolling.
So I'm looking for a better way to cache my images
Here is my image array :
const MAX = 4875; //last image number
const PREFIX = "images/image-scroll/Test_"; //image location
const EXT = ".jpg"; //image format
var images = [];
for (let i = 0; i <= MAX; i += 1) {
images.push(
PREFIX + ("00000" + i).slice(-5) + EXT
);
}
Currently, I'm preloading images this way:
//Preload Images
jQuery('document').ready(function(){
jQuery.each(images, function() {
jQuery('<img />').attr('src', this).appendTo('body').hide();
});
});
This method works, but it makes the site heavy and it'll keep creating img elements every time you update the page.
Is it possible if I can just load all images to cache it without adding elements to the code?
One possible solution is to call GET requests to the image URLS directly instead of waiting for browser to call it from the DOM element. This way the DOM is not modified and the images may be cached in the browser.
The network and caching layers should work similarly to how it would if you had added it to DOM.
//Preload Images
jQuery('document').ready(function(){
jQuery.each(images, function() {
fetch(this); // uses the fetch API to do a get request. You may use the jQuery AJAX if required.
});
});

Why isn't phaser.js able to load an image from a third-party domain?

I'm learning phaser.js, and I cant even load the image.
Here is the code:
// Need state. All game logic goes in state
var GameState = {
// Load all your images. Thats what the preload function is
preload : function(){
//Load Image
this.load.image( 'background', 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSMxwX5oTml7qBFmUD3vEIzEhqLQfakBVjmkQezA8HKs4KnT-2Q' );
},
//Execute after everything is loaded
create: function(){
//From top left param = (x,y)
this.background = this.game.add.sprite(0,0, 'background');
},
update: function(){
}
}
// New Game instance, 3rd parameter WEBGL or CANVAS automatic GL
var game = new Phaser.Game(640,360,Phaser.automatic);
// add state to game
// First just a name, second par is the actual Object
game.state.add('GameState', GameState);
game.state.start('GameState');
And here is the image that clearly shows that it doesen't load:
Your image isn't showing up because Phaser can't make use of cross-origin images, so all images need to be loaded from the same origin. In practice, this means that instead of loading the image directly from gstatic.com, you need to first download the image to your computer, then move it to your Phaser project folder and load it using a relative path.
For more information, please see the Wikipedia article on the Same-Origin Policy.

Copy canvas from one page to another without crossing max character limit

I want to play a video in HTML video element and take snapshot on pause. The snapshot is displayed on the page inside a canvas. Now I want the same snap to appear on another page and for this I am trying to encode the snapshot in base 64 using toDataUrl() method & pass it through URL.
But the maximum length of URL can be 2048 char while the output of toDataUrl is much bigger. How to proceed?
Working fine:
video.addEventListener('pause', function(){
$(this).hide();
$("#canvas1").show();
draw( video, thecanvas, img);
}, false);
function draw(video,thecanvas,img){
var context = thecanvas.getContext('2d');
context.drawImage(video,0,0,thecanvas.width,thecanvas.height);
var dataURL = thecanvas.toDataURL('image/jpeg',.1);
img.setAttribute('src',dataURL);
}
Not working: The function to direct to another page
function toskuentry(){
var imgsrc = $('#thumbnail_img').attr('src');
window.location.href = "sku_entry.php?imgsrc="+imgsrc;
}
Don't pass it through the URL, use HTML5 Web Storage. You can use either sessionStorage or localStorage:
function toskuentry(){
localStorage.setItem("img", $('#thumbnail_img').attr('src'));
}
On the next page you can access it by localStorage.getItem("img");.
One good option would be to use Firebase. They have an example of doing that.
https://www.firebase.com/tutorial/#session/n24v8lvnltc
Firebase uses local storage when offline, so that means you could also use local storage if you didn't want to use Firebase.
something like
localStorage["data"] = dataURL;
//...other page
var dataURL = JSON.parse(localStorage["data"]);

fabric.js - toDataURL shows blank page when there is image on canvas

I'm using fabric.js for my canvas application, toDataURL method works properly except when there is a image on canvas. When i add an image to canvas and call toDataURL it shows me a blank page.
//When i call it from chrome console
canvas.toDataURL();
//It returns a working data url with no problem.
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAGkCAYAAAAPPajHAAAgAElEQ…fpmwgogX1TrjoqP0FACewngtZh+iYCSmDflKuOyk8Q+H+CKCqUW0spTgAAAABJRU5ErkJggg=="
//When i execute same code in a .js file it returns a data url which shows a blank image.
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAGkCAYAAAAPPajHAAAKC0lEQ…sBAmEBAw6XJzoBA/YDBMICBhwuT3QCBuwHCIQFDDhcnugEHt/IAaW9dzALAAAAAElFTkSuQmCC"
It's interesting that it's working on chrome dev console but not works in .js file even if it's same code. I noticed that working data url finishes with '==' but other one not. However i don't know what this means.
You didn't give much to analyze but I'll go from there on my gut feeling.
The image you are using is probably violating Cross-Origin Resource Sharing (CORS) requirements. When this happens the canvas will return a blank image when you try to get the pixel data either by using canvas.toDataURL() or context.getImageData().
It basically happens when the image is not located on the same domain as the page or is loaded from the file:// protocol.
You can try to add the following to the image object before setting the source:
image.crossOrigin = 'anonymous';
image.src = '...';
From tag:
<img crossOrigin='anonymous' src='...' alt='' />
This will request permission from the server to use the image cross-origin. If the server allows you should be fine.
If not you will either have to copy the image to your own server so it loads from the same domain as your page, or create a proxy page that loads the image externally and serves it to your page from the proxy page (it sounds complicated but really isn't).
If the image does not show up at all on the canvas you are probably not using load callback which you need since image loading is asynchronous. If so just add:
image.onload = function() {
/// now you can draw the image to canvas
}
image.crossOrigin = 'anonymous';
image.src = '...';
The problem is solved. The point i missed is, i was calling toDataURL function before canvas is loaded, that's why it was showing me a blank page.
canvas.loadFromJSON(json,function(){
var dataURL = canvas.toDataURL();
});
This solved my problem when i gave toDataURL() function as a callback to loadFromJSON function.
But after a while i had a different issue about CORS when i tried to upload my images from s3 bucket and i solved this problem as upward solution.
I was facing the same issues when I was trying to generate images from the canvas using Fabricsjs and generate PDF from images using JSPDF so below is my case I also spend hours on this may this can help someone to save time.
Load the canvas from JSON that i.e
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(obj, object) {
//fabric.log(obj, object);
});
Canvas was drawing images all fine then I was generating the images from that canvas it was a case of multiple images in a single canvas and I was generating PDF based on each page of the canvas.
Instead of this
canvas.toDataURL('image/png', 0.1)
I used this and it starts returning me the propper images dataurl
var imgData = document.getElementById('canvas_0').toDataURL();
Below are snippets
$("#pdfSelector .canvas-container").each(function(index, value){ // canvas selector
html2canvas($("#canvas_"+index), { // html2canvas used to get images
onrendered: function(canvas) { // on successfully render of images
//var imgData = canvas.toDataURL('image/png', 0.1);
var imgData = document.getElementById('canvas_0').toDataURL();
const imgProps= doc.getImageProperties(imgData);
const pdfWidth = doc.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
doc.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight, 'page_'+index, 'FAST');
}
});
});

How to load an other image, if the current image loads slow?

I'm working on a HTML5 canvas game, and I want to load a high resolution image as background. This image is 10MB, so if the image loads slow, then I want to load a smaller image instead.
var myimg = new Image();
myimg.onload = function() {
clearTimeout(t);
alert('high resolution image loaded');
};
mximg.src = 'path/to/highres.png';
var t = setTimeout(function(){
//cancel loading somehow ?
myimg.onload = function() {
alert('low resolution image loaded');
};
myimg.src = 'path/to/low_res.png';
},5000);
should I cancel somehow the loading, or it's cancelled if I edit the src attribute?
One alternative "solution" would be to load the low-res image first. Only if it loaded quickly enough you start to load the high-res version to replace it.
There are three possible benefits as I see it:
You avoid having to worry about cancelling the load :-)
You avoid loading unnecessary data (the partially downloaded high-res image) when the user is on low bandwidth, but instead load unnecessary data (the complete low-res image) when the user is on high bandwidth (in which case it doesn't matter that much anyway).
While you load the high-res image, you have the option to show the low-res image as a placeholder (requires that you load the low-res and high-res images into two separarate DOM Image objects and swap out the low-res with the high-res).
You can't stop the loading of images, however it is possible to cancel an ordinary AJAX request (see this solution on SO). Usually images aren't loaded via AJAX for good reasons, but you can work around this by sending the image as a base64 encoded string. So you let PHP read the image and convert it to base64. This string can be sent to JS via AJAX and "directly" drawn to your canvas (solution on SO).
I really don't know if this is the best way to do this... Anyways, see if this works for you:
HTML:
<canvas id="background" width="800" height="600"></canvas>
JavaScript: (using jQuery)
function drawBackgroundImage(src) {
var image = $("<img/>").load(function(){
$("canvas#background")[0].getContext("2d").drawImage(image[0], 0, 0);
}).attr("src", src);
}
function loadImage(highres, lowres) {
var t;
var xhr = $.ajax({
type: "POST",
url: "load_image.php",
data: "image=" + highres,
success: function(imgbinary){
if (imgbinary != "") {
clearTimeout(t);
drawBackgroundImage(imgbinary);
}
}
});
t = setTimeout(function(){
xhr.abort();
drawBackgroundImage(lowres);
}, 5000);
}
loadImage("path/to/highres.png", "path/to/low_res.png");
PHP: (load_image.php)
(This uses part of a function from the PHP manual.)
<?php
$result = "";
#ob_start();
if (isset($_POST["image"])) {
$filename = $_POST["image"];
if (file_exists($filename)) {
$filetype = pathinfo($filename, PATHINFO_EXTENSION);
$imgbinary = fread(fopen($filename, "r"), filesize($filename));
$result = "data:image/".$filetype.";base64,".base64_encode($imgbinary);
}
}
#ob_end_clean();
echo $result;
?>

Categories