JS use drawImage(Image,...) in Image.onload in screenshot codes - javascript

I'm reading chrome extension codes for capturing full page screenshot and here is a piece of codes I cannot figure out the logic behind (https://github.com/erichua23/prj/blob/676e98366c6a25c56b2e342a3aecec76ae076391/screenshot/background.js#L63):
chrome.tabs.captureVisibleTab(this.tabId, { format: "png" }, function(img) {
var blockImg = new Image();
var canvas = self.canvas;
if (Capturer.yPos + Capturer.clientHeight >= Capturer.scrollHeight) {
blockImg.onload = function() {
var ctx = canvas.getContext("2d");
var y = Capturer.clientHeight - Capturer.scrollHeight % Capturer.clientHeight;
ctx.drawImage(blockImg, 0, 0, width, height, 0, self.yPos - y, width, height);
Capturer.postImg();
};
} else {
blockImg.onload = function() {
var ctx = canvas.getContext("2d");
ctx.drawImage(blockImg, 0, 0, width, height, 0, Capturer.yPos, width, height);
Capturer.yPos += Capturer.clientHeight;
self.scrollPage(self.tabId, 0, Capturer.clientHeight);
};
}
blockImg.src = img;
});
Why putting a blank image on the canvas? And how the screenshot is obtained?
Thank You for your time and expertise.

Related

How can I fix this pixelate bugs with canvas NodeJS problems?

I have developed a game in NodeJS where you have to guess an image's name meanwhile the image depixelates.
The problem is that the server uses canvas to pixelate the image but the render don't fit entirely in the frame as you can see :
The pixelate function :
function pixelate(image, ctx, canvas, value) {
var size = value / 100,
w = canvas.width * size,
h = canvas.height * size;
ctx.drawImage(image, 0, 0, w, h);
ctx.msImageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height)
}
And the loop were i pixelate the image :
function image_pixel(bool = 1) {
if (bool) {
if (pixel_state > 24) {
restartGame("", false);
} else {
loadImage('image.jpg').then((image) => {
pixel_state += 0.1;
var canvas = createCanvas(image.width, image.height);
var ctx = canvas.getContext('2d');
pixelate(image, ctx, canvas, pixel_state);
io.emit('image', canvas.toDataURL());
})
}
} else { // Image without pixelisation
loadImage('image.jpg').then((image) => {
var canvas = createCanvas(image.width, image.height);
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
io.emit('image', canvas.toDataURL());
})
}
};
I tried to round the "w" and "h", the image will fill entirely in frame but some of the images sent will be the same so it'll feel laggy for the user.
Finally found something, I resized all of my pictures to square aspect ratio and then for the "pixel_state" if it's like 100/(2^x) i won't have any ghost pixels almost anymore.

JavaScript canvas.drawImage alpha loss

Pretty new to JavaScript.
I'm building a site that compares the template image with the user's input and builds some image processing directives. The template image is stored in the site's folder.
$(function() {
$("#btnDirective").click(generateEmoteDirectiveFile);
});
function generateEmoteDirectiveFile() {
getImageData('imgs/templates/human.png');
}
function getImageData(source) {
var image = new Image();
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
for (var px = 0, cx = canvas.width * canvas.height * 4; px < cx; px += 4)
if (data[px+3] != 255 && data[px+3] != 0)
console.log("Alpha: " + data[px+3]);
};
image.src = source;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="scripts/jquery-1.11.3.min.js"></script>
<script src="scripts/script.js"></script>
</head>
<body>
<button id="btnDirective">Generate</button>
</body>
</html>
'imgs/templates/human.png' contains a lot of semitransparent values, that are never fetched:
So you are trying to get the integer values for each pixel where it's alpha value of neither 0 nor 255?
Well, your image has pixels that are either full transparent, or they are solid white/black. So you will have no partially-transparent pixels.
See the image of the chili pepper emoji from Emojipedia that is used below. Around ~6% of its pixels are partially transparent (around the borders).
$(function() {
$('#btnDirective').click(generateEmoteDirectiveFile);
});
function generateEmoteDirectiveFile() {
getImageData('https://i.imgur.com/4LzuX3G.png');
getImageData('https://i.imgur.com/R7g697w.png'); // Using a testable image
}
function getImageData(source) {
var image = new Image();
image.crossOrigin = 'Anonymous'; // This allows Imgur CORS...
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
document.body.appendChild(canvas); // Add canvas to body...
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
var pixels = canvas.width * canvas.height;
var alphaValues = [];
for (var px = 0, cx = pixels * 4; px < cx; px += 4) {
if (data[px + 3] != 255 && data[px + 3] != 0) {
alphaValues.push(data[px + 3]);
}
}
var nonAlphaPixels = (alphaValues.length / pixels * 100).toFixed(2);
console.log('Alpha (' + nonAlphaPixels + '%): ' + alphaValues.join(','));
};
image.src = source;
}
function drawPartialPixels(imageData) {
}
body { background: #444; }
#btnDirective { display: block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnDirective">Generate</button>
Here is an example of drawing only the partial pixels.
$(function() {
$('#btnDirective').click(generateEmoteDirectiveFile);
});
function generateEmoteDirectiveFile() {
getImageData('https://i.imgur.com/R7g697w.png', onImageLoad);
}
function getImageData(source, onLoadFn) {
var image = new Image();
image.src = source;
image.crossOrigin = 'Anonymous'; // This allows Imgur CORS...
image.onload = function() {
onLoadFn(this);
};
}
function onImageLoad(image) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = canvas.width * canvas.height;
for (var px = 0, cx = pixels * 4; px < cx; px += 4) {
var partialAlpha = imageData.data[px + 3] != 255 && imageData.data[px + 3] != 0;
imageData.data[px + 0] = partialAlpha ? 255 : 0;
imageData.data[px + 1] = partialAlpha ? 0 : 0;
imageData.data[px + 2] = partialAlpha ? 0 : 0;
imageData.data[px + 3] = partialAlpha ? 255 : 0;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.putImageData(imageData, 0, 0);
document.body.appendChild(canvas); // Add canvas to body...
}
body { background: #444; }
#btnDirective { display: block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnDirective">Generate</button>

Converting canvas to PNG returns blank image

I am experiencing an issue with converting a canvas to PNG.
Although the canvas looks exactly as I want it and the conversion from canvas to data URL PNG seems right, the image is blank.
I also tried converting a div to PNG but it did not work for me because I wanted a greyscale filter to be applied. Anyone have any ideas?
JavaScript
var imgis = new Image();
var bubble = new Image();
var canvasWidth;
var canvasHeight;
var ctx = canvas.getContext('2d');
bubble.onload = function() {
var imgis = new Image();
var bubble = new Image();
var ctx = canvas.getContext('2d');
bubble.onload = function() {
// set the canvas' size
canvas.width = this.width;
canvas.height = this.height;
// first fill a rect
ctx.fillStyle = 'rgba(255, 255, 255, 0)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// set the gCO
ctx.globalCompositeOperation = 'luminosity';
// if the browser doesn't support Blend Modes
console.log(ctx.globalCompositeOperation)
if (ctx.globalCompositeOperation !== 'luminosity')
fallback(this);
else {
// draw the image
ctx.drawImage(this, 0, 0);
ctx.drawImage(imgis, 30, 60);
// reset the gCO
ctx.globalCompositeOperation = 'source-over';
}
}
imgis.crossOrigin = "anonymous";
bubble.crossOrigin = "anonymous";
imgis.src = "image1 src";
bubble.src = "image2 src";
function fallback(img) {
// first remove our black rectangle
ctx.clearRect(0, 0, canvas.width, canvas.height);
//draw the image
ctx.drawImage(img, 0, 0);
ctx.drawImage(imgis, 30, 60);
// get the image data
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var d = imgData.data;
// loop through all pixels
// each pixel is decomposed in its 4 rgba values
for (var i = 0; i < d.length; i += 4) {
// get the medium of the 3 first values
var med = (d[i] + d[i + 1] + d[i + 2]) / 3;
// set it to each value
d[i] = d[i + 1] = d[i + 2] = med;
}
// redraw the new computed image
ctx.putImageData(imgData, 0, 0);
}
canvas = document.getElementById('canvas');
var image = Canvas2Image.convertToPNG(canvas);
console.log(image.src);
// document.getElementById('theDemo').src = image.src;
var image_data = $(image).attr('src');
console.log(image_data);
$("#theDemo").attr('src', image_data);
HTML
<canvas id='canvas' > </canvas>
<img src="" id="theDemo" />
I assume you're using canvas2image. You should replace var image = Canvas2Image.convertToPNG(canvas); with Canvas2Image.convertToPNG(canvas, width, height). Hopefully that helps!
EDIT Since the issue is with the actual canvas to base64 conversion, you can try to use the .toDataURL() method instead of using that library. My comment explains how to test this in your specific code.

Pixelated resize using canvas with transparent PNG

I want to accomplish a pixelated effect using the canvas option imageSmoothingEnabled=false; so the image "unblurs" on scroll.
Everything works fine until using transparent images namely PNGs. The scaled image is projected, which stays in the background.
Also the image does not get loaded until the user has scrolled a few pixels.
I've found out that the canvas.drawImage() function owns parameters to set the offset. However I haven't found a solution to this.
Demo https://jsfiddle.net/aLjfemru/
var ctx = canvas.getContext('2d'),
img = new Image(),
play = false;
/// turn off image smoothing - this will give the pixelated effect
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
/// wait until image is actually available
img.onload = function(){
image1.src="nf.png";
context.drawImage(image1, 50, 50, 10, 10);
};
img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';
/// MAIN function
function pixelate(v) {
document.getElementById("v").innerHTML = "(v): " + v;
/// if in play mode use that value, else use slider value
var size = v * 0.01;
var w = canvas.width * size;
var h = canvas.height * size;
/// draw original image to the scaled size
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, w, h);
ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}
function onScroll() {
$(window).on('scroll', function() {
var y = window.pageYOffset;
if (y > 10) {
y = Math.pow(y, 0.8);
if (y >= 60) {
y = 100;
}
pixelate(y);
}
});
}
onScroll();
Some quick changes to get it happening
Use a second canvas to do the pixelation
Wait for the images to load before doing the rendering.
The onscroll will not fire until you scroll, so when image has loaded call the rendering function to display the image.
canvas.width = innerWidth-20;
ctx = canvas.getContext("2d");
var ctxImage;
const img = new Image;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';
/// wait until image is actually available
img.onload = function(){
// I dont knwo what this is for so removed the following two lines
//image1.src="nf.png";
//context.drawImage(image1, 50, 50, 10, 10);
// Create a canvas to match the image
var c = document.createElement("canvas");
canvas.width = Math.min(canvas.width,(c.width = this.naturalWidth));
canvas.height = c.height = this.naturalHeight;
ctxImage = c.getContext("2d");
// changing canvas size resets the state so need to set this again.
ctx.imageSmoothingEnabled = false;
onScroll();
pixelate(100); // call first time
};
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.fillText("Loading please wait.",ctx.canvas.width /2, ctx.canvas.height / 4);
/// MAIN function
function pixelate(v) {
document.getElementById("v").innerHTML = "(v): " + v;
/// if in play mode use that value, else use slider value
var size = Number(v) * 0.01;
var w = img.width * size;
var h = img.height * size;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctxImage.clearRect(0, 0, ctxImage.canvas.width, ctxImage.canvas.height);
ctxImage.drawImage(img, 0, 0, w, h);
ctx.drawImage(ctxImage.canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}
function onScroll() {
addEventListener("scroll", function() {
var y = window.pageYOffset;
if (y > 10) {
y = Math.pow(y, 0.65);
if (y >= 100) {
y = 100;
}
pixelate(y);
}
});
}
#fix {
position: fixed;
}
html {
height: 2000px;
}
<div id="fix">
<p id="v" value="Animate">1</p><br />
<canvas id="canvas"></canvas>
</div>
This has since been made into an extremely minimalist library, and my PR for PNG support can be found here.
Once it has been merged I will come back and update this answer.
The full code, generalized and simplified from #Blindman67's answer:
/**
* 8bit
*
* A module that converts an image into a pixelated version (just like
* 8bit artwork).
*
* #author rogeriopvl <https://github.com/rogeriopvl>
* #license MIT
*/
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.eightBit = factory();
}
} (this, function () {
// Necessary to hide the original image with PNG transparency
const invisibleCanvas = document.createElement("canvas");
const invisibleCtx = invisibleCanvas.getContext("2d");
/**
* Draws a pixelated version of an image in a given canvas.
* #param {object} canvas - a canvas object
* #param {object} image - an image HTMLElement object
* #param {number} quality - the new quality: between 0 and 100
*/
const eightBit = function (canvas, image, quality) {
quality /= 100;
canvas.width = invisibleCanvas.width = image.width;
canvas.height = invisibleCanvas.height = image.height;
const scaledW = canvas.width * quality;
const scaledH = canvas.height * quality;
const ctx = canvas.getContext("2d");
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
// Draws image scaled to desired quality on the invisible canvas, then
// draws that scaled image on the visible canvas.
ctx.clearRect(0, 0, canvas.width, canvas.height);
invisibleCtx.clearRect(0, 0, invisibleCtx.canvas.width, invisibleCtx.canvas.height);
invisibleCtx.drawImage(image, 0, 0, scaledW, scaledH);
ctx.drawImage(invisibleCtx.canvas, 0, 0, scaledW, scaledH, 0, 0, canvas.width, canvas.height);
};
return eightBit;
}));

Resizing base64 image does not work in Firefox

I tried many different ways, but in Firefox, when I resize the first time, it returns a blank image:
function imageToDataUri(img, width, height) {
var canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
setTimeout(function () {
cursorimg = canvas.toDataURL();
}, 500);
}
This is my function and I call it like this:
cursorImage.onload = function(){
imageToDataUri(cursorImage, width, height);
}
I had the exact same issue as you, and the issue disappeared when I created the canva outside the "onload" callback, like this:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
cursorImage.onload = function(){
ctx.drawImage(img, 0, 0, width, height);
cursorimg = canvas.toDataURL();
}
I'm still a beginner in JavaScript, I can't explain why it worked...

Categories

Resources