Can we get the real image size through the canvas? - image

In image tag, if we don't supply width and height property, we will get nothing when retrieving the width and the height of the image. I am using the canvas element to load an image and scale it proportionally. In order to do this, I have to get the actual image size. Is it possible to do that in html 5?

The HTMLImageElement has two properties for this, naturalWidth and naturalHeight. Use those.
As in:
var img = new Image();
img.addEventListener('load', function() {
// once the image is loaded:
var width = img.naturalWidth; // this will be 300
var height = img.naturalHeight; // this will be 400
someContext.drawImage(img, 0, 0, width, height);
}, false);
img.src = 'http://placekitten.com/300/400'; // grab a 300x400 image from placekitten
It is wise to set source only after the event listener is defined, see Phrogz's exploration on that here: Should setting an image src to data URL be available immediately?

You cannot retrieve width/height before image has been loaded.
Try something like:
// create new Image or get it right from DOM,
// var img = document.getElementById("myImage");
var img = new Image();
img.onload = function() {
// this.width contains image width
// this.height contains image height
}
img.src = "image.png";
Anyhow onload will not fire if image has been loaded before script execution. Eventually you can embed script in html <img src="test.jpg" onload="something()">

if I understand you correctly, you can use the getComputedStyle method.
var object = document.getElementById(el);
var computedHeight = document.defaultView.getComputedStyle(object, "").getPropertyValue("width");

Not fully understood your question.
But you can use javascript to get the width and height of the image.
and then pass it into
/ Five arguments: the element, destination (x,y) coordinates, and destination
// width and height (if you want to resize the source image).
context.drawImage(img_elem, dx, dy, dw, dh);
while drawing image on canvas.
or check this if it helps
http://jsfiddle.net/jjUHs/

Related

How to use x2 canvas elements and rendering paper.js on img capture of html5 video to base64

Still very much a newbie to coding, so please be gentle :)
I'm hoping someone might be able to help how to use Paper.js on a second canvas after the first one has been executed?
I'm trying to use x2 canvas elements:
Canvas 1 - to capture a html5 video image still and convert to base64 (tick :-) = done)
Canvas 2 - Use the base64 image and perform the 'Working with Rasters to find the colors of pixels' and convert to circle paths (boo = fail :-( )
Something like this:
The code:
<script src="https://cdn.jsdelivr.net/npm/hls.js#latest"></script>
<video id="video" preload="auto" muted="" playsinline="" width="580" src="blob:https://www.georgefisher.co.uk/78e3a45c-ae07-4ea5-af56-45a5ed9cf1b0"></video>
<script>
var video = document.getElementById('video');
var videoSrc = 'https://camsecure.co/HLS/georgefisher.m3u8';
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
}
video.play()
</script>
<br>
<button onclick="capture()">Capture</button>
<br>
<canvas id="canvas" style="overflow:auto">
</canvas>
<canvas id="canvas2" resize>
<img src="" id="myImg"/></canvas>
var resultb64="";
function capture() {
var canvas = document.getElementById('canvas');
var video = document.getElementById('video');
canvas.width = video.videoWidth/4;
canvas.height = video.videoHeight/4;
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth/4, video.videoHeight/4);
resultb64=canvas.toDataURL();
document.querySelector("#myImg").src = canvas.toDataURL();
}
/*Paper JS Setup for working in CodePen */
/* ====================== *
* 0. Initiate Canvas *
* ====================== */
// expose paperjs classes into global scope
paper.install(window);
// Only executed our code once the DOM is ready.
window.onload = function() {
// bind paper to the canvas
paper.setup('canvas2');
// paper.activate();
// Get a reference to the canvas object
var canvas = document.getElementById('canvas2');
var ctx = canvas.getContext('2d');
// console.log(ctx, image);
// ctx.drawImage(image, 0, 0);
// return;
// }
// Create a raster item using the image id='' tag
var image = document.querySelector('img');
var raster = new Raster(image);
// Hide the raster:
raster.visible = false;
// The size of our grid cells:
var gridSize = 15;
// Space the cells by 120%:
var spacing = 1
;
// As the web is asynchronous, we need to wait for the raster to load before we can perform any operation on its pixels.
raster.onLoad = function() {
// Since the example image we're using is much too large, and therefore has way too many pixels, lets downsize it to 40 pixels wide and 30 pixels high:
raster.size = new Size(40, 30);
for (var y = 0; y < raster.height; y++) {
for(var x = 0; x < raster.width; x++) {
// Get the color of the pixel:
var color = raster.getPixel(x, y);
// Create a circle shaped path:
var path = new Path.Circle({
center: new Point(x, y).multiply(gridSize),
radius: gridSize / 2 / spacing,
});
// Set the fill color of the path to the color
// of the pixel:
path.fillColor = color;
}
}
// Move the active layer to the center of the view, so all the created paths in it appear centered.
project.activeLayer.position = view.center;
}
}
I've tried giving the second canvas a different Id="canvas2" and referencing that, which I can see in the console. However, nothing appears in the second canvas and the paper.js script doesn't seem to execute, can someone help me understand why?
Please see also see link to the fiddle below:
https://jsfiddle.net/jmnes/o4Lpkfs6/1/
Alternatives method.
You don't need to capture the video, you don't need to capture the pixels using paper.js and raster. You don't need to find the color of each circle and draw it.
All these methods are slow, complex, and power hungry.
You can create a mask and mask out the circles, with the colors drawn from a smaller canvas with a res that matches the number off circles.
How to
Add one (main canvas) canvas to the DOM. This will display the result
Create 2 offscreen canvas.
One (color canvas) has the same resolution as the circles you want to display. Eg if you have 30 by 40 circle the canvas res should be 30 by 40
One (mask canvas) is the circle mask. It is the same resolution as the main canvas. Draw the circles all in one color on this canvas.
Then rendering once a frame
Draw the video on the color canvas to fit.
Turn off smoothing on the main canvas eg ctxMain.imageSmoothingEnabled = false
Draw the color canvas onto the main canvas to fit.
This will draw a color square at each circle position. ctx.drawImage(colorCanvas, 0, 0, mainCanvas.width, mainCanvas.height)
Set composite operation "destination-in" eg ctxMain.globalCompositeOperation = "destination-in"
Draw the mask canvas (canvas with circles on it) onto the main canvas. This will remove pixels outside each circle.
Restore default composite operation for the main canvas ctxMain.globalCompositeOperation = "source-over"
All done for a real-time FX on almost any device.
The above methods is the fastest way to render the effect you are after using the 2D API

drag-drop, resize images and then drawing features in 1 canvas

I am working on an application where the user comes and sees a blank area(div or canvas or whatever, lets call it mycanvas hereafter). Now he drags some images from outside(a div) and drops them on mycanvas. He can also resize them. And, he can also draw something in mycanvas with pencils and colors with erasing feature. Now, as per my research till now, I've figured out that the drawing part is a pure HTML 5 canvas stuff. So, no problem with that. But I'm not sure whether he can drop images from an outside div/canvas to mycanvas. Please tell me how to achieve all the three features(drag-drop from outside, draw with pencil, resize images) in a single area.
I have create a online dnd editor by Html5Canvas.
I will create a loop first
var loop = function(){
// Operation Here
}
self.setInterval(loop, 1000/60);
Create the data model, for example a image
var DndImage = function(x, y, width, height, image){
this.type = "image";
this.image = image;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
Then we draw the image in the looping
var ObjectArray = new Array();
var WIDTH = 800;
var HEIGHT = 600;
var loop = function(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, WIDTH, HEIGHT);
for(var x = 0; x < ObjectArray.length; x++){
if(ObjectArray[x].type == "image")
context.drawImage(ObjectArray[x].image,ObjectArray[x].x,ObjectArray[x].y, ObjectArray[x].width, ObjectArray[x].height);
}
}
Function to add New image object
function addImage(src, x, y, width, height){
var img = new Image();
img.src = src;
img.onload = function(){
ObjectArray.push(new DndImage(x, y, width, height, img));
}
}
And now if you want to do a dnd, You need to do is set up a Listener to listen the mouse move event. And set the DndImage Object x and y to follow the mouse position in the image canavs. You can scale the image or changing the size too.
docuemnt.addEventListener("mousedown", function(){ });
docuemnt.addEventListener("mouseup", function(){ });
docuemnt.addEventListener("mousemove", function(){ });
docuemnt.addEventListener("click", function(){ });
Hope I can help you :D
You can achieve all the required features using kinetic js.
To drag, drop and resize
http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/
To paint using different shapes, say a line:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-line-tutorial/
and dropping from outside canvas is the simplest thing, probably:
http://www.w3schools.com/html/html5_draganddrop.asp
Just check these and let me know if there is any problem in integration.

HTML5 canvas, scale image after drawing it

I'm trying to scale an image that has already been draw into canvas.
This is the code:
var canvas = document.getElementById('splash-container');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw image at its original size
context.drawImage(imageObj, 0, 0);
};
imageObj.src = 'images/mine.jpeg';
// Now let's scale the image.
// something like...
imageObj.scale(0.3, 0.3);
How should I do?
You're thinking about it wrong. Once you've drawn the image onto the canvas it has no relationship to the imageObj object. Nothing you do to imageObj will affect what's already drawn. If you want to scale the image, do in the drawImage function:
drawImage(imgObj, 0, 0, imgObj.width * 0.3, imgObj.height * 0.3)
If you want to animate the scaling or are looking to achieve some other effect which requires you to draw the image at full size initially you'll have to first clear it before drawing the scaled down image.
What robertc says is correct, but if you really wanted to scale an image on a canvas after drawing it for some reason, you could just scale the whole canvas using the CSS width/height properties and that would scale the image without having to redraw it.

Titanium: get png height without creating ImageView

Is there a way to get a .png height without creating ImageView?
The methods I found on google require createImageView first and then doing a .height.
I want to avoid creating ImageView because I'm going to createImageView after I get the height of the png and perform some changes.
Or rather, I will be using the height value during the var imagevariablename = Ti.UI.createImageView itself, so I can't using imagevariablename.height because the declaration of var imagevariablename is not done yet.
I don't know of any way to get the height / width of an image without creating an imageView in Titanium. In my app, I create a temporary image view and read the attributes without ever adding it to a view / window. Then you can create the 'real' image view once you know the size:
var imageTemp = Ti.UI.createImageView({
image : someFile.read(),
height:'auto',
width:'auto'
});
Ti.API.info( "height=" + imageTemp.size.height);
Ti.API.info( "width=" + imageTemp.size.width);
imageTemp = null;
Try this code
var imageTemp = Ti.UI.createImageView({
image : <image>,
height:'auto',
width:'auto'
}),
imageSize = imageTemp.toImage();
Ti.API.info( "height=" + imageSize.height);
Ti.API.info( "width=" + imageSize.width);
imageTemp = imageSize = null;
If you create a Blob from your image you can get width and height from the blob
From Titanium docs:
If this blob represents an image, this is the height of the image in pixels.
In my condition this is run like this.
var imageTemp = Ti.UI.createImageView({
image : someFile.read(),
height:'auto',
width:'auto'
});
alert( "height=" + imageTemp.toBlob().height);
alert( "width=" + imageTemp.toBlob().width);
imageTemp = null;
I was working on this and had trouble with the code above using 3.2.2, testing on Android. Various attempts would just give me 1, 0 or SIZE for the width and height values. This DOES use an imageView, but the following gets me everything I need in this environment. I also am using the load event instead of postLayout. Hopefully this helps someone.
$.map.image = 'http://getyourownimage.com/dev/8fac94c6-872b-4bda-a56a-7dba09188c66.png';
$.map.zIndex = 1;
$.map.width = 'auto';
$.map.height = 'auto';
$.map.addEventListener('load',function(e){
var rect = $.map.getRect();
Ti.API.info(rect.width); //actual width of imageView
Ti.API.info(rect.height); //actual height of imageView
Ti.API.info($.map.getWidth()); //returns auto/SIZE, doesn't work
Ti.API.info($.map.getHeight()); //returns auto/SIZE, doesn't work
Ti.API.info($.map.toImage().width); //some scaled value, not useful
Ti.API.info($.map.toImage().height); //some scaled value, not useful
Ti.API.info($.map.toBlob().width); //image original/full size width
Ti.API.info($.map.toBlob().height); //image original/full size height
alert('rectX:'+rect.width+',rectY:'+rect.height+',mapGW:'+$.map.getWidth()+',mapGH:'+$.map.getHeight()+',tiX:'+$.map.toImage().width+',tiY:'+$.map.toImage().height+',tbX:'+$.map.toBlob().width+',tbY:'+$.map.toBlob().height);
});

html5: copy a canvas to image and back

I implemented a zoom in and out function on a canvas element.
it works by scaling the canvas, translating it, and then redraw the whole scene again.
the problem is that it takes a lot of time to redraw everything because i got a lot of things on my canvas.
I need a way to copy the canvas to an image object and than copy the image back to the canvas without loosing quality. what are the specific methods to copy canvas to a javascript variable, and to to copy this variable back to the canvas later?
I'll be glad if you write down the code because I couldn't find any good explanation over the internet.
thanks,
The drawImage() method can draw to a canvas using another canvas instead of an image.
You could create a 'backup' canvas, of the same size as your original, draw the first one to there and then draw that one back to the original when you need it.
e.g.
// Assume we have a main canvas
// canvas = <main canvas>
ctx = canvas.getContext('2d');
..
// create backing canvas
var backCanvas = document.createElement('canvas');
backCanvas.width = canvas.width;
backCanvas.height = canvas.height;
var backCtx = backCanvas.getContext('2d');
// save main canvas contents
backCtx.drawImage(canvas, 0,0);
..
// restore main canvas
ctx.drawImage(backCanvas, 0,0);
There are a few ways to do it theres the getImageData and putImageData methods Reference, However putImageData and getImageData are pretty slow. Another way is to save the data to an image in memory and recall it from that which is much faster, then the third way is the one above mentioned by andrewmu which involves copying to another canvas element. I have included examples for the first and second type.
Image in memory method
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
savedData = new Image();
function save(){
// get the data
savedData.src = canvas.toDataURL("image/png");
}
function restore(){
// restore the old canvas
ctx.drawImage(savedData,0,0)
}
getImageData putImageData method
// Setup our vars, make a new image to store the canvas data
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
canvasData = '';
function save(){
// get the data
canvasData = ctx.getImageData(0, 0, 100, 100);
}
function restore(){
// restore the old canvas
ctx.putImageData(canvasData, 0, 0);
}
added image into canvas
var image = new Image();
image.src = "1.jpg";
image.onload = function () {
context.drawImage(image, 0, 0);
};

Resources