Preloading images (in Chrome) [duplicate] - google-chrome

I am pre-loading some images and then using them in a lightbox. The problem I have is that although the images are loading, they aren't being displayed by the browser.
This issue is specific to Chrome. It has persisted through Chrome 8 - 10, and I've been trying on and off to fix it all this time and have got nowhere.
I have read these similar questions,
Chrome not displaying images though assets are being delivered to browser
2 Minor Crossbrowser CSS Issues. Background images not displaying in Google Chrome?
JavaScript preloaded images are getting reloaded
Which all detail similar behaviour but in Chrome for Mac. Whereas this is happening in Windows.
All other browsers seem to be fine.
If you have Firefox and Chrome open, load the page in Firefox, and then in Chrome, the images appear.
Once you have manually loaded the images, using the Webkit webdev toolbar thingy, they always show up
All the links the images and such are fine and working
Clearing everything from Chrome doesn't seem to make any difference (cache, history, etc)
If anyone has any ideas it would be fantastically helpfull, as I'm literally all out of options here.
PS, Apologies if there are late replies, I'm off on holiday for a week tomorrow! :D
Update
Here is the javascript function which is preloading the images.
var preloaded = new Array();
function preload_images() {
for (var i = 0; i < arguments.length; i++){
document.write('<');
document.write('img src=\"'+arguments[i]+'\" style=\"display:none;\">');
};
};
Update
I'm still having issues with this, and I've removed the whole preloading images function. Perhaps delivering a style sheet via document.write() isn't the best way?

Chrome might not be preloading them as it's writing to the DOM with no display, so it might be intelligent enough to realise it doesn't need to be rendered. Try this instead:
var preloaded = new Array();
function preload_images(){
for (var x = 0; x < preload_images.arguments.length; x++)
{
preloaded[x] = new Image();
preloaded[x].src = preload_images.arguments[x];
}
}
The Javascript Image object has a lot of useful functions as well you might find useful:
http://www.javascriptkit.com/jsref/image.shtml
onabort()
Code is executed when user aborts the
downloading of the image.
onerror()
Code is executed when an error occurs
with the loading of the image (ie: not
found). Example(s)
onload()
Code is executed when the image
successfully and completely downloads.
And then you also have the complete property which true/false tells you if the image has fully (pre)loaded.

It turns out that Chrome takes into account the HTTP Caching and discards any preloaded images immediately after preload if the Caching is incorrectly set to expire.
In my case I am generating the images dynamically and by default the response was sent to the browser with immediate expiration.
To fix it I had to set the following below:
Response.Cache.SetExpires(DateTime.Now.AddYears(1));
Response.Cache.SetCacheability(HttpCacheability.Public);
return File(jpegStream, "image/jpeg");

Related

How to get GIFs "out of sync"

I'm trying to reliably load the same GIF, but have it play at different times.
Overall, I expected to find a spec that would tell me what the rules were for rendering (i.e. what's in sync what's out of sync), but I haven't been able to find any such standard. Is there any spec for how GIFs are rendered with respect to timing?
Consider these examples:
https://i.stack.imgur.com/LwWBD.gif
https://i.stack.imgur.com/LwWBD.gif?blah=1
https://i.stack.imgur.com/3As1l.gif
Safari, seems to keep everything in sync regardless of the URL. Chrome on the initial load has the timings separate by URL, but eventually has them in sync. Firefox seems to depend solely on the URL without any parameters to determine syncing.
Any insight would be appreciated.
Tested on Chrome, abney317's answer works for me. I was able to get staggered start times by adding a query string to the end of the URL.
const image = document.querySelector('img');
img.src = imgUrl + '?id=' + Math.floor(Math.random() * 100);

speechSynthesis.speak not working in chrome

I'm using chrome Version 55.0.2883.87 m (64-bit) on Windows 10.
The following simple html file reproduces the problem and is extracted from my more complex app. It is supposed to speak the 3 words on page load. It works on MS Edge and Firefox but does not work on chrome. This code was working for me on Chrome no problem a couple weeks back.
<html>
<head>
<script lang="javascript">
window.speechSynthesis.speak(new SpeechSynthesisUtterance("cat"));
window.speechSynthesis.speak(new SpeechSynthesisUtterance("dog"));
window.speechSynthesis.speak(new SpeechSynthesisUtterance("bark"));
</script>
</head>
<body></body>
</html>
I may never know for sure, because this problem was intermittent, but it seemed to go away after I started to cancel right before speak.
utter = new window.SpeechSynthesisUtterance("cat");
window.speechSynthesis.cancel();
window.speechSynthesis.speak(utter);
I don't think the cancel necessarily has to come between the utterance object creation and use. Just that it come before every speak. I may have had a different problem as I was only creating one utterance object, not a bunch. I did only see it on Chrome 78. Using Windows 7, 64-bit. Never saw the problem on Firefox or Edge.
EDIT 2 weeks later. No recurrences after several dozen tries. It seems .cancel() solved my problem. My symptoms were: calling speechSynthesis.speak() in Chrome would sometimes not start the speech. There were no immediate indications of a problem in the code, speechSynthesis.speaking would be true and .pending would be false. There would be no events from the utterance object. Normally, when speech would work, I'd get a 'start' event about 0.1 seconds after calling .speak().
speechSynthesis.speak() is no longer allowed without user activation in Google's Chrome web browser since 2018. It violates autoplay policy of Google Chrome. Thus Google Chrome has managed to revoke it's autoplay functionality but you can make use of it by adding a button to make a custom call.
You can visit here to check the status provided by chrome itself also below is the image attached which clearly shows that speechSynthesis.speak() call is prohibited without user's permission.
Link to image
Link to article by Google Chrome
To add to this, the issue for me was the playback rate on the instance of SpeechSynthesisUtterance was above 2. I discovered it must be set to 2 or less in chrome (although it works with higher rates in other browsers like safari).
In chrome, if the utterance rate is above 2, it causes the window.speechSynthesis to be stuck, and needs window.speechSynthesis.cancel() before it will play audio again (at a valid rate below 2) via .speak().
Did your text to voice tryout work only once? Here is why.
In chrome you have to cancel the speechSynthesis, otherwise its not compliant to googles autoplay policy. So you should start your script with:
window.speechSynthesis.cancel()
To cancel any speech synthesis that happened before.
resultsDisplay = document.getElementById("rd");
startButton = document.getElementById("startbtn");
stopButton = document.getElementById("stopbtn");
recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition)();
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.maxAlternatives = 5;
recognition.onresult = function(event) {
resultsDisplay.innerHTML = "You Said:" + event.results[0][0].transcript;
};
function start() {
recognition.start();
startButton.style.display = "none";
stopButton.style.display = "block";
}
function stop() {
recognition.stop();
startButton.style.display = "block";
stopButton.style.display = "none";
}
.resultsDisplay {width: 100%; height: 90%;}
#stopbtn {display: none;}
<div class="resultsDisplay" id="rd"></div>
<br/>
<center>
<button onclick="start()" id="startbtn">Start</button>
<button onclick="stop()" id="stopbtn">Stop</button>
</center>
Try
utterance = new SpeechSynthesisUtterance("cat, dog, bark");
speechSynthesis.speak(utterance);
I made a Weave at LiveWeave.
Instead of specifying the text while calling new, you could try specifying an object with rate, volume, and text separately, and then converting it to voice.

How do I make my html gif unloop? [duplicate]

I have an animated gif in an img tag that I start by rewriting the src attribute. The gif was created, though, to loop and I only want it to play once. Is there a way, with Javascript or jQuery, to stop an animated gif from playing more than once?
I was having the same problem with an animated gif. The solution is rather simple.
Open the Animated gif in Photoshop.
Go to the Window tab and select timeline(if the timeline is not already open).
At the bottom of the timeline panel, you will find an option, which says "Forever".
Change that to "Once".
Go to File> Export> Export for Web and save it as a gif.
That should do it.
can you find out how long the gif takes to loop once?
if so then you can stop the image like this:
pseudocode:
wait until the end of the image (when it is about to loop)
create a canvas element that has a static version of the gif as currently displayed drawn on it
hide gif
display canvas element in a way that makes it look like the gif froze
javascript:
var c = $("canvas")[0];
var w = c.width;
var h = c.height;
var img = $("img")[0];
setTimeout(function () {
c.getContext('2d').drawImage(img, 0, 0, w, h);
$(img).hide();
$(c).show();
},10000);
jsfiddle
edit:
I forgot to add reference to the original answer that I took this from, sorry
Stopping GIF Animation Programmatically
that one doesn't address the time factor you need for only one loop
Also, it has been mentioned that this approach is problamatic in certain cases (It actually didn't work when I try it in firefox right now...). so here are a few alternatives:
mentioned by Mark: edit the gif itself to avoid looping. this is the best option if you can.
but I've run into cases where it was not an option (like automated generation of images by a third party)
instead of rendering the static image with canvas, keep a static image version and switch to stop looping . this probablyhas most of the problems as the canvas thing
Based on this answer, it's kinda expensive, but it works. Let's say a single loop takes 2 seconds. At a setTimeout after 2 seconds kick in a setInterval, that would reset image source every millisecond:
setTimeout(function() {
setInterval(function() {
$('#img1').attr('src',$('#img1').attr('src'))
},1)
}, 2000)
again, probably just a proof of concept, but here's demo: http://jsfiddle.net/MEaWP/2/
Actually it is possible to make a gif to stop after just one iteration or any specific number of iterations, see an example below (if it is not already stopped), or in jsfiddle.
To do that the gif must be created with number of iterations specified. This could be done using Screen to Gif, it allows to open a gif or a bunch of images and edit it frame by frame.
This solution also allows you to reset the animation by imgElem.src = imgElem.src; but this does not work in MS IE/Edge.
Jurijs Kovzels's answer works in some condition but not in all.
This is browser-dependent.
It works well with Firefox. But In Google Chrome and Safari, it does not work if the gif is on the same server. The example he provided works because the gif is on the external server.
To restart gifs stored on the internal server, using Google Chrome and Safari, you need extra steps to make it work.
const img = document.getElementById("gif");
img.style = "display: none;";
img.style = "display: block;";
setTimeout(() => {
img.src = img.src;
}, 0);
This is inspired by this answer.
Not sure if this is the best way to respond to everyone and have it appear after all the previous answers and comments, but it seems to work.
I don't have much control over the gif. People post whatever gif they want as the "thankyou.gif in their account directory and then the ThankYou code runs whatever they've put there when a comment is submitted to a form they've posted. So some may loop, some may not, some may be short, some may be long. The solution I've come to is to tell people to make them 5 seconds, because that's when I'm going to fade them out, and I don't care if they loop or not.
Thanks for all the ideas.
I know I am pretty late here but..here it is...
I don't know if you would go to this length but let me share a trick.
Open the GIF in Macromedia Flash 8(it has deprecated since then), Export the GIF as Animated GIF. You will have to choose the file location. After that you would receive a dialog box with settings. In that, add the number of times you want the animation to happen. Click OK. Problem solved.

Unexpected CORS issue for normal images in Chrome and iOS Safari

I'm facing a CORS issue that is driving me insane. Allow me to share an example URL:
http://www.jungledragon.com/image/19905/mature_female_eastern_forktail.html/zoom
As the issue can only be reproduced once per page, here is a list of other images:
http://www.jungledragon.com/all/recent
From that overview, you can open any photo page. Next, from that photo page click the image once more to launch it fullscreen, as that is where the issue lies.
Now allow me to explain the setup, and the problem. The site itself is hosted on a Linux server within my control. The site is at www.jungledragon.com. The images, however, are stored at Amazon S3, where the image bucket has an alias of media.jungledragon.com.
The basic situation is simple:
<div id="slideshow-image-container">
<div class="slideshow-image-wrapper">
<img src="http://media.jungledragon.com/images/1755/19907_large.jpg?AWSAccessKeyId=05GMT0V3GWVNE7GGM1R2&Expires=1409788810&Signature=QH26XDrVuhyr1Qimd7IOBsnui5s%3D" id="19907" class="img-slideshow img-sec wide" data-constrained="true" data-maxheight="2056" crossorigin="anonymous">
</div>
</div>
As you can see, I'm just using the normal 'html' way of loading an image. The image URL is signed and can time out, but that shouldn't be relevant. It is my understanding that CORS does not apply to this situation, since loading images from an external domain this way has been supported for decades. The image is not loaded using javascript, after all.
Just to be sure though, the crossorigin attribute is set in HTML. Furthermore, as a way of testing, I have set a very liberal CORS policy on the image bucket:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
<AllowedHeader>origin</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Now, the situation gets a bit more complicated. The fullscreen image viewer is supposed to get a background color that is the dominant/average color of the actual image on screen. That color is calculated using canvas, yet it is only calculated once. The first time it is calculated for that image, the result is communicated to the back-end using an ajax call and then stored forever. Subsequent visits to the image will not run the calculation logic again, it will simply set the background color of the body element and all is good.
Here is the logic that does the calculation:
<script>
$( document ).ready(function() {
<?php if (!$bigimage['dominantcolor']) { ?>
$('#<?= $bigimage['image_id'] ?>').load(function(){
var rgb = getAverageRGB(document.getElementById('<?= $bigimage['image_id'] ?>'));
document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
if (rgb!==false) {
$.get(basepath + "image/<?= $bigimage['image_id'] ?>/setcolor/" + rgb.r + "-" + rgb.g + "-" + rgb.b);
}
});
<?php } ?>
});
Yes, I'm mixing in back-end code with front-end code. The above code says that if we do not yet know the dominant color in the scene, calculate it. The load function is used because at document ready, the actual image from the normal html may not have been loaded completely. Next, if the dominant color is not known yet, and the image is loaded, we trigger the function that calculates the dominant color. Here it is:
function getAverageRGB(imgEl) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
imgEl.crossOrigin = "anonymous";
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */
return false;
}
length = data.data.length;
while ( (i += blockSize * 4) < length ) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}
The following line is CORS-relevant:
data = context.getImageData(0, 0, width, height);
Although I believe I have set up CORS correctly, I can live with this code failing in some browsers. It seems to work fine in Firefox and IE11, for example. If it fails, I would expect it to fail calculating the dominant color. However, something far worse is happening in highly specific cases: the image is not shown alltogether.
My thinking is that my 'classic' loading of the image via img src tags should have nothing to do with this script working or failing, in all cases at least the image should just load, irrespective of the canvas trick.
Here are the situations I discovered where the image does not load alltogether, which I consider a major issue:
On iOS7 on iPhone 5, the first load works fine. The calculation may fail but the image loads. Refreshing the page often breaks the image. 3rd and 4th tries then continue to succeed, and so on.
Worse, at work in Chrome 36 the image does not load alltogether. I say at work, since at home it is not an issue. Possibly a proxy makes the difference. I can refresh all I want, for images that do not have the calculation ran yet, it keeps failing.
The natural thing to do then is to debug it using Chrome's inspector. Guess what? With the inspector open, it always succeeds. The image will always load and the CORS request headers and responses look perfectly fine. This leaves me with virtually no way to debug this. I can tell though that when opening the inspector when the image does not load does give me the "CORS error" in the console, from the previous request I made. Refreshing with the inspector open will then make that go away.
From reading other questions I've learned that cache may be an influence, yet more likely the issue lies in the origin header not sent by the browser. I believe the issue may be in that direction, yet I fail to understand this:
How it influences my "normal" loading of the image using img tags
How it is only an issue behind a proxy (supposedly) in Chrome, and only when the inspector windows is closed
How it works so unreliably and inconsistently in Safari on iOS
As said, I can live with only some browsers succeeding with the canvas part, but I can't live with the image not being normally loaded in any case. That part should just work.
I realize the situation is incredibly hard for you to debug, but I hope my explanation triggers some much-needed help.
Update: I've discovered that when I remove crossorigin="anonymous" from the img tag, the image will load correctly in the specific scenarios I mentioned. However, the consequence of that move is that the color calculation will no longer work in Chrome, not at home and not at work. It continues to work in Firefox though. I'm investigating what to do next.
I managed to solve the issue myself. I still cannot fully explain cause and effect here, but this is what I did:
I removed crossorigin="anonymous" from the html's img element. This will at least make sure that the image is always loaded.
The color calculation part I solved by basically rewriting its logic:
var imgSrc = $('#<?= $bigimage['image_id'] ?>').attr('src');
var cacheBurstPrefix = imgSrc.indexOf("?") > -1 ? '&' : '?';
imgSrc += cacheBurstPrefix + 'ts=' + new Date().getTime();
var imagePreloader = new Image();
imagePreloader.crossOrigin = "Anonymous";
imagePreloader.src = imgSrc;
$(imagePreloader).imagesLoaded(function() {
var rgb = getAverageRGB(imagePreloader);
document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
if (rgb!==false) {
$.get(basepath + "image/<?= $bigimage['image_id'] ?>/setcolor/" + rgb.r + "-" + rgb.g + "-" + rgb.b);
}
});
Instead of reusing the img element from the html, I'm creating a new in-memory image element. Using a cache bursting technique I'm making sure it is freshly loaded. Next, I'm using imagesLoaded (a 3rd party plugin) to detect the event of this in-memory image being loaded, which is far more reliable than jQuery's load() event.
I've tested extensively and can confirm that in no case does normal image loading ever break again. It works in every browser and proxy situation. As an added bonus, the color calculation part now seems to work in far more browsers, including several mobile browsers.
Although I am still not confident on the root cause, after much frustration I'm very happy with the new situation.

Stop img tags from flickering when re-rendering with JavaScript

Our web app is built entirely in JS.
To make it snappy we cache resources (models) between page views and reload the resource when you view a page.
Our flow is like this:
The user is in ViewA
The user switches to ViewB
We use the cached resource to render ViewB
We start a fetch for resource
When the resource is fetched we render again
This has a nasty drawback of causing <img> tags to flicker, ever if they are the same.
The problem is that Backbone.js, which we use, doesn't tell us if anything changed when fetching a collection, just that it was fetched.
Here's a quick demo of what I mean: http://jsfiddle.net/p7DdG/
It only happens in webkit and with <img> tags, not with background images as you can see.
We think it's kinda ugly to use background-image instead of a proper img tag.
Is there any solution to this?
The problem is gone in Chrome 19, problem solved :)
Not knowing exactly how the URL of each image is being built I'm not certain this will work, but could you check the src attribute of each image tag against the one you are replacing it with before doing the replace?
e.g.
var newImageSrc = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
if (newImageSrc != $("img").attr("src")) {
$('img').replaceWith('<img src="'+newImageSrc +'">');
}
Alternatively - load the image offscreen, and attach an event handler to the onload event of the image, which moves the image to the current image's parent tag, and remove the old one.
e.g.
var oldImage = $("#oldImageId");
var newImageSrc = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
var newImage = new Image();
$(newImage).load(function (event) {
$(oldImage).parent().append(newImage);
$(oldImage).detach();
});
$(newImage).attr("src", newImageSrc);
I ran into the same problem and noticed that sometimes images do flicker and sometimes don't. Even in latest Chrome (v33 as of now).
For posterity, flickering happens with uncached images.
In my case, Cache-Control: public, max-age=31536000 totally eliminated it.