I'm trying to cache my favicon image just like any other image, but I'm not seeing it in the cache, nor getting my confirmation console.log, nor seeing it when I disconnect from the internet (basically it is not caching).
I want to cache it so I can access it offline, so I can dynamically change the icon if the internet disconnects.
My html:
<link id="favicon" rel="icon" type="image/png" src="assets/favicon-red-16x16.ico.png">
My js:
// cache images
function preloadImages(array) {
if (!preloadImages.list) {
preloadImages.list = [];
}
var list = preloadImages.list;
for (var i = 0; i < array.length; i++) {
console.log('caching image...')
var img = new Image();
img.onload = function() {
console.log('image cached')
var index = list.indexOf(this);
if (index !== -1) {
// remove image from the array once it's loaded
// for memory consumption reasons
list.splice(index, 1);
}
}
list.src = array[i];
}
}
preloadImages(["../assets/favicon-green-16x16.ico.png", "../assets/favicon-red-16x16.ico.png"]);
question: Is it possible to cache the favicon client side? Is there another way to store it locally?
if i convert to base64 how do I store and grab it from local storage?
ps. using Chrome latest
<___ UPDATE ___>
Though the question is technically answered, How can I do this two store 2 (more than one) base64 image? I can't figure out how to draw 2 onto a canvas or 2 canvases.
Try this code pal.
You can hide iconImage img element. The other img tag i have used, is for testing only, so you can remove it.
<!DOCTYPE html>
<html>
<link id="favicon" rel="icon" href="img_the_scream.jpg" />
<body>
<img id="iconImage" src="img_the_scream.jpg" alt="The Scream" width="220" height="277">
<br />
<img id="img" width="220" height="277"/>
<script>
function onLoadHandler() {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("iconImage");
var base64Image = localStorage.getItem("lsFavicon");
var favicon = document.getElementById("favicon");
var img2 = document.getElementById("img");
if (base64Image == null && document.navigator.onLine) {
ctx.drawImage(img, 0, 0);
base64Image = canvas.toDataURL();
localStorage.setItem("lsFavicon", base64Image);
favicon.setAttribute("href", base64Image);
}
else if (base64Image != null) {
favicon.setAttribute("href", base64Image);
img2.setAttribute("src", base64Image);
}
}
window.onload = onLoadHandler;
</script>
</body>
</html>
Related
i have a div with several images fixed in position that i want to put into a single canvas so that i can save the composite picture. is this possible?
i read through the canvas tutorial at w3schools and i checked out the API with MDN and came up with the following code that does nothing...
<div id="pics" >
<img id="i1" class="images"
src="http://chris.chrisjneeds.com/images/stars/stars01.jpg" width="300" height="277" style="position: fixed;">
<img id="i2" class="images"
src="http://chris.chrisjneeds.com/images/ships/ships26.png" width="300" height="277" style="position: fixed;">
</div>
<canvas id="myCanvas" width="250" height="300"
style="border:1px solid #d3d3d3; horizontal-align: right; float: right">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
function myCanvas() {
var aImages = document.getElementsByClassName('images'),
nImgsLen = aImages.length;
var oCanvas = document.getElementById("myCanvas");
var oCtx = oCanvas.getContext("2d");
for (var oImgData, nImgId = 0; nImgId < nImgsLen; nImgId++) {
oImgData = oCtx.getImageData(0, 0, 300, 277);
oCtx.putImageData(oImgData, 0, 0);
}
var img=new Image();
img.src = oCanvas.toDataURL();
oCtx.drawImage(img,10,10);
}
i'm expecting the composite image in the canvas but so far i don't get anything. please help
Sure, it is possible, but not that way like in your code.
getImageData/putImageData methods are intended for pixel manipulation and absolutely useless for your problem. Your code just copies an area of just created canvas into itself (i.e. does nothing). But what you actually need is draw your images one by one onto the canvas using drawImage method. Also note that you don't need to use toDataURL method (it's mostly used for images sending/saving) cause you with drawImage calls you'll already have needed composite image in the canvas.
So your code should look like this:
...
var aImages = document.getElementsByClassName('images');
var oCanvas = document.getElementById("myCanvas");
var oCtx = oCanvas.getContext("2d");
for (var img of aImages) {
oCtx.drawImage(img, 0, 0, img.width, img.height);
}
the second part of my question is "so that i can save the composite picture"
this is what i found from HOW TO SAVE AN IMAGE TO DISK FROM A CANVAS
here is the complete code (i hope it helps someone)
function getImgs4Canvas() {
var aImages=$("#cloneimages img");
var oCanvas = document.getElementById("imgCanvas");
var oCtx = oCanvas.getContext("2d");
for (var oimg of aImages) {
oCtx.drawImage(oimg, 0, 0, oimg.width, oimg.height);
}
var jpgFile = oCanvas.toDataURL('image/jpeg', 1.0);
// save the image as a jpg 'blob' in the user's download (default) directoy
ImageSaver.download_data_uri(jpgFile, "downloadimgtest");
}
var ImageSaver = {
// function to force-download from a data uri as a filename
// NB the download="filename" attribute isn't yet supported by safari
download_data_uri: function(dataURI, fileName) {
var tempUrl = ImageSaver.make_url_from_data(dataURI);
var link = $(' ');
$("body").append(link);
$("#download").get(0).click();
},
// function to generate a temporary browser index url for a datauri
// if a data-uri is larger than 2mb, chrome's address bar can't handle it.
// fortunately, you can blob it and then use a temporary blob url
make_url_from_data: function(dataURI) {
var blob = ImageSaver.make_blob(dataURI);
var tempUrl = URL.createObjectURL(blob);
return tempUrl;
},
// function to convert a datauri to a blob
// Blobs are temporary data structures that can hold binary data, and make that data accessible through a short url. They can probably do other things too; I have no idea.
make_blob: function(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
};
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], {
type: mimeString
});
}
}
Disclaimer upfront: I'm still very new to JavaScript. (And to programming in general, for that matter.)
So, I'm trying to create an interface that would display an image in multiple aspect ratios, when cropped by object-fit: cover. I'd like to see several aspect ratios side-by-side and be able to test different images as well.
I'm using JavaScript's File API to avoid uploading/downloading. It's also worth noting that I'm doing everything on Google Apps Script so it can be an easily accessible web app.
Right now, I have the <img> in a <div> so I can use replaceChild. That's the only way I've been able to get it to work. You can see it here on CodePen. This is the function I've been using:
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
var placehold = document.getElementById('userImg');
document.getElementById('userImageDiv').replaceChild(img, placeHold);
}
img.id = "userImg";
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
What I've tried:
I tried getting the img.onload function to append img twice:
var placeholdTwo = document.getElementById('imgTwo');
document.getElementById('imageTwoDiv').replaceChild(img, placeholdTwo);
But it only displayed in imgTwo - I'm guessing because the function only creates one FileReader.
I also tried reading the image in one location, then copying it's src to additional locations, but no luck there:
function repeatImg(){
var repeatImage = document.getElementById('userImg').src;
document.getElementById('imageOne').src = repeatImage;
document.getElementById('imageTwo').src = repeatImage;
}
Then, I tried making multiples of the whole handleImage function and calling them all with an event listener, but that didn't work either.
Is there any way to accomplish this?
Simply wrap the original file object, which is a blob, and set that as source. This way you avoid adding up memory usage and base64 encoding/decoding overheads as with a Data-URL - there's no need to create an intermediate image element either - just update the src on the existing ones:
document.querySelector("input").onchange = handleImage;
function handleImage() {
var url = URL.createObjectURL(this.files[0]);
document.getElementById('userImg').src =
document.getElementById('imageOne').src =
document.getElementById('imageTwo').src = url;
}
<label>Select an image: <input type=file></label>
<img id=userImg>
<img id=imageOne>
<img id=imageTwo>
Looking at the linked pen, repeatImg does not get called by the userImgDiv change event listener.
Calling repeatImg() at the end of img.onload works for me.
img.onload = function(){
var placeHold = document.getElementById('userImg');
document.getElementById('userImageDiv').replaceChild(img, placeHold);
repeatImg();
}
CodePen.
I think perhaps I'm missing something, but why not just set the image sources in your img.onload method?
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
var placehold = document.getElementById('userImg');
document.getElementById('userImageDiv').replaceChild(img, placeHold);
document.getElementById('imageOne').src = img.src;
document.getElementById('imageTwo').src = img.src;
}
img.id = "userImg";
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
You're only using one Image. I would do something like this instead:
/* external.js */
//<![CDATA[
var doc, bod, M, I, Q, S, old = onload; // for use on other loads
onload = function(){
if(old)old(); // change old var name if using technique on other pages
doc = document; bod = doc.body;
M = function(tag){
return doc.createElement(tag);
}
I = function(id){
return doc.getElementById(id);
}
Q = function(selector, withinElement){
var w = withinElement || doc;
return w.querySelectorAll(selector);
}
S = function(selector, withinElement){
var w = withinElement || doc;
return w.querySelector(selector);
}
I('form').onsubmit = function(){
return false;
}
// you can put the below code on another page onload if you want
var up = I('upload'), out = I('out'), reader = new FileReader;
up.onchange = function(){
reader.onload = function(){
var img0 = M('img'), img1 = M('img');
img0.src = img1.src = this.result; out.innerHTML = '';
out.appendChild(img0); out.appendChild(img1);
}
reader.readAsDataURL(this.files[0]);
}
}
//]]>
/* external.css */
html,body{
padding:0; margin:0;
}
body{
background:#000; overflow-y:scroll;
}
.main{
width:940px; background:#ccc; padding:20px; margin:0 auto;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<meta name='viewport' content='width=device-width' />
<title>Test Template</title>
<link type='text/css' rel='stylesheet' href='external.css' />
<script type='text/javascript' src='external.js'></script>
</head>
<body>
<div class='main'>
<form id='form' name='form'>
<input id='upload' name='upload' type='file' />
</form>
<div id='out'></div>
</div>
</body>
</html>
I'm really struggling to write a function for getting the Base64 encoding of an image. Since this function will be part of a bigger script that uses jsPDF.js to make PDFs on-the-fly from a website, It's important the be able to calculate those Base64 encodings as the result of a function. The images will be hosted on the same server, so no same-origin issues. I know the .toDataURL() method of the canvas element can do this and I also know that the image needs to be fully loaded in order to get the Data URL correctly, so I wrote this function
// Encode image to Base64
function encodeBase64(url, format)
{
var image = new Image(),
canvas = document.createElement("canvas"),
context = canvas.getContext("2d");
image.src = url;
image.onload = function ()
{
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0, image.width, image.height);
var dataURL = canvas.toDataURL(format);
alert(dataURL);
};
}
The problem is that I don't know how to "extract" the dataURL value from the onload function so that the encodeBase64 function simply returns that value and I can put it in an array. Alert returns that string correctly so I'm sure the code works, but if I try to write any other statement like "return dataURL" or similar I just get undefined value. Please help.
First load all the images into an array.
Then create the dataURLs using canvas and load the dataURLs into a second array.
Example code and a Demo: http://jsfiddle.net/m1erickson/fbdb3qbw/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// array for dataURLs
var dataURLs=[];
// put the paths to your images in imageURLs[]
var imageURLs=[];
// push all your image urls!
imageURLs.push({url:"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sun.png",format:null});
imageURLs.push({url:"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/temp1.png",format:'image/jpeg'});
// the loaded images will be placed in images[]
var imgs=[];
var imagesOK=0;
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
img.format=imageURLs[i].format;
imgs.push(img);
dataURLs.push('');
img.index=imgs.length-1;
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i].url;
}
}
function start(){
// the imgs[] array now holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
// now loop through each img and create its dataURL
for(var i=0;i<imgs.length;i++){
var img=imgs[i];
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
dataURLs[img.index] = canvas.toDataURL(img.format);
}
// Demo: report the results to the console
console.log(dataURLs);
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Fetch dataURLs from images (see results in the console)</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[ Addition: pulling urls from textarea ]
Here's how to pull the urls from the textarea.
(#loadImages is a button that's pushed when your user has typed the urls into the textbox).
I haven't looked at the jsPDF source so I can't speak to your dims issue.
$('#loadImages').click(function(){
var inputText = document.getElementsByTagName("textarea")[0].value.split("\n");
for(var i = 0; i < inputText.length; i++){
imageURLs.push({url: inputText[i],format:"image/jpeg"});
}
loadAllImages(start);
});
I've got a question in regards to javascript and dynamically displaying images to
form an animation.
The pictures I have are around 1360x768 in size and quite big despite being .png pics.
I've come up with a code for switching out the pics dynamically, but even run on a local
webserver it is too slow (thus sometimes I see the pic being built).
So my question is: is there a better way to do this than dynamically switching out
the "src" part of the image tag, or is there something else that could be done in combination with that, to make sure that the user doesn't have any strange phenomenons
on the client?
<script>
var title_index = 0;
function display_title()
{
document.getElementById('picture').src=
"pics/title_" + title_index + '.png';
if (title_index < 100) {
title_index = title_index + 5;
setTimeout(display_title,3000);
}
}
</script>
<body onload="setTimeout(display_image,3000)">
<image id="picture" src="pic/title_0.png"/>
</body>
Thanks.
I've had this problem too, even when preloading the images into the cache,
Google's The Hobbit experiment does something interesting. They do low resolution while animating and switch it for a hiresolution if you "pause" (stop scolling in the case of The Hobbit experiment). They also use the HTML5 canvas tag to smooth out the animation.
Here's their blog post about their method:
http://www.html5rocks.com/en/tutorials/casestudies/hobbit-front-end/
Their end product:
http://middle-earth.thehobbit.com
Edit:
Pre loading example:
<!Doctype html>
<head>
<title>test</title>
</head>
<body>
<canvas id="myCanvas" width="1360" height="768"></canvas>
<script type="text/javascript">
var images = {};
var loadedImages = 0;
var numImages = 0;
var context = '';
function loadImages(sources, callback)
{
// get num of sources
for(var src in sources)
{
numImages++;
}
for(var src in sources)
{
images[src] = new Image();
images[src].onload = function()
{
if(++loadedImages >= numImages)
{
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d');
var sources =
{
frame0: 'http://piggyandmoo.com/0001.png',
frame1: 'http://piggyandmoo.com/0002.png',
frame2: 'http://piggyandmoo.com/0003.png',
frame3: 'http://piggyandmoo.com/0004.png',
frame4: 'http://piggyandmoo.com/0005.png',
frame5: 'http://piggyandmoo.com/0006.png',
frame5: 'http://piggyandmoo.com/0007.png',
frame5: 'http://piggyandmoo.com/0008.png',
frame5: 'http://piggyandmoo.com/0009.png'
};
var width = 1360;
var height = 768;
var inter = '';
var i = 0;
function next_frame()
{
if(numImages > i)
{
context.drawImage(images['frame' + (i++)], 0, 0);
}
else
{
clearInterval(inter);
}
}
loadImages(sources, function(images)
{
//animate using set_timeout or some such...
inter = setInterval(function()
{
next_frame();
}, 1000);
});
</script>
</body>
Code modified from: www.html5canvastutorials.com/tutorials/html5-canvas-image-loader/
You could overcome this issue by preloading the images on page load. This means that the images would then be stored in memory and immediately available to you. Take a look at the following:
JavaScript Preloading Images
http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
I don't know if there is a work around for this IE9 issue I ran into, but here's what I'm trying to do. I have an image in a canvas on my page. I want to copy this canvas image to another canvas, but in a pop-up window I create. What I'm encountering in this experiment is I can copy the canvas image into another dynamically created canvas on the same page, no problem. But when I try to do it in a pop-up window, IE gives me a DOM Exception: TYPE_MISMATCH_ERR (17). Sadly, this seems to be an IE thing, because I ran my same code in Chrome, and it worked...
So here's my code. You'll need to provide your own image though, I used a simple 640x480 jpeg file. You'll also need the console open, since I'm doing a console.error. I also tried this code as a file and running from localhost on my local IIS.
<!DOCTYPE html>
<html>
<head>
<title>Canvas Copy Test</title>
<style>
#mainSrc {
border:1px solid red;
}
#dest01 {
width:640px;
height:480px;
border:1px solid blue;
}
</style>
<script>
var destWin; // Destination Window
window.onload=function()
{
var testImg = new Image();
testImg.src = "me.jpg";
testImg.onload = function()
{
var mainCanvas = document.getElementById("mainSrc");
var mainCtx = mainCanvas.getContext("2d");
mainCtx.drawImage(testImg,0,0);
}
var copyBtn = document.getElementById("copyBtn");
var copyWinBtn = document.getElementById("copy2WinBtn");
copyBtn.addEventListener("click",copyImage,false);
copyWinBtn.addEventListener("click",copy2Win,false);
}
// Copy Canvas Image to Another on the same page.
function copyImage()
{
var mainCanvas = document.getElementById("mainSrc");
var destCanvas = document.createElement("canvas");
var destDiv = document.getElementById("dest01");
destCanvas.width = mainCanvas.width;
destCanvas.height = mainCanvas.height;
var dCtx = destCanvas.getContext("2d");
dCtx.drawImage(mainCanvas,0,0);
destDiv.appendChild(destCanvas);
}
// Copy Canvas to Popup Window
function copy2Win()
{
var mainCanvas = document.getElementById("mainSrc");
try {
destWin = window.open("","destWin");
var destWinDoc = destWin.document;
var destWinHTML = "<!DOCTYPE html><html><head><title>POPUP</title><body><div id='destWinDiv' style='width:640px; height:480px; border:1px solid red'></div></body></html>";
destWinDoc.write(destWinHTML);
var destCanvas = destWinDoc.createElement("canvas");
var destDiv = destWinDoc.getElementById("destWinDiv");
destCanvas.width = mainCanvas.width;
destCanvas.height = mainCanvas.height;
var dCtx = destCanvas.getContext("2d");
dCtx.drawImage(mainCanvas,0,0);
destDiv.appendChild(destCanvas);
}
catch (err)
{
console.error(err);
}
}
</script>
</head>
<body>
<canvas id="mainSrc" width="640" height="480"></canvas>
<p>
<input type="button" name="Copy" value="Copy" id="copyBtn" />
<input type="button" name="Copy2Win" value="Copy To New Window" id="copy2WinBtn" />
</p>
<div id="dest01"></div>
</body>
</html>
Well, after playing around a little more, I figured out that the tag can actually take in a base64 encoded image from the canvas toDataURL() and display it... So I was able to make this modification in my above copy2Win function to be this:
function copy2Win()
{
var mainCanvas = document.getElementById("mainSrc");
destWin = window.open("","destWin");
var destWinDoc = destWin.document;
var destWinHTML = "<!DOCTYPE html><html><head><title>POPUP</title><body><div id='destWin' style='width:640px; height:480px; border:1px solid red'><img src='" + mainCanvas.toDataURL() + "' alt='Copy!' /></div></body></html>";
destWinDoc.write(destWinHTML);
}
The thing to note is I'm writing out the img tag's src to be the canvas.toDataURL(), and this works. IE doesn't complain about this. Although the data isn't into another canvas, I'm able to get what I need, which is my image data pulled from my canvas and displayed in a new window. Interestingly, if you look at the generated source code the image is actually shown as the base64 encoded data in the src, so it seems the browser is decoding the src data for display; interesting.