I have an image tag in my HTML code with src containing the path to a local image.
<img alt="abc" src="./images/abc.png" />
Upon clicking the image, I want to call a JavaScript method that will return the buffer data of the image.
Example buffer:
(23234)[234,345,786]
How is it done in pure JavaScript?
You can not read pixels from an image, but you can draw an image to a canvas, and use getImageData to extract an array of the RGBA pixel data. Then it is possible to get color under the mouse cursor.
Notes about the example below:
the image is tiny because getImageData has cross-origin protection, and as uploading images for examples does not seem to be possible, the image is encoded in a data URI
however data URI-s also have cross-origin issues in certain browsers, like IE (it will not with IE as far as I remember). I tested the code with Chrome, so that works for sure, and I think it should work with Firefox too
none of these matters with real life code, so if you get this code out from here, and just write <img src="something.jpg" ... (so hosted locally), it can be a large image and it will work with IE too
there is some race condition here, sometimes I get messages about missing imgready function, so StackOverflow may load the HTML first and inject the scripts later. If you see that message, run the snippet again. With more "traditional" code order (scripts located in head) it could not happen
var imgdata;
function imgready(){
var img=document.getElementById("you");
var cnv=document.createElement("canvas");
var w=cnv.width=img.width;
var h=cnv.height=img.height;
var ctx=cnv.getContext("2d");
ctx.drawImage(img,0,0);
imgdata=ctx.getImageData(0,0,w,h);
}
function mmove(event){
if(!imgdata)return;
var x=event.clientX-event.target.offsetLeft;
var y=event.clientY-event.target.offsetTop;
var offset=(x+y*imgdata.width)*4;
var r=imgdata.data[offset];
var g=imgdata.data[offset+1];
var b=imgdata.data[offset+2];
document.getElementById("logdiv").innerText=x+","+y+" ("+offset+"): r="+r+" g="+g+" b="+b;
var cnv=document.getElementById("colorcnv");
var ctx=cnv.getContext("2d");
ctx.clearRect(0,0,cnv.width,cnv.height);
ctx.fillStyle="rgb("+r+","+g+","+b+")";
ctx.beginPath();
ctx.arc(10,10,10,0,Math.PI*2);
ctx.fill();
}
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QAqRXhpZgAASUkqAAgAAAABADEBAgAHAAAAGgAAAAAAAABHb29nbGUAAP/bAIQAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFAEDBAQFBAUJBQUJFA0LDRQUFBQUExQPFBQUFBQUFBQUFBQUFBQUEBUUFBQVDxQUFA4UFBQVFBEVFBQTFBQUERQU/8AAEQgAFAAUAwERAAIRAQMRAf/EABoAAAEFAQAAAAAAAAAAAAAAAAgEBQYHCQP/xAAnEAABAwMEAQMFAAAAAAAAAAABAgMFBBEhAAYHEmETIjEII0FCof/EABkBAAIDAQAAAAAAAAAAAAAAAAQGAwUHAv/EACwRAAEDAwIDBgcAAAAAAAAAAAECAxEABCExUQUGEkFhweHw8RMiMnGBsdH/2gAMAwEAAhEDEQA/AM6GuRZOaplxjVGyh2oQWkuNEhQxm3m2NVhtUNHrJwKPDql/KBVkO/SDPDa9DKRM9QyMm+EOCLbSUOtNFQBeKrmyR83tnqbXItpbb5nZLpbeaKUyROudojt98VZq4QtKAptYJ1inWqjEsVC2i428WyUF1o3Qu2OyTYYPyNGJV1CRiuYjFRSf4KmuERszcM49RvOzdIJOgj2qhtai0W0KBc6LUW7esgWUkEnsAD1JDOi3evVFgCJ7Z8KqSWmEhwKk7R40SXB3M8NOcPbm2puGoVB1VLQ1b7zTTQSiqZKlOKSwv9VdlC4JTg4CsqTn/HuWb3h9wi4t09SCpIB1IOAOoffAORvGlMVpxVm5a+C4YUAZ79Tj1/aGyOl9xGjbK32XV2ytbIyfFrY8/nW0K5aszmFD8+RpUTfORSrdG5ZvccjGtzM7LTbVBQKYo25Svdq00rVh9toOKV6aPan2psMDGg+GmHFK2FDOfTXCnYQaZN09u1yQrOQQR/dPgSClJ7/36mgN6WvrU2vrcqsPk6kccKVECpUiRX//2Q==" id="you" onload="imgready()" onmousemove="mmove(event)">
<canvas id="colorcnv" width="20" height="20"></canvas><br>
<div id="logdiv"></div>
Modified version of tevemadar's answer that might be usefull:
function imgToBuffer(e){
let cnv=document.createElement("canvas"), w=cnv.width=e.width, h=cnv.height=e.height, ctx=cnv.getContext("2d");
ctx.drawImage(e,0,0);
return getImageData(0,0,w,h)
}
This function simply draws the image element to canvas and returns the image buffer. No extra HTML needed.
To get the ArrayBuffer out of it, use
imgToBuffer(el).data.buffer
Related
I've used the following code in an embedded code field on Google Sites to display images on my website, it's all going well on my Windows, Linux and Android devices, but they don't show up on the iPhone (whether using Chrome or Safari)!
<form name="submit-to-google-sheet">
<img id="img1" width=163 height=227>
</form>
<script>
const img1 = document.getElementById('img1');
img1.src = "https://docs.google.com/uc?export=view&id={imageGoogleDriveID}";
</script>
some context/constraints: I'm pulling my images from my Google Drive. They are ~80kb JPEGs. I'm using a HTML form as I have other elements (buttons, fields) which I've removed from the code extract below to focus on the issue. I need to keep this form.
I've explored the Base64 format which does allow to display the images on iOS-operated devices (or so I understood). It works if I just set the image source to a Base64 URI:
imgBase64.src = "data:image/jpeg;base64,/9j/4 [...] //9k=";
But I can't call a Base64 file from Drive as conveniently as a JPEG.
I'm manipulating 250+ images so I can't either have the base64 strings in the middle of the code, it'd be too large to work with.
I've come up with the piece of code below, and I end up getting:
on Android/Windows: a nice image for img1 and a simple black square for imgBase64
on iOS: an empty box for img1 (my issue in the first place) and a simple black square for imgBase64
After investigation, it seems that the URI I get out of canvas.toDataURL("image/jpeg") is not at all the same thing as what I get out of an encoder (such as base64.guru/converter/encode/url). It is very short and I get a lot of As. It seems that the canvas is not loading the image correctly:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCADjAKMDAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AJ/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//Z
Any idea why the conversion doesn't work?
<form name="myForm">
<img id="img1" width=163 height=227>
<img id="imgBase64" width=163 height=227>
</form>
<script>
const form = document.forms['myForm'];
var imageUrl = "https://docs.google.com/uc?export=view&id={imageGoogleDriveID}";
const img1 = document.getElementById('img1');
img1.src=imageUrl;
const imgBase64 = document.getElementById('imgBase64');
const canvas = document.createElement("canvas");
canvas.width = 163;
canvas.height = 227;
img1.onload = function() {
canvas.getContext("2d").drawImage(img1, 0, 0);
}
var dataURL = canvas.toDataURL("image/jpeg");
imgBase64.src = dataURL; //gives me a black square
imgBase64.src = "data:image/jpeg;base64,/9j/4 [...] //9k="; //works fine!
</script>
We just found the fix for iOS: when third-party cookies and cross-site tracking are blocked, the images don't load. The settings to toggle are explained here.
Base64 wasn't the solution, since the issue was coming from pulling images from my Google Drive, i.e. a different domain from my website. However I still haven't found why drawImage() doesn't work.
So, I'm trying to programmatically add an image to my canvas, from a Javascript function :
// Spawn function
var spawnWrapper = function() {
myCanvas = Processing.getInstanceById('mycanvas');
// myCanvas.ellipse(50,50,50,50); // works fine here too
myImage = myCanvas.loadImage('pegman.png');
myCanvas.image(myImage,0,0);
};
The same successive calls in console works :
Also, there are no errors mentioned on the console.
I'm really stuck there and would appreciate any help ;-)
I suspect that you might be missing the preload directive.
This directive regulates image preloading, which is required when
using loadImage() or requestImage() in a sketch. Using this directive
will preload all images indicated between quotes, and comma separated
if multiple images are used, so that they will be ready for use when
the sketch begins running.
I hope that helps. I'm curious as to why you're using processing.js instead of P5.js?
Good luck.
I'm making a Chrome extension which in order to reduce bandwidth usage it stops all outcoming requests which are images.
I want to provide functionality where if the user clicks on the image (or technically a layer on top of that image) it would try to reload the image, this time not being blocked by the extension.
How can I tell the browser to retry loading the image? And if there isn't a straightforward way to do it, what would be a work around? Deleting the old image from the DOM and adding it again?
Any help is appreciated. :)
EDIT 1:
To answer #CBroe's question:
Using the chrome.webRequest.onBeforeRequest API in a background script.
To answer #jfriend00's question:
The usual placeholder "couldn't load image" icon, I guess also known as "broken file" icon:
See all those broken images?
That screenshot also illustrates the point of a layer on top of another image. Should those images not be broken, the loaded image would be there but that layer (the one in a dark grey which shows the image's dimensions) still remains there.
The desired href still exists there in the img tag:
If simply assigning the same src value to the img element is not enough¹, then create a new Image object in JavaScript, and assign the value to its src property.
¹ It might not be, if the browser just goes, “oh hey, that is the same value for the src attribute that the img already had, so I don’t have to do anything” – creating a new JS Image object however should make the browser request that resource again if he realizes he does not have it cached already.
What I would do instead is replace the URLs of the images with an image from your extension. A 1x1 pixel transparent GIF or PNG.
When you do this, add an attribute to all of the elements you replaced... something like data-yourextension-originalurl, with the URL of the original image. If the user then wants to load images, it's easy enough to go back and fix those image elements.
While I'm not too familiar with the Chrome API, a quick glance seems to suggest that there's no way to get the specific img element from each onBeforeRequest, which you'd need to know in order to figure out where to attach custom code.
This may be better accomplished with native JavaScript of some sort. For example, if Chrome lets you inject code on load, you could apply a function like the one below to all img elements after document load but before image load.
// Given an img element, replaces its src with a placeholder URL,
// and sets its click action to load its original src
function makePlaceholder(elem){
elem["data-oldtitle"] = elem.title;
elem["data-oldhref"] = elem.href;
elem["data-oldsrc"] = elem.src;
elem["data-oldonclick"] = elem.onClick;
elem.title = "Click to load the blocked image.";
elem.href = '';
elem.src = "http://example.com/placeholder.png";
elem.onClick = function(){
this.src = this["data-oldsrc"];
this.title = this["data-oldtitle"];
this.href = this["data-oldhref"];
this.onClick = this["data-oldonclick"];
};
}
The simple way to force reloading an image in JavaScript is:
var img = document.getElementById("myImage");
img.src = img.src.replace(/\?.+/,"") + "?" + new Date().getTime();
This adds a unique QueryString to the image which basically forces the browser to not use a cached version of the image.
I have done the following code to convert HTML Content(DIV) to save as Image (JPEG, PNG,GIF Etc) with below code.
<pre>
html2canvas($(".mainbox"), {
onrendered: function(canvas) {
theCanvas = canvas;
document.body.appendChild(canvas);
Canvas2Image.saveAsImage(canvas);
$("#FinalImage").append(canvas);
}
});
</pre>
I have also included html2canvas.js,base64.js and canvas2image.js in my page. At the end Image is shown in #FinalImage DIV and browser ask me to save it in my drive up to now all are working fine.
Now the question is name of the saved image has no Extension, every time I need to go to the image and assign the Extension(".jpg",".png" etc...). Is there any solution to set extension by default when user saves from the browser.
Thanks in advance.
I have done same functionality for capturing signature. This is different from your approach. but this code snippet may help you. plz comment if u need whole source code.
var canvas = document.getElementById(<canvas element id>)// get canvas element
var dataURL = canvas.toDataURL("image/png");// convert to img, specify extension
document.getElementById(<new image id>).src = dataURL; // write as an image
In line two I specified png.there you can change the extension of image. Hope it helps
I'm making an Android game, in HTML5 and Javascript, I am part of the way there, but have hit something that has stumped me, My JS file and my Html file were working together, to draw on the canvas etc, but now I'm trying to draw an image on the canvas, nothing is being displayed, I know the img function is being found, as, alert (img);, works so it's just lost on me. (currently this is copied from a book I was given at college, and it's identical, the JS has been verified in JSHint and passes, so I'm lost) also, please be quite simple, I'm pretty new to JS but have used html for a long time, and this just has to be a simple game for a college assignment.
My HTML code is
<canvas id="game" width="1024" height="600">Sorry, your browser does not support this</canvas>
and my JS is:
function init() {
var elem = document.getElementById('game');
var canvas = elem.getContext('2d');
var img = document.createElement('img');
img.setAttribute('src', 'http://www.minkbooks.com/content/snow.jpg');
img.addEventListener("load", function() {
canvas.drawImage(img, 20, 20);
alert(canvas);
});
}
addEventListener("load", init);
and here it is on JSfiddle: http://jsfiddle.net/xw8m7/
This answer is based on your jsfiddle. You are executing your javascript code as soon as it is loaded. Depending on where your code is located in the html, the canvas element might not be loaded yet, and that would prevent your code from loading the image into the canvas element, and you would still get the alert.
In JSFiddle, you need to set the option of running your code "onDomready". That means that the JavaScript won't run until everything has been loaded (your canvas element). After changing that in your jsfiddle, your function loaded the image into the canvas just fine.
Update:
Based on your comment about XDK, I found a bit of example code and modified it. Original source: https://software.intel.com/en-us/node/493117
document.addEventListener("intel.xdk.device.ready",function(){
init();
},false);