Canvas drawImage doesn't work but fillrect does - javascript

I'm completely new to javascript but not to programming...for the life of me I cannot figure this out. I'm trying to draw an image on a canvas. I can get a rectangle to draw but not an image.
Here's my code:
<head>
<meta http-equiv = "Content-type" content = "text/html;charset=utf-8">
<meta name = "viewport" id = "viewport" content = "width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;"/>
<script type = "text/javascript">
function drawPic()
{
////////////// DOESN'T WORK ///////////////////
var canvas = document.getElementById('mainCanvas');
if (canvas.getContext)
{
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function ()
{
canvas.drawImage(img, 0, 0);
};
img.src = "pic1.jpg";
}
///////////////////////////////////////////////////////////////
///////////// WORKS //////////////////////////////////////////
if (canvas.getContext)
{
var context = canvas.getContext('2d');
context.fillStyle = "rgb(150,29,28)";
context.fillRect(2, 2, 96, 96);
}
}
</script>
</head>
<body onload = "drawPic();">
<canvas id = "mainCanvas"></canvas>
</body>

well instead of canvas.drawImage(img, 0, 0); it should be called on context - context.drawImage(img, 0, 0); . Hope it helps :)

You need to make an AJAX Call.
Add something like this to your code and the image should load:
window.onload = function() {
// make ajax call to get image data url
var request = new XMLHttpRequest();
request.open("GET", "http://www.html5canvastutorials.com/demos/assets/dataURL.txt", true);
request.onreadystatechange = function() {
// Makes sure the document is ready to parse.
if(request.readyState == 4) {
// Makes sure it's found the file.
if(request.status == 200) {
loadCanvas(request.responseText);
}
}
};
request.send(null);
};
See this tutorial for a full example: http://www.html5canvastutorials.com/advanced/html5-canvas-load-image-data-url/

Related

javascript: uncaught reference error

I am making a javascript game, using Canvas. However, I got that error(below image) and background image is not shown. I suspect below 4 files, because other files didn't make any trouble. I guess the problem is related with game_state...how can I solve the problem??
I am agonizing for 2days:( plz, help me..
error image1
error image2
index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>Lion Travel</title>
<!--GameFramework-->
<script src="/.c9/gfw/GameFramework.js"></script>
<script src="/.c9/gfw/FrameCounter.js"></script>
<script src="/.c9/gfw/InputSystem.js"></script>
<script src="/.c9/gfw/SoundManager.js"></script>
<script src="/.c9/gfw/GraphicObject.js"></script>
<script src="/.c9/gfw/SpriteAnimation.js"></script>
<script src="/.c9/gfw/ResourcePreLoader.js"></script>
<script src="/.c9/gfw/DebugSystem.js"></script>
<script src="/.c9/gfw/Timer.js"></script>
<script src="/.c9/gfw/FrameSkipper.js"></script>
<script src="/.c9/gfw/TransitionState.js"></script>
<!--GameInit-->
<script src="/.c9/gfw/gfw.js"></script>
<!--Game Logic-->
<script src="/.c9/RS_Title.js"></script>
</head>
<body>
<canvas id="GameCanvas" width="800" height="600">html5 canvas is not supported.</canvas>
</body>
</html>
gfw.js
function onGameInit() {
document.title = "Lion Travel";
GAME_FPS = 30;
debugSystem.debugMode = true;
resourcePreLoader.AddImage("/.c9/title_background.png");
soundSystem.AddSound("/.c9/background.mp3", 1);
after_loading_state = new TitleState();
setInterval(gameLoop, 1000 / GAME_FPS);
}
window.addEventListener("load", onGameInit, false);
RS_Title.js
function TitleState()
{
this.imgBackground = resourcePreLoader.GetImage("/.c9/title_background.png");
soundSystem.PlayBackgroundMusic("/.c9/background.mp3");
return this;
}
TitleState.prototype.Init = function()
{
soundSystem.PlayBackgroundMusic("/.c9/background.mp3");
};
TitleState.prototype.Render = function()
{
var theCanvas = document.getElementById("GameCanvas");
var Context = theCanvas.getContext("2d");
//drawing backgroundimage
Context.drawImage(this.imgBackground, 0, 0);
};
TitleState.prototype.Update = function()
{
};
GameFramework.js
var GAME_FPS;
var game_state = after_loading_state;
function ChangeGameState(nextGameState)
{
//checking essential function
if(nextGameState.Init == undefined)
return;
if(nextGameState.Update == undefined)
return;
if(nextGameState.Render == undefined)
return;
game_state = nextGameState;
game_state.Init();
}
function Update()
{
timerSystem.Update();
game_state.Update();
debugSystem.UseDebugMode();
}
function Render()
{
//drawing
var theCanvas = document.getElementById("GameCanvas");
var Context = theCanvas.getContext("2d");
Context.fillStyle = "#000000";
Context.fillRect(0, 0, 800, 600);
//game state
game_state.Render();
if(debugSystem.debugMode)
{
//showing fps
Context.fillStyle = "#ffffff";
Context.font = '15px Arial';
Context.textBaseline = "top";
Context.fillText("fps: "+ frameCounter.Lastfps, 10, 10);
}
}
function gameLoop()
{
Update();
Render();
frameCounter.countFrame();
}
The issue here is that you are initializing game_state with the object after_loading_state even before after_loading_state is initialized(which is initialized only after the document is loaded). Due to this game_state remains undefined.
To fix this, change var game_state = after_loading_state; in GameFramework.js to var game_state;. And add game_state = after_loading_state; as the first line in gameLoop function. This way, the initialization of variables occur in the correct order.

Remove all white space from Image with Base64 and Cors

My idea is to grab an image from an URL, send it through a cors proxy, convert that to base64, then remove the white space from the image and replace that with a transparent background. I have managed to do that:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax Image</title>
<style>
body {
background: darkslategrey;
}
.text {
color: white;
}
</style>
</head>
<body>
<!-- Original -->
<h3 class="text">Original</h3>
<img src="" id="original">
<!-- Modified -->
<h3 class="text">Modified</h3>
<canvas id="modified"></canvas>
<script src="../CommonLinkedFiles/jquery3_2_1.js"></script>
<script>
var stockSymbol = "extr";
var logoUrl = "https://storage.googleapis.com/iex/api/logos/" + stockSymbol.toUpperCase() + ".png";
// Converting URL to Base64 with the use of a proxy
var getDataUri = function (targetUrl, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + targetUrl);
xhr.responseType = 'blob';
xhr.send();
};
// Returns Base 64 of image
getDataUri(logoUrl, function (base64) {
console.log('RESULT:', base64);
//original
$("#original").attr("src", base64);
var canvas = document.getElementById("modified"),
ctx = canvas.getContext("2d"),
image = document.getElementById("original");
canvas.height = canvas.width = 128;
ctx.drawImage(image,0,0);
var imgd = ctx.getImageData(0, 0, 128, 128),
pix = imgd.data,
newColor = {r:0,g:0,b:0, a:0};
for (var i = 0, n = pix.length; i <n; i += 4) {
var r = pix[i],
g = pix[i+1],
b = pix[i+2];
if(r == 255&& g == 255 && b == 255){
// Change the white to the new color.
pix[i] = newColor.r;
pix[i+1] = newColor.g;
pix[i+2] = newColor.b;
pix[i+3] = newColor.a;
}
}
ctx.putImageData(imgd, 0, 0);
});
</script>
</body>
You can see here at: JsFiddle
My question is how do I remove all of the white space given any image.
Edit: Keith Solved the image by adding on onload function.
After some tinkering, I figured out that all of the "white" pixels were not exactly white so I so modifying the if statement it searched for all of near white pixels:if(r >= 250&& g >= 250 && b >= 250){
JSFiddle

Fading a loaded image into Canvas with drawImage

This question about crossfading images already gave an answer to the crossfading solution in Canvas. I am trying to do the same thing, only difference is that i am trying to fade images that are loaded on runtime.
The images are loaded propperly but no fade is visible. Is this not working because of the loaded images? Thanks.
HTML
<div id="wrapper">
<canvas id="bg1"></canvas>
<canvas id="bg2"></canvas>
</div>
JS
var toggle = true;
var canvas = document.getElementById('bg1');
canvas.width = $(document).width();
canvas.height = $(document).height();
var ctx = canvas.getContext('2d');
var canvas2 = document.getElementById('bg2');
canvas2.width = $(document).width();
canvas2.height = $(document).height();
var ctx2 = canvas2.getContext('2d');
var image = new Image();
image.src = 'download1.jpg';
var image2 = new Image();
image2.src = 'download2.jpg';
image.onload = function() {
ctx.drawImage(image, 0, 0, 200, 100);
ctx2.drawImage(image2, 0, 0, 200, 100);
};
$('#wrapper').click(function () {
if (toggle)
{
$('#bg2').fadeIn();
$('#bg1').fadeOut();
}
else
{
$('#bg1').fadeIn();
$('#bg2').fadeOut();
}
toggle = !toggle;
});
Yep, you need to give your images time to load.
But also, jQuery cannot do fadeIn/fadeout on a canvas element so you will have to do that manually.
Demo: http://jsfiddle.net/m1erickson/zw9S4/
Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/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(){
$("#fade").hide();
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-2.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg");
loadAllImages();
//
function loadAllImages(){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
$("#fade").show();
ctx.drawImage(imgs[0],0,0);
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var fadeOutIndex=imgs.length-1;
var fadeInIndex=0;
var fadePct=0;
function animateFade(){
if(fadePct>100){return;}
requestAnimationFrame(animateFade);
ctx.clearRect(0,0,canvas.width,canvas.height);
draw(imgs[fadeInIndex],fadePct/100);
draw(imgs[fadeOutIndex],(1-fadePct/100));
fadePct++;
}
function draw(img,opacity){
ctx.save();
ctx.globalAlpha=opacity;
ctx.drawImage(img,0,0);
ctx.restore();
}
$("#fade").click(function(){
fadePct=0;
if(++fadeOutIndex == imgs.length){fadeOutIndex=0;}
if(++fadeInIndex == imgs.length){fadeInIndex=0;}
animateFade();
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="fade">Fade to next Image</button><br>
<canvas id="canvas" width=204 height=204></canvas><br>
</body>
</html>
Try to fade in/out the images directly on the canvas instead of fading in and out the canvas elements (or there is not really any point using the canvas as you could use image elements instead).
First, of course, wait for the images to load:
var isBusy = false, /// for fade loop
count = 2; /// number of images to load
image = new Image();
image2 = new Image();
/// setup load handler
image.onload = image2.onload = handleLoad;
image.src = 'download1.jpg';
image2.src = 'download2.jpg';
function handleLoad() {
count--;
if (count === 0) {
/// when loaded draw a single image onto canvas
ctx.drawImage(image, 0, 0, ctx.canvas.width, ctx.canvas.height);
}
};
Now we can change the click handler a little bit around and use canvas only to do the fade in of the next image:
$('#wrapper').click(function () {
var img, /// current image to fade in
opacity = 0; /// current globalAlpha of canvas
/// if we're in a fade exit until done
if (isBusy) return;
isBusy = true;
/// what image to use
img = toggle ? image2 : image;
/// fade in
(function fadeIn() {
/// set alpha
ctx.globalAlpha = opacity;
/// draw image with current alpha
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
/// increase alpha to 1, then exit resetting isBusy flag
opacity += 0.02;
if (opacity < 1)
requestAnimationFrame(fadeIn);
else
isBusy = false;
})();
toggle = !toggle;
});
Online demo
Hope this helps.

HTML5 canvas photo slide show issue

Hi I found this code on Stackoverflow for a canvas photo slide show, but I'm just wondering how to make the transitions between images slower?
var loaded = 0, numOfImages = 4;
//first part of chain, invoke async load
var image0 = document.createElement('img'); //this will work in new Chrome
var image1 = document.createElement('img'); //instead of new Image
var image2 = document.createElement('img');
var image3 = document.createElement('img');
//common event handler when images has loaded with counter
//to know that all images has loaded
image0.onload = image1.onload =
image2.onload = image3.onload = function(e) {
loaded+;
if (loaded === numOfImages)
draw(); // <-- second part of chain, invoke loop
}
//show if any error occurs
image0.onerror = image1.onerror =
image2.onerror = image3.onerror = function(e) {
console.log(e);
}
//invoke async loading... you can put these four into your
//window.onload if you want to
image0.src = "img/pic1.jpg";
image1.src = "img/pic2.jpg";
image2.src = "img/pic3.jpg";
image3.src = "img/pic4.jpg";
// this is the main function
function draw() {
var images = new Array(image0, image1, image2, image3),
counter = 0,
maxNum = images.length - 1,
myCanvas = document.getElementById('myCanvas'),
ctx = myCanvas.getContext('2d'),
me = this; //this we need for setTimeout()
//third part of chain, have a function to invoke by setTimeout
this._draw = function() {
//if the next image will cover the canvas
//there is no real need to clear the canvas first.
//I'll leave it here as you ask for this specifically
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
ctx.drawImage(images[counter++], 0, 0);
if (counter > maxNum) counter = 0;
setTimeout(me._draw, 1000); //here we use me instead of this
}
this._draw(); //START the loop
}
but I'm just wondering how to make the transitions between images slower?
You have a typo in your onload methods:
loaded++; // instead of loaded+;
The setTimeout controls the delay until me._draw is called again.
For example 3 seconds of delay would be 3000 milliseconds, like this:
setTimeout(me._draw, 3000);
If you instead want an actual transition, you could use something like this:
changing images on a canvas with transitions
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/m8E6J/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var loaded = 0, numOfImages = 4;
//first part of chain, invoke async load
var image0 = document.createElement('img'); //this will work in new Chrome
var image1 = document.createElement('img'); //instead of new Image
var image2 = document.createElement('img');
var image3 = document.createElement('img');
//common event handler when images has loaded with counter
//to know that all images has loaded
image0.onload = image1.onload =
image2.onload = image3.onload = function(e) {
loaded++;
if (loaded === numOfImages)
draw(); // <-- second part of chain, invoke loop
}
//show if any error occurs
image0.onerror = image1.onerror =
image2.onerror = image3.onerror = function(e) {
console.log(e);
}
//invoke async loading... you can put these four into your
//window.onload if you want to
image0.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg";
image1.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-2.jpg";
image2.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg";
image3.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg";
// this is the main function
function draw() {
var images = new Array(image0, image1, image2, image3),
counter = 0,
maxNum = images.length - 1,
myCanvas = document.getElementById('myCanvas'),
ctx = myCanvas.getContext('2d'),
me = this; //this we need for setTimeout()
//third part of chain, have a function to invoke by setTimeout
this._draw = function() {
//if the next image will cover the canvas
//there is no real need to clear the canvas first.
//I'll leave it here as you ask for this specifically
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
ctx.drawImage(images[counter++], 0, 0);
if (counter > maxNum) counter = 0;
setTimeout(me._draw, 3000); //here we use me instead of this
}
this._draw(); //START the loop
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="myCanvas" width=600 height=400></canvas>
</body>
</html>

How can I draw an image from the HTML5 File API on Canvas?

I would like to draw an image opened with the HTML5 File API on a canvas.
In the handleFiles(e) method, I can access the File with e.target.files[0] but I can't draw that image directly using drawImage. How do I draw an image from the File API on HTML5 canvas?
Here is the code I have used:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script>
window.onload = function() {
var input = document.getElementById('input');
input.addEventListener('change', handleFiles);
}
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.drawImage(e.target.files[0], 20,20);
alert('the image is drawn');
}
</script>
</head>
<body>
<h1>Test</h1>
<input type="file" id="input"/>
<canvas width="400" height="300" id="canvas"/>
</body>
</html>
You have a File instance which is not an image.
To get an image, use new Image(). The src needs to be an URL referencing to the selected File. You can use URL.createObjectURL to get an URL referencing to a Blob (a File is also a Blob): http://jsfiddle.net/t7mv6/86/.
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image;
img.onload = function() {
ctx.drawImage(img, 20,20);
alert('the image is drawn');
}
img.src = URL.createObjectURL(e.target.files[0]);
Note: be sure to revoke the object url when you are done with it otherwise you'll leak memory. If you're not doing anything too crazy, you can just stick a URL.revokeObjectURL(img.src) in the img.onload function.
References:
https://developer.mozilla.org/en/DOM/File
http://html5demos.com/file-api
Live Example
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 20, 20);
}
img.src = url;
}
window.URL.createObjectUrldocs
You could also use the FileReader instead to create the object URL.
The FileReader has slightly better browser support.
The FileReader approach works in FF6 / Chrome. I'm not certain whether setting Img.src to a Blob is valid and cross-browser though.
Creating object urls is the correct way to do it.
Edit:
As mentioned in the commment window.URL support whilst offline seems unavailable in FF6/Chrome.
Here is a complete example (Fiddle) using FileReader (which has better browser support as mentioned by Raynos). In this example I also scale Canvas to fit the image.
In real life example you might scale the image to some maximum so that your form will not blow up ;-). Here is an example with scaling (Fiddle).
var URL = window.webkitURL || window.URL;
window.onload = function() {
var input = document.getElementById('input');
input.addEventListener('change', handleFiles, false);
// set original canvas dimensions as max
var canvas = document.getElementById('canvas');
canvas.dataMaxWidth = canvas.width;
canvas.dataMaxHeight = canvas.height;
}
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
var reader = new FileReader();
var file = e.target.files[0];
// load to image to get it's width/height
var img = new Image();
img.onload = function() {
// setup scaled dimensions
var scaled = getScaledDim(img, ctx.canvas.dataMaxWidth, ctx.canvas.dataMaxHeight);
// scale canvas to image
ctx.canvas.width = scaled.width;
ctx.canvas.height = scaled.height;
// draw image
ctx.drawImage(img, 0, 0
, ctx.canvas.width, ctx.canvas.height
);
}
// this is to setup loading the image
reader.onloadend = function () {
img.src = reader.result;
}
// this is to read the file
reader.readAsDataURL(file);
}
// returns scaled dimensions object
function getScaledDim(img, maxWidth, maxHeight) {
var scaled = {
ratio: img.width / img.height,
width: img.width,
height: img.height
}
if (scaled.width > maxWidth) {
scaled.width = maxWidth;
scaled.height = scaled.width / scaled.ratio;
}
if (scaled.height > maxHeight) {
scaled.height = maxHeight;
scaled.width = scaled.height / scaled.ratio;
}
return scaled;
}
canvas {
border:1px solid black
}
<input type="file" id="input"/>
<div>
<canvas width="400" height="300" id="canvas"/>
</div>

Categories