large Images Canvas with FF - html

i have a Pronlem with large Image Files to display it in a Canvas with FileReader. With small Images it works fine, in Chrome with large images too. But in Firefox it displays nothing and after toDataUrl its gives a black Image. The Image size is 5580 * 8333 (8mb).
If i load the dataUrl from FileReader in a Image Tag it works too.
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
console.log(reader.result);
var canvas = document.getElementById("resize");
var ctx = canvas.getContext("2d");
var image = new Image();
image.src = reader.result;
image.onload = function() {
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var tempW = image.width;
var tempH = image.height;
if (tempW > tempH) {
if (tempW > MAX_WIDTH) {
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
} else {
if (tempH > MAX_HEIGHT) {
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
image.width=tempW;
image.height=tempH;
canvas.width = tempW;
canvas.height = tempH;
ctx.drawImage(image, 0, 0, tempW, tempH);
};
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
Thanks for help

Related

Pixel Manipulation does not work on some images

I am trying to extract only white text from the image using pixel manipulation but it does not work on some images.
It works on https://prnt.sc/24q29qu but not on https://prnt.sc/24pymne
Please see the code used and you may just paste the code in the console to see the output. Tested it on chrome browser. You may click on the output in the console to see the image output.
var imageSource = document.querySelector("body > div.image-constrain.js-image-wrap > div > div > img")
var width = 2*imageSource.width;
var height = 2*imageSource.height;
var img = new Image();
img.crossOrigin = 'anonymous';
img.src = imageSource.src;
var c = document.createElement("canvas")
c.width = width;
c.height = height;
var ctx = c.getContext("2d");
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0, 0, width, height);
var data = imageData.data;
console.log(data);
// Replacing All the pixels except white
for (let i = 0; i < data.length; i += 4) {
if(data[i] != 255) {
data[i] = 0;
}
if(data[i+1] != 255) {
data[i+1] = 0;
}
if(data[i+2] != 255) {
data[i+2] = 0;
}
if(data[i+3] != 255) {
data[i+3] = 0;
}
}
console.log(imageData.data);
ctx.putImageData(imageData, 0, 0);
img.src = c.toDataURL();
pixelatedImage = c.toDataURL();
console.log(pixelatedImage);
Your code is not targeting white pixels, it is targeting each Red Green Blue and Alpha channels that are not 255 and set these channels to 0.
This means that if you have a red #FF0000 pixel, it will stay unchanged (Red is #FF (255) and thus won't be targeted, G & B are already 0, and Alpha is 255 too, so untargeted.
In your image, the Green channel of the green part is 255, so it's untargeted. However its Red channel is neither 0 nor 255, and you can see that the green color actually does change.
(async() => {
const resp = await fetch("https://i.ibb.co/ZKnmnT6/image.png");
if (!resp.ok) {
throw resp.status;
}
const blob = await resp.blob();
const image = await createImageBitmap(blob);
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
document.body.append(canvas);
const [r,g,b,a] = ctx.getImageData(0, 0, 1, 1).data;
console.log({r,g,b,a});
})().catch(console.error);
To target white pixels, you need to check that the four RGBA channels are all 255, not one at a time.
(async() => {
const resp = await fetch("https://i.ibb.co/ZKnmnT6/image.png");
if (!resp.ok) {
throw resp.status;
}
const blob = await resp.blob();
const image = await createImageBitmap(blob);
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
document.body.append(canvas);
const img = ctx.getImageData(0, 0, image.width, image.height);
const imgdata = img.data;
for (let i = 0; i<imgdata.length; i+=4) {
if (
imgdata[i ] !== 255 ||
imgdata[i+1] !== 255 ||
imgdata[i+2] !== 255 ||
imgdata[i+3] !== 255
) {
imgdata[i ] =
imgdata[i+1] =
imgdata[i+2] =
imgdata[i+3] = 0;
}
}
ctx.putImageData(img, 0, 0);
})().catch(console.error);
But you can do this in a more performant way by using an Uint32Array view over the ImageData's .data to treat each full pixel as a single entry, a white pixel would be 0xFFFFFFFF (beware though if you want to target an other color, the order is now 0xAAGGBBRR).
(async() => {
const resp = await fetch("https://i.ibb.co/ZKnmnT6/image.png");
if (!resp.ok) {
throw resp.status;
}
const blob = await resp.blob();
const image = await createImageBitmap(blob);
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
document.body.append(canvas);
const img = ctx.getImageData(0, 0, image.width, image.height);
const imgdata = new Uint32Array(img.data.buffer);
for (let i = 0; i<imgdata.length; i++) {
if (imgdata[i] !== 0xFFFFFFFF) {
imgdata[i] = 0x00000000;
}
}
ctx.putImageData(img, 0, 0);
})().catch(console.error);

Make an AnalyserNode react to an HTMLAudioElement

I'm trying to get a spectroscope (sine wave) to show while an audio file is playing. The audio file plays fine but the graph only shows a flat line:
function play() {
var audio = document.querySelector('audio');
audio.load();
audio.play();
var context = new (window.AudioContext || window.webkitAudioContext)();
var source = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85;
source.connect(context.destination);
var canvas = document.querySelector('canvas');
var canvasCtx = canvas.getContext('2d');
var drawVisual;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
analyser.fftSize = 2048;
var bufferLength = analyser.fftSize;
var dataArray = new Uint8Array(bufferLength);
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
var draw = function() {
drawVisual = requestAnimationFrame(draw);
analyser.getByteTimeDomainData(dataArray);
canvasCtx.fillStyle = 'rgb(255, 255, 255)';
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = 'rgb(255, 0, 255)';
canvasCtx.beginPath();
var sliceWidth = WIDTH / bufferLength;
var x = 0;
for(var i = 0; i < bufferLength; i++) {
var v = dataArray[i] / 128.0;
var y = v * HEIGHT / 2;
if(i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
canvasCtx.lineTo(canvas.width, canvas.height / 2);
canvasCtx.stroke();
};
draw();
}
<audio loop src="data:audio/ogg;base64,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UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSqmklFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimVUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFIKAJCKcACQejChDBQashIASAUAAIxRSinGnIMQMeYYY9BJKClizDnGHJSSUuUchBBSaS23yjkIIaTUUm2Zc1JaizHmGDPnpKQUW805h1JSi7HmmmvupLRWa64151paqzXXnHPNubQWa64515xzyzHXnHPOOecYc84555xzzgUA4DQ4AIAe2LA6wknRWGChISsBgFQAAAIZpRhzzjnoEFKMOecchBAihRhzzjkIIVSMOeccdBBCqBhzzDkIIYSQOecchBBCCCFzDjroIIQQQgcdhBBCCKGUzkEIIYQQSighhBBCCCGEEDoIIYQQQgghhBBCCCGEUkoIIYQQQgmhlFAAAGCBAwBAgA2rI5wUjQUWGrISAAACAIAclqBSzoRBjkGPDUHKUTMNQkw50ZliTmozFVOQORCddBIZakHZXjILAACAIAAgwAQQGCAo+EIIiDEAAEGIzBAJhVWwwKAMGhzmAcADRIREAJCYoEi7uIAuA1zQxV0HQghCEIJYHEABCTg44YYn3vCEG5ygU1TqIAAAAAAADADgAQDgoAAiIpqrsLjAyNDY4OjwCAAAAAAAFgD4AAA4PoCIiOYqLC4wMjQ2ODo8AgAAAAAAAAAAgICAAAAAAABAAAAAgIBPZ2dTAAQiVgAAAAAAAGJlAAACAAAAPuePCyUVNCgpJykqMhMUFBQfHwEBAQEBAQEBAQEBAQEdEzctLSorKy05DN3v80/tzuTbDAAIjkoywUfOEcIE+hpP+uN/gfj5tZru2igfgIQDAAAAAAAAQAEAoAc3r//fwfNvv/rq+Zf287YCJEmyCLVtAF4r78vbHxDkgw/cXzRKwAMAfv4QAL4OAAAAAAAAAAAAAJ7KAACUfwBeK+/L2x8Q5IMP3F80SoEHAPz8oQC8agAAAAAAAAAAAAB+NgsAUPcKAF4r78vbH1DkAyvuzxplAiQcAAAAAAAAAGoAVgAA8L/mpgAA8WWjAF4r7+PbPwDi/PbA/a1EKfAAgH9/EYCtAAAAAAAAAAAAAFCvUQAAPBgAXivvy9sfIPLBF+7PGiXgJACAbwAAAAAAAAAAAACAmmMAFHhiAACgMpUAFhtv8kvCS8N+Pj8wNzFQwkPX148e1XWNnjoAHQAAAAAAAAAIn45Uqd4jhK0agAfgDgFM7+99+cuBAAAA4BkbeKnpdxEAVO/v4xZaAwAAAJwRcO718GsOSABM7+99+VsDAAAA+lPC93HqWwI0AETv7/NrWgMAAAD6DwF3X5ddAkgAbGHK5YvHI8F64jVDQ8WPV23Gj1dtTo+/76dH77FDAaRMdby4jQQ2sj3eJY6lXhSNpV6sjN1drMzdlStuhwAKDg4OBgAAAAAAAAAALNkvru5u3yUwvf56EPWqzemN99h41eb0xntsPANM6+/jO5Ly/rGyAQAAQJOIESgAOhuP9CXJluV/OJCf5ewtPDjPT58+PSfsawCADigAAAAAAADak7cmS87/Oz6JMcYYc4wKUXsAAF4rj+vbH6DbB3457i+aCE4CAPgGAAoAAAAAAAAAAKDmGAD0eGIAAACqC4MBAF4rj+vbH6DbB3457i+aCE4CALgGgAIAAAAAAAAAAPCzAgBnfDUAAADV1+EBAF4rj8v7f93N+f2X4/46oznBAwD+9h0A/C0AAAAAAAAAAAAAdwEAAFj1AF4r9/uHP4CwD3y63Z81mgtOAgB4AAAAAAAAAAAAAAAYTQBwemwKAACMxwNeK4/r2x+A2wd+Oe4vGs0DJwEA/A4AAAAAAAAAAAAAlJ0AgNMwIwAAMK46XiuP41vCSzfnt98dz28lugA8AODfHw4Afk4AAAAAAAAAoAjVA1ToBgAAWP4BPro26EcSKvkNW8cpZ2/hoTcGkM/TAQAjoVAAFAoAAOHdL++QeFPqn83NVQAoN6EBEgCPADSACYAC"></audio>
<br>
<canvas width="640" height="100"></canvas>
<br>
<button onclick="play()">Play</button>
Note the audio source is hardcoded here to avoid CORS issues; normally audio.source would be set on line 3 immediately after the audio var is initialized, e.g.
var audio = document.querySelector('audio');
audio.src = 'https://www.example.com/foo.mp3';
The AnalyserNode is not connected yet. It needs to get the signal as an input which you want to analyze.
You can achieve that by changing the following line ...
source.connect(context.destination);
... into ...
source.connect(analyser).connect(context.destination);

Canvas.toDataURL() not showing background image of canvas

I have added background image to canvas using css.
But when converting it into png using canvas.toDataURL() , its not showing background image.
It seems like its not parsing css background image.
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
d3.select('canvas')
.attr('style', 'background-image:url("chart.png");background-position:50%;background-repeat:no-repeat');
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
//var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var svg = new Blob([svgString], {type: "image/svg+xml"});
var url = DOMURL.createObjectURL(svg);
var png = '';
img.onload = function() {
ctx.drawImage(img, 0, 0);
png = canvas.toDataURL("image/png");
document.querySelector('#chart').innerHTML = '<img src="'+png+'"/>';
DOMURL.revokeObjectURL(png);
img.src = "";
};
img.crossOrigin = "anonymous";
img.src = url;
As said in comments, background-image is not part of the canvas context and thus, can't be exported by any canvas' export methods.
If you want to get this image drawn on the canvas, simply draw it before you draw the other image.* The main difficulty being to reproduce the different option CSS background has. But in your case, it's quite simple.
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var svg = new Blob([svgString], {
type: "image/svg+xml"
});
var url = DOMURL.createObjectURL(svg);
var png = '';
var toLoad = 2;
var loaded = 0;
var background = new Image();
var svgImg = new Image();
// attach the event to both images
background.onload = svgImg.onload = function(){
// only when both has loaded
if(++loaded === toLoad){
// set the canvas size to the svg image's one
canvas.width = svgImg.width;
canvas.height = svgImg.height;
// draw the background image first
ctx.drawImage(background, (canvas.width/2)-(background.width/2), (canvas.height/2)-(background.height/2));
// then the svg image
ctx.drawImage(svgImg, 0, 0);
png = canvas.toDataURL("image/png");
document.querySelector('#chart').innerHTML = '<img src="' + png + '"/>';
// you want to revoke the svgImg ObjectURL, not the canvas dataURI
DOMURL.revokeObjectURL(svgImg.src);
}
}
svgImg.src = url;
// set it only if you're doing a cross origin request
// Object URL are not
background.crossOrigin = 'anonymous';
background.src = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png'
svg{border: 1px solid red;}
canvas{border: 1px solid blue;}
img{border: 1px solid green;}
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="55" height="55" fill-opacity=".5"/>
</svg>
<canvas id="canvas"></canvas>
<p id="chart"></p>
*As said by markE, if you can't draw the background before, you can also set the globalCompositeOperation of your context to destination-over in order to draw behind the actual content.
Now, this wasn't clearly part of your question, but if you tried to set the background-image to your svg node, you should have been able to draw it on your canvas image, as part of the svg.
But since HTMLImage (<img>) element can't load any external resources form its loaded media, you would have to first convert the image to a dataURI version, and append the styles either as the svg's style attribute, either in a <style> element appended inside the svg element.
Here is a ugly example that will convert an svg element with a CSS defined background-image, and draw it on the canvas.
Don't use it, this just here for the demo but is likely to break. Also, this has only been quickly tested against FF, Chrome and Safari.
function convertSVGWithBG(svg, callback) {
// this function is not be bullet proof, better if you know the urls in advance
// in case of multi-images
var imgsToLoad = getComputedStyle(svg).backgroundImage.split(',');
appendDocumentStylesTo(svg);
var toLoad = imgsToLoad.length,
loaded = 0,
// we need to keep it sorted
rules = [],
canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
imgsToLoad.forEach(function(s, i) {
var bgURL = parseURL(s),
bgImg = new Image();
bgImg.crossOrigin = 'anonymous';
var errored = false;
bgImg.onload = function() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage(this, 0, 0);
rules[i] = canvas.toDataURL();
if (++loaded === toLoad) {
onend();
}
bgImg.onerror = function() {
if (!errored) {
errored = true;
this.crossOrigin = null;
this.removeAttribute('crossorigin');
this.src = this.src;
} else {
console.warn('failed to load img at src ', this.src);
if (--toLoad === loaded) {
onend();
}
}
};
};
bgImg.src = bgURL;
function onend() {
var toLoad = rules.filter(function(r) {
return r;
}).length,
loaded = 0;
// wait for the dataURI version has loaded too
rules.forEach(function(url) {
var img = new Image();
img.onload = function() {
if (++loaded === toLoad) {
callback(svg);
}
};
img.src = url
});
// it has to be inline style, or appended in a <style> element directly in our svg element
var fullRule = 'url(' + rules.join('), url(') + ')';
svg.style.backgroundImage = fullRule;
}
});
function parseURL(str) {
// this is ugly and there should be a better way to do so (maybe regex)
var url = str.split('"')[1];
if (!url) {
url = str.split("'")[1];
}
if (!url) {
url = str.split('(')[1].split(')')[0];
}
return url;
}
}
function svgToCanvas(svg) {
var svgString = new XMLSerializer().serializeToString(svg);
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var svg = new Blob([svgString], {
type: "image/svg+xml"
});
var url = DOMURL.createObjectURL(svg);
var svgImg = new Image();
svgImg.onload = function() {
canvas.width = svgImg.width;
canvas.height = svgImg.height;
ctx.drawImage(svgImg, 0, 0);
png = canvas.toDataURL("image/png");
document.querySelector('#chart').innerHTML = '<img src="' + png + '"/>';
DOMURL.revokeObjectURL(svgImg.src);
}
svgImg.src = url;
}
var svg = document.querySelector('svg');
convertSVGWithBG(svg, svgToCanvas);
// this is completely unstable and should never be used...
function appendDocumentStylesTo(element) {
var docStyleSheets = document.styleSheets;
var i = 0,
j, rules, r, key;
for (i; i < docStyleSheets.length; i++) {
rules = docStyleSheets[i].cssRules;
for (j = 0; j < rules.length; j++) {
r = rules[j];
if (element.matches(r.selectorText)) {
if (r.style) {
for (k = 0; k < r.style.length; k++) {
key = r.style[k];
// ugly hack for Safari
if (key.indexOf('repeat') > -1) {
key = 'background-repeat';
}
element.style[key] = r.style[key];
}
}
}
}
}
}
canvas {
border: 1px solid blue;
}
img {
border: 1px solid green;
}
svg {
background-image: url(https://dl.dropboxusercontent.com/s/rumlhyme6s5f8pt/ABC.png), url(https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png);
background-position: 50%;
background-repeat: no-repeat;
}
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="55" height="55" fill-opacity=".5" />
</svg>
<canvas id="canvas"></canvas>
<p id="chart"></p>
This solution is working
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
//var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var svg = new Blob([svgString], {type: "image/svg+xml"});
var url = DOMURL.createObjectURL(svg);
var png = '';
var emailConfirmationMessage = '';
var img1 = new Image();
img.onload = function() {
ctx.drawImage(img1, 136, 136);
ctx.drawImage(img, 0, 0);
sendEmail(canvas,DOMURL);
};
img1.onload = function(){
img.src = url;
};
img1.src = 'chart1.png';

Multiple images in html5 canvas not stacking in the right sequence

I'm adding multiple png transparent images to an html5 canvas one above the other but they don't stack in the right sequence (defined by the array containing the url of these images)
I read in other discussions that it may be a closure problem but no solution as far.
This is my code:
function drawCanvas() {
var canvas;
var context;
var imgArray = [
'images/img1.png',
'images/img2.png',
'images/img3.png',
'images/img4.png',
'images/img5.png',
'images/img6.png'
];
canvas = document.getElementById('myCanvas');
context = canvas.getContext("2d");
for (var i = 0; i < imgArray.length; i++) {
var img = new Image();
img.src = imgArray[i];
var drawTee = function(i, context, canvas) {
return function() {
console.log(i, 'loaded')
context.drawImage(this, 0, 0);
}
};
img.onload = drawTee(i, context, canvas);
}
};
Can anyone help me?
The problem is that the order of images on the canvas is determined by the order in which the images finish loading.
Solution: Wait for all the images to finish loading and then add them to the canvas
function drawCanvas() {
var canvas;
var context;
var imgArray = [
'images/img1.png',
'images/img2.png',
'images/img3.png',
'images/img4.png',
'images/img5.png',
'images/img6.png'
];
var images = [];
canvas = document.getElementById('myCanvas');
context = canvas.getContext("2d");
var loadCount = 0;
for (var i = 0; i < imgArray.length; i++) {
var img = new Image();
img.src = imgArray[i];
images.push(img);
img.onload = function() {
if(++loadCount == imgArray.length) {
for(var i=0; i < imgArray.length; i++) {
context.drawImage(images[i], 0, 0);
}
}
};
}
};

HTML5 Canvas background image

I'm trying to place a background image on the back of this canvas script I found. I know it's something to do with the context.fillstyle but not sure how to go about it. I'd like that line to read something like this:
context.fillStyle = "url('http://www.samskirrow.com/background.png')";
Here is my current code:
var waveform = (function() {
var req = new XMLHttpRequest();
req.open("GET", "js/jquery-1.6.4.min.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/soundmanager2.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/soundcloudplayer.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/raf.js", false);
req.send();
eval(req.responseText);
// soundcloud player setup
soundManager.usePolicyFile = true;
soundManager.url = 'http://www.samskirrow.com/client-kyra/js/';
soundManager.flashVersion = 9;
soundManager.useFlashBlock = false;
soundManager.debugFlash = false;
soundManager.debugMode = false;
soundManager.useHighPerformance = true;
soundManager.wmode = 'transparent';
soundManager.useFastPolling = true;
soundManager.usePeakData = true;
soundManager.useWaveformData = true;
soundManager.useEqData = true;
var clientID = "345ae40b30261fe4d9e6719f6e838dac";
var playlistUrl = "https://soundcloud.com/kyraofficial/sets/kyra-ft-cashtastic-good-love";
var waveLeft = [];
var waveRight = [];
// canvas animation setup
var canvas;
var context;
function init(c) {
canvas = document.getElementById(c);
context = canvas.getContext("2d");
soundManager.onready(function() {
initSound(clientID, playlistUrl);
});
aniloop();
}
function aniloop() {
requestAnimFrame(aniloop);
drawWave();
}
function drawWave() {
var step = 10;
var scale = 60;
// clear
context.fillStyle = "#ff19a7";
context.fillRect(0, 0, canvas.width, canvas.height);
// left wave
context.beginPath();
for ( var i = 0; i < 256; i++) {
var l = (i/(256-step)) * 1000;
var t = (scale + waveLeft[i] * -scale);
if (i == 0) {
context.moveTo(l,t);
} else {
context.lineTo(l,t); //change '128' to vary height of wave, change '256' to move wave up or down.
}
}
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(4 * i, 255 + waveRight[i] * 128.);
}
context.lineWidth = 0.5;
context.strokeStyle = "#000";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
Revised code - currently just showing black as the background, not an image:
// canvas animation setup
var backgroundImage = new Image();
backgroundImage.src = 'http://www.samskirrow.com/images/main-bg.jpg';
var canvas;
var context;
function init(c) {
canvas = document.getElementById(c);
context = canvas.getContext("2d");
soundManager.onready(function() {
initSound(clientID, playlistUrl);
});
aniloop();
}
function aniloop() {
requestAnimFrame(aniloop);
drawWave();
}
function drawWave() {
var step = 10;
var scale = 60;
// clear
context.drawImage(backgroundImage, 0, 0);
context.fillRect(0, 0, canvas.width, canvas.height);
// left wave
context.beginPath();
for ( var i = 0; i < 256; i++) {
var l = (i/(256-step)) * 1000;
var t = (scale + waveLeft[i] * -scale);
if (i == 0) {
context.moveTo(l,t);
} else {
context.lineTo(l,t); //change '128' to vary height of wave, change '256' to move wave up or down.
}
}
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(4 * i, 255 + waveRight[i] * 128.);
}
context.lineWidth = 0.5;
context.strokeStyle = "#ff19a7";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
Theres a few ways you can do this. You can either add a background to the canvas you are currently working on, which if the canvas isn't going to be redrawn every loop is fine. Otherwise you can make a second canvas underneath your main canvas and draw the background to it. The final way is to just use a standard <img> element placed under the canvas. To draw a background onto the canvas element you can do something like the following:
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 903;
canvas.height = 657;
var background = new Image();
background.src = "http://www.samskirrow.com/background.png";
// Make sure the image is loaded first otherwise nothing will draw.
background.onload = function(){
ctx.drawImage(background,0,0);
}
// Draw whatever else over top of it on the canvas.
Why don't you style it out:
<canvas id="canvas" width="800" height="600" style="background: url('./images/image.jpg')">
Your browser does not support the canvas element.
</canvas>
Make sure that in case your image is not in the dom, and you get it from local directory or server, you should wait for the image to load and just after that to draw it on the canvas.
something like that:
function drawBgImg() {
let bgImg = new Image();
bgImg.src = '/images/1.jpg';
bgImg.onload = () => {
gCtx.drawImage(bgImg, 0, 0, gElCanvas.width, gElCanvas.height);
}
}
Canvas does not using .png file as background image. changing to other file extensions like gif or jpg works fine.