How to change window level of an image on canvas using javascript - javascript

I have an image on canvas or a set of images that i draw on the canvas. I can draw them fine but I want to change the window level of the image on canvas by dragging the mouse over it. I've seen a lot of external javascript api's but they're quite huge and i don't want to use them for this purpose.
here's my JSFIDDLE that is basically drawing an image on the canvas
this is how my code looks
// Grab the Canvas and Drawing Context
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Create an image element
var img = document.createElement('IMG');
// When the image is loaded, draw it
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
// Specify the src to load the image
img.src = "http://imgsv.imaging.nikon.com/lineup/lens/zoom/normalzoom/af-s_dx_18-140mmf_35-56g_ed_vr/img/sample/sample5_l.jpg";
i need something with basic JS or JQuery. it would be great if you can point me in the right direction using a sample code.
Thanks in advance.

If you want to use JavaScript, try something like:
<script>
var c = document.getElementById("drawingboard");
var ctx = c.getContext("2d");
var mouseDown = 0;
document.body.ontouchstart = function() {
mouseDown+=1;
}
document.body.ontouchend = function() {
mouseDown-=1;
}
function draw(event){
ctx.color='gold';
ctx.fillStyle = "lime";
ctx.drawImage(img,event.clientX,event.clientY);}
</script>

This is what I gained after some research:
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const rangeMin = level - window / 2;
const rangeMax = level + window / 2;
const totalSize = canvas.width * canvas.height;
for (let idx = 0; idx < totalSize; idx++) {
if (imageData.data[idx] < rangeMin) {
imageData.data[idx] = 0;
} else if (imageData.data[idx] > rangeMax) {
imageData.data[idx] = 255;
}
}
ctx.putImageData(imageData, 0, 0);

Related

Dynamically changing Text color depending on Background Image

right now I am writing a small chrome extension. the extension grabs the Bing Image of the Day and sets it as the body background image, and then the extension also grabs the weather, time, date, etc. The problem is that sometimes the image of the day is for example, bright on one side and dark on the other. So, no matter what color the text is, some of it is illegible. How can I determine what color each text should be depending on the background image color behind a SPECIFIC text?
Thanks in advance.
You can use jQuery's attr() function. For example, if you img tag has an id attribute of 'my_image':
<img id="my_image" src="first.jpg"/>
Jquery
$("#my_image").attr("src","second.jpg");
I got something to work.... It is kind of makeshift and not foolproof, but I found a script that calculates overall brightness, which then allows the script to decide whether it should display black or white text. Seems to work well, as of now. Here it is:
function getImageBrightness(imageSrc) {
var img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
document.body.appendChild(img);
var colorSum = 0;
img.onload = function () {
// create canvas
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var r, g, b, avg;
for (var 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;
}
brightness = Math.floor(colorSum / (this.width * this.height));
console.log(brightness);
if (brightness < 150) {
$(".contrast").css("color", "white");
} else {
$(".contrast").css("color", "black");
}
}
}
credit to: https://jsfiddle.net/s7Wx2/

How can i save an image in my computer that has been filtered with CSS [duplicate]

I'm building a new website that will let users apply filters to images (just like Instagram). I will use -webkit-filter for that.
The user must be able to save the filtered image. There is any way I can do that using JavaScript?
You can't save images directly, but you can render them in Canvas, then save from there.
See: Save HTML5 canvas with images as an image
There is no direct/straight forward method to export an image with CSS Filter.
Follow the below steps for Saving/Exporting an Image with -webkit-filter applied on it:
1. Render the image to a canvas:
var canvas = document.createElement('canvas');
canvas.id="canvasPhoto";
canvas.width = imageContaainer.width;
canvas.height = imageContaainer.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(imageContaainer, 0, 0, canvas.width, canvas.height);
Get the ImageData from canvas and apply the filter. Eg: I will apply grayscale filter to the ImageData below:
function grayscale(ctx) {
var pixels = ctx.getImageData(0,0,canvas.width, canvas.height);
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
var v = 0.2126*r + 0.7152*g + 0.0722*b;
d[i] = d[i+1] = d[i+2] = v
}
context.putImageData(pixels, 0, 0);
}
Add an event and use the below code to trigger download
function download(canvas) {
var data = canvas.toDataURL("image/png");
if (!window.open(data))
{
document.location.href = data;
}
}

Render .pdf to single Canvas using pdf.js and ImageData

I am trying to read an entire .pdf Document using PDF.js and then render all the pages on a single canvas.
My idea: render each page onto a canvas and get the ImageData (context.getImageData()), clear the canvas do the next page. I store all the ImageDatas in an array and once all pages are in there I want to put all the ImageDatas from the array onto a single canvas.
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);
p.Out("pre-rendered page " + i);
});
}
//Now we have all 'dem Pages in "pages" and need to render 'em out
canvas.height = 0;
var start = 0;
for(var i = 0; i < pages.length; i++){
if(canvas.width < pages[i].width) canvas.width = pages[i].width;
canvas.height = canvas.height + pages[i].height;
context.putImageData(pages[i], 0, start);
start += pages[i].height;
}
});
So from the way I understnad thing this should work, right?
When I run this I end up with the canvas that is big enought to contain all the pages of the pdf but doesn't show the pdf...
Thank you for helping.
The PDF operations are asynchronous at all stages. This means you also need to catch the promise at the last render as well. If you not catch it you will only get a blank canvas as the rendering isn't finished before the loop continues to the next page.
Tip: I would also recommend that you use something else than getImageData as this will store uncompressed bitmap, for example the data-uri instead which is compressed data.
Here is a slightly different approach eliminating the for-loop and uses the promises better for this purpose:
LIVE FIDDLE
var canvas = document.createElement('canvas'), // single off-screen canvas
ctx = canvas.getContext('2d'), // to render to
pages = [],
currentPage = 1,
url = 'path/to/document.pdf'; // specify a valid url
PDFJS.getDocument(url).then(iterate); // load PDF document
/* To avoid too many levels, which easily happen when using chained promises,
the function is separated and just referenced in the first promise callback
*/
function iterate(pdf) {
// init parsing of first page
if (currentPage <= pdf.numPages) getPage();
// main entry point/function for loop
function getPage() {
// when promise is returned do as usual
pdf.getPage(currentPage).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
// now, tap into the returned promise from render:
page.render(renderContext).then(function() {
// store compressed image data in array
pages.push(canvas.toDataURL());
if (currentPage < pdf.numPages) {
currentPage++;
getPage(); // get next page
}
else {
done(); // call done() when all pages are parsed
}
});
});
}
}
When you then need to retrieve a page you simply create an image element and set the data-uri as source:
function drawPage(index, callback) {
var img = new Image;
img.onload = function() {
/* this will draw the image loaded onto canvas at position 0,0
at the optional width and height of the canvas.
'this' is current image loaded
*/
ctx.drawImage(this, 0, 0, ctx.canvas.width, ctx.canvas.height);
callback(); // invoke callback when we're done
}
img.src = pages[index]; // start loading the data-uri as source
}
Due to the image loading it will be asynchronous in nature as well which is why we need the callback. If you don't want the asynchronous nature then you could also do this step (creating and setting the image element) in the render promise above storing image elements instead of data-uris.
Hope this helps!
I can’t speak to the part of your code that renders the pdf into a canvas, but I do see some problems.
Every resetting canvas.width or canvas.height automatically clears the canvas contents. So in the top section, your clearRect is not needed because the canvas is cleared by canvas.width prior to your every page.render.
More importantly, in the bottom section, all your previous pdf drawings are cleared by every canvas resizing (oops!).
getImageData() gets an array where each pixel is represented by 4 consecutive elements of that array (red then green then blue then alpha). Since getImageData() is an array, so it doesn’t have a pages[i].width or pages[i].height—it only has a pages[i].length. That array length cannot be used to determine widths or heights.
So to get you started, I would start by changing your code to this (very, very untested!):
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
var canvasWidth=0;
var canvasHeight=0;
var pageStarts=new Array();
pageStarts[0]=0;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
// changing canvas.width and/or canvas.height auto-clears the canvas
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
// calculate the width of the final display canvas
if(canvas.width>maxCanvasWidth){
maxCanvasWidth=canvas.width;
}
// calculate the accumulated with of the final display canvas
canvasHeight+=canvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[i]=pageStarts[i-1]+canvas.height;
p.Out("pre-rendered page " + i);
});
}
canvas.width=canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for(var i = 0; i < pages.length; i++){
context.putImageData(pages[i], 0, pageStarts[i]);
}
});
Alternatively, here’s a more traditional way of accomplishing your task:
Use a single “display” canvas and allow the user to “page through” each desired page.
Since you already start by drawing each page into a canvas, why not keep a separate, hidden canvas for each page. Then when the user wants to see page#6, you just copy the hidden canvas#6 onto your display canvas.
The Mozilla devs use this approach in their pdfJS demo here: http://mozilla.github.com/pdf.js/web/viewer.html
You can check out the code for the viewer here: http://mozilla.github.com/pdf.js/web/viewer.js
You can pass the number page to the promises , get that page canvas data and render in the right order on canvas
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
Complete example
function renderPDF(url, canvas) {
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
var context = canvas.getContext('2d');
var scale = 1;
var canvasWidth = 256;
var canvasHeight = 0;
var pageStarts = new Array();
pageStarts[0] = 0;
var k = 0;
function finishPage(localCanvas, num) {
var ctx = localCanvas.getContext('2d');
pages[num] = ctx.getImageData(0, 0, localCanvas.width, localCanvas.height);
// calculate the accumulated with of the final display canvas
canvasHeight += localCanvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[num] = pageStarts[num -1] + localCanvas.height;
if (k + 1 >= pdf.numPages) {
canvas.width = canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for (var i = 0; i < pages.length; i++) {
context.putImageData(pages[i+1], 0, pageStarts[i]);
}
var img = canvas.toDataURL("image/png");
$scope.printPOS(img);
}
k++;
}
function renderPage(page, localCanvas, num) {
var ctx = localCanvas.getContext('2d');
var viewport = page.getViewport(scale);
// var viewport = page.getViewport(canvas.width / page.getViewport(1.0).width);
// changing canvas.width and/or canvas.height auto-clears the canvas
localCanvas.width = viewport.width;
/// viewport.width = canvas.width;
localCanvas.height = viewport.height;
var renderTask = page.render({canvasContext: ctx, viewport: viewport});
renderTask.then(() => {
finishPage(localCanvas, num);
});
}
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
});
}

Using Canvas and Drawimage in functions with video

I am using the HTML5 canvas and DrawImage functions to display low rate video. tnt gave excellent advice to get this project off the ground: Trying to use Canvas and DrawImage to display low-rate video at 90 degrees
While tnt's solution worked fine when the camera and angle are known at load time by using onload functions, I need to be able to turn the video off and on between several cameras and change other parameters. To handle that, a number of individual functions are needed, but I haven't been able to first do a setInterval on a camera and then pass the constantly changing image to DrawImage. 'cam_1.jpg' is the video in the example below. The functions shown in body onload below will also have to be called by other routines during runtime. Any advice will be appreciated.
var cam = null;
var c = null;
var ctx = null;
var ra = 0;
function init() {
cam = new Image;
c = document.getElementsByTagName('canvas')[0];
ctx = c.getContext('2d');
}
function draw(cam) {
ctx.save();
ctx.clearRect( 0, 0, 240, 320 );
ctx.translate( 240, 0);
ctx.rotate(1.57);
ctx.drawImage(cam, 0, 0 );
ctx.restore();
}
function inter() {
setInterval(function(){cam.src = 'cam_1.jpg?uniq='+Math.random();},500);
}
</script></head><body onload = "init(), draw(cam), inter()" >
Thank you.
I suggest you use an object array; something like this:
var cams = []; // an array to hold you cams!
function addcam() {
this.image = new Image;
this.setting1 = 0;
this.settingn = 0;
}
cams[1] = addcam();
cams[1].image.src = "cam1.jpg";
cams[1].setting1 = 2;
setInterval(function(){cam.src = '+cams[1].image.src+'?uniq='+Math.random();},500);
#tnt, Are you suggesting the following? Thank you:
var cams = []; // an array to hold you cams!
function addcam() {
this.image = new Image;
this.setting1 = 0;
this.settingn = 0;
}
function draw(camnum){
cams[1] = addcam();
cams[1].image.src = "cam_1.jpg";
cams[1].setting1 = 2;
cam = new Image;
c = document.getElementsByTagName('canvas')[0];
ctx = c.getContext('2d');
}
function inter() {
setInterval(function(){'cam.src = ' +cams[1].image.src+ '?uniq='+Math.random();},500);
}
function draw(cam) {
ctx.save();
ctx.clearRect( 0, 0, 240, 320 );
ctx.translate( 240, 0);
ctx.rotate( 1.57);
ctx.drawImage(this, 0, 0 );
ctx.restore();
}
</script></head><body onload = "draw(cam), inter()" >

How to use canvas.toDataURL() to get base64 of image in Adobe AIR?

Is it possible to use canvas.toDataURL() in Adobe AIR?
When I try I get the following error:
Error: SECURITY_ERR: DOM Exception 18
Adobe AIR enforces same origin for images used in the canvas API. Once you've used something from another domain in your canvas, you can't get pixel data back out of it. However, you can make use of the Loader class to get the pixel data, and convert it into a canvas ImageData.
For example:
function getDataURL(url, callback) {
var loader = new air.Loader();
loader.contentLoaderInfo.addEventListener(air.Event.COMPLETE, function(event) {
var bitmapData = loader.content.bitmapData;
var canvas = document.createElement('canvas');
canvas.width = bitmapData.width;
canvas.height = bitmapData.height;
var context = canvas.getContext('2d');
var imageData = context.createImageData(canvas.width, canvas.height);
var dst = imageData.data;
var src = bitmapData.getPixels(bitmapData.rect);
src.position = 0;
var i = 0;
while (i < dst.length) {
var alpha = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = alpha;
}
context.putImageData(imageData, 0, 0);
callback(canvas.toDataURL());
});
loader.load(new air.URLRequest(url));
}
window.addEventListener('load', function() {
getDataURL('http://www.google.com/images/logo.gif', function(dataURL) {
air.trace(dataURL);
});
}, false);

Categories

Resources