I have a canvas that does a transition with many images applying a alpha for the fade. The problem is that for each frame apply the blur and that do very slow the animation.
If before apply the transition, do a copy of canva and apply the blur, and after use this canvas for draw in the other canvas, the animation fade no work.
The code is the next:
function animateFade()
if (fadePct > 100) {
return;
}
requestAnimationFrame(animateFade);
draw(imgs[fadeInIndex], fadePct / 100);
draw(imgs[fadeOutIndex], (1 - fadePct / 100));
fadePct++;
}
function draw(image, opacity) {
ctx.save();
ctx.globalAlpha = opacity;
ctx.drawImage(image, 0, 0);
StackBlur.canvasRGB(canvas, 0, 0, canvas.width, canvas.height, 50);
ctx.restore();
}
imageURLs = []; // put the paths to your images here
imagesOK = 0;
imgs = [];
var items = $('.carrousel .post');
for (var i = 0; i < items.length; i++) {
image = items.eq(i).find("img").attr('src');
imageURLs.push(image);
}
for (var i = 0; i < imageURLs.length; i++) {
img = new Image();
imgs.push(img);
img.onload = function () {
imagesOK++;
if (imagesOK >= imageURLs.length) {
ctx.drawImage(imgs[0], 0, 0);
var ratio = 1;
ratio = $('#best_game').width() / img.width;
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
ctx.drawImage(imgs[0], 0, 0, canvas.width, canvas.height);
StackBlur.canvasRGB(canvas, 0, 0, canvas.width, canvas.height, 50);
}
};
img.onerror = function () {
alert("image load failed");
}
img.crossOrigin = "anonymous";
img.src = imageURLs[i];
}
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
});
Related
I have the following code that allows the user to upload an image which gets put into a canvas, but once it has been drawn I want users to be able to rotate the image with the click of a button, but I don't know how to re-access the image object to be able to rotate the canvas. The code below is what works:
onFilePicked (e) {
const files = e.target.files;
for (let file of files) {
if(file !== undefined) {
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
this.loadImage(file, image);
}
}
},
loadImage(file, image) {
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
}
})
},
resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
},
And seen below is the function I built out to rotate the image- it works in that if I replace the code inside of the resizeImage function with the code below that the image is drawn in a way that is rotated correctly, but I don't know how to access the origImg object to be able to redraw the canvas in a separate function.
rotateImage(origImg, maxWidth, maxHeight){
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.height * scale;
canvas.height= origImg.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(origImg, 0, 0, canvas.height, canvas.width);
return canvas.toDataURL("image/jpeg");
},
Running this function as-is triggers the following console error:
Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
How do I get/reuse the origImg object from the resizeImage function so I can use it in the rotateImage function?
you can try with this code:
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.drawImage(origImg,0,0); // Or at whatever offset you like
};
And apply your code insede onload function of img and finally transform img source to date URL
Try this code, based on one file picker, two buttons. The first one resize image and the second one rotete the image
function resizeImg()
{
var oPicker = document.getElementById('avatar');
var oImage = document.getElementById('imgOut');
var file = oPicker.files[0];
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
oImage.thumbnail = this.resizeImage(img, 400, 300);
oImage.src = this.resizeImage(img, 1280, 960);
}
})
}
function rotateImg()
{
var imgOut = document.getElementById('imgOut');
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let scale = 1;
canvas.width = imgOut.height * scale;
canvas.height= imgOut.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(imgOut, 0, 0, canvas.height, canvas.width);
imgOut.src = canvas.toDataURL("image/jpeg");
}
function resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
}
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Image test</h1>
<img src="" id="imgOut" />
<label for="avatar">Choose a profile picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">
<input type="button" id="resImg" onclick="resizeImg()" value="Resize" />
<input type="button" id="rotImg" onclick="rotateImg()" value="Rotate" />
</body>
</html>
As you have a part in onFilePicked() where you store something about the images:
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
and later update the same objects in loadImage() (well, an event handler in it) as
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
It could be simply extended to
image.original = img;
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
Starting from this point, the objects in your images array would have an original field, storing the original, non-resized variant of the image.
I have a function that loops through an image's pixels to determine the average "brightness" of the image as a number between 0 (black) - 255 (white).
The problem is during testing I found that while an image that's entirely black (#000000) will correctly return 0, an image that's entirely white (#FFFFFF) returns a number around 200 instead of 255. Am I missing something?
Here's my function, any help would be appreciated!
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
}
Sorry, but as the snippet below proves, the result for the image you mentioned is 255.
Maybe you want to check out what file you were using in the tests ? you're probably using a wrong file...
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.crossOrigin = 'anonymous';
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
};
getBrightness(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Solid_white.svg/768px-Solid_white.svg.png',
(b)=>console.log(b));
I just included the line img.crossOrigin = 'anonymous'; in order to avoid the cors security message.
I'm taking image input from user, then resizing and showing it on a canvas. Here is the code-
HTML-
<form class="cmxform">
<input type='file' id="Photo" />
<canvas id="canvas" width="300" height="200"></canvas>
</form>
JavaScript-
$("#Photo").change(function (e) {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.src = URL.createObjectURL(e.target.files[0]);
img.onload = function () {
ctx.drawImage(img, 0, 0, img.width, img.height, // source rectangle
0, 0, canvas.width, canvas.height); // destination rectangle
}
});
But here I'm loosing the aspect ratio. Is there any way to do it?
UPDATE-
I've got the answer from this sa question -
Here is a snippet to help you for that
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
var fill = true;
if (fill)
{
$('#fill').attr("disabled", true);
}
$("#Photo").change(function (e) {
img.src = URL.createObjectURL(e.target.files[0]);
img.onload = function () {
if (fill)
{
drowImageFill(img);
}
else
{
drowImageCenter(img);
}
}
});
$("#fill").click(function(){
//console.log("fill");
var input = document.getElementById('Photo');
if (input.files[0] !== undefined)
{
img.src = URL.createObjectURL(input.files[0]);
img.onload = function () {
drowImageFill(img);
}
}
$('#fill').attr("disabled", true);
$('#center').attr("disabled", false);
fill = true;
});
$("#center").click(function(){
//console.log("center");
var input = document.getElementById('Photo');
if (input.files[0] !== undefined)
{
img.src = URL.createObjectURL(input.files[0]);
img.onload = function () {
drowImageCenter(img);
}
}
$('#center').attr("disabled", true);
$('#fill').attr("disabled", false);
fill = false;
});
//ratio formula
//http://andrew.hedges.name/experiments/aspect_ratio/
function drowImageFill(img){
ctx.clearRect(0, 0, canvas.width, canvas.height);
//detect closet value to canvas edges
if( img.height / img.width * canvas.width > canvas.height)
{
// fill based on less image section loss if width matched
var width = canvas.width;
var height = img.height / img.width * width;
offset = (height - canvas.height) / 2;
ctx.drawImage(img, 0, -offset, width, height);
}
else
{
// fill based on less image section loss if height matched
var height = canvas.height;
var width = img.width / img.height * height;
offset = (width - canvas.width) / 2;
ctx.drawImage(img, -offset , 0, width, height);
}
}
function drowImageCenter(img)
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
if( img.height / img.width * canvas.width < canvas.height)
{
// center based on width
var width = canvas.width;
var height = img.height / img.width * width;
offset = (canvas.height - height) / 2;
ctx.drawImage(img, 0, offset, width, height);
}
else
{
// center based on height
var height = canvas.height;
var width = img.width / img.height * height;
offset = (canvas.width - width) / 2;
ctx.drawImage(img, offset , 0, width, height);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="300" height="200" style="border:2px solid #000000;"></canvas>
<form class="cmxform">
<input type='file' id="Photo" />
</form>
<button id="fill">Fill</button>
<button id="center">Center</button>
I'm loading a PNG and try to check, whether it is fully opaque, meaning alpha channel is near 100% over the whole image. Therefore, I use the canvas and 2D-Context to get the pixel data and loop through it checking the alpha value.
To my surprise i get whole areas of zeros (RGBA = [0000]) where it obviously shouldn't.
Browser in focus: chrome 50.0.2661.87
Here is my code, it is embedded in a ThreeJS environment:
var imageData = zipHandler.zip.file(src); // binary image data
var texture = new THREE.Texture();
var img = new Image();
img.addEventListener( 'load', function ( event ) {
texture.imageHasTransparency = false; // extend THREEJS Texture by a flag
if (img.src.substring(imgSrc.length-4).toLowerCase().indexOf("png") > -1
|| img.src.substring(0, 15).toLowerCase().indexOf("image/png") > -1) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// search for pixel.alpha < 250
for (var pix = 0, pixDataLen = pixData.length; pix < pixDataLen; pix += 4) {
if (pixData[pix+3] < 250) {
texture.imageHasTransparency = true;
break;
}
}
}
texture.image = img;
texture.needsUpdate = true;
this.removeEventListener('load', arguments.callee, false);
}, false );
var fileExtension = src.substr(src.lastIndexOf(".") + 1);
img.src = "data:image/"+fileExtension+";base64,"+ btoa(imageData.asBinary());
The order is correct: first define new Image(), then the onload function and then the source.
Solved. The image was larger than the canvas, so when context.drawImage() was started, only parts of the area was filled. I've set the canvas dimensions according to the image size, so now it works and we have
// ...
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width; // !!!!!
canvas.height = img.height; // !!!!
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// ...
I've created a straight forward linear HTML5 animation but I now want the image to continuously scale bigger then smaller until the end of the canvas' height.
What's the best way to do this?
Here's a JSFIDDLE
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame;
var canvas = document.getElementById('monopoly-piece');
var context = canvas.getContext('2d');
var img = document.createElement("img");
img.src = "images/tophat.png";
img.shadowBlur = 15;
img.shadowColor = "rgb(0, 0, 0)";
var xSpeed = 0; //px per ms
var ySpeed = 0.15;
function animate(nowTime, lastTime, xPos, yPos) {
// update
if ((img.style.height + yPos) > canvas.height) {
xPos = 0;
yPos = 0;
}
var timeDelta = nowTime - lastTime;
var xDelta = xSpeed * timeDelta;
var yDelta = ySpeed * timeDelta;
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// shadow
context.shadowOffsetX = 3;
context.shadowOffsetY = 7;
context.shadowBlur = 4;
context.shadowColor = 'rgba(0, 0, 0, 0.4)';
//draw img
context.drawImage(img, xPos, yPos);
if (yPos > canvas.height - img.height ) {
addMarker();
}
else {
requestAnimationFrame(
function(timestamp){
animate(timestamp, nowTime, xPos + xDelta, yPos + yDelta);
}
);
}
}
animate(0, 0, -10, 0);
Here is my current code which animates an image from the top of the canvas element to the bottom and then stops.
Thanks.
context.DrawImage has additional parameters that let you scale your image to your needs:
// var scale is the scaling factor to apply between 0.00 and 1.00
// scale=0.50 will draw the image half-sized
var scale=0.50;
// var y is the top position on the canvas where you want to drawImage your image
var y=0;
context.drawImage(
// draw img
img,
// clip a rectangular portion from img
// starting at [top,left]=[0,0]
// and with width,height == img.width,img.height
0, 0, img.width, img.height,
// draw that clipped portion of of img on the canvas
// at [top,left]=[0,y]
// with width scaled to img.width*scale
// and height scaled to img.height*scale
0, y, img.width*scale, img.height*scale
)
Here's an example you can start with and fit to your own design needs:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var scale = 1;
var scaleDirection = 1
var iw, ih;
var y = 1;
var yIncrement = ch / 200;
var img = new Image();
img.onload = start;
img.src = "https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
function start() {
iw = img.width;
ih = img.height;
requestAnimationFrame(animate);
}
function animate(time) {
if (scale > 0) {
requestAnimationFrame(animate);
}
ctx.clearRect(0, 0, cw, ch);
ctx.drawImage(img, 0, 0, iw, ih, 0, y, iw * scale / 100, ih * scale / 100);
scale += scaleDirection;
if (scale > 100) {
scale = 100;
scaleDirection *= -1;
}
y += yIncrement;
}
$("#test").click(function() {
scale = y = scaleDirection = 1;
requestAnimationFrame(animate);
});
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="test">Animate Again</button>
<br>
<canvas id="canvas" width=80 height=250></canvas>