How do I generate a thumbnail client-side in a modern browser? - html

I'm looking for an elegant way to generate a thumbnail for use with the FileAPI. Currently I get a DataURL representing an image. Problem is, if the image is very large, than moving it around and rerendering it becomes CPU intensive. I can see 2 options to get around this.
Generate a thumbnail on the client
Generate a thumbnail on the server, send the thumbnail back to the client (AJAX).
With HTML5 we have a canvas element? Does anyone know how to use it to generate thumbnails from pictures? They don't have to be perfect -- sampling quality is acceptable. Is there a jQuery plugin that will do this for me? Are there any other way to speed up the clientside use of large images?
I'm using HTML5, and Firefox 3.6+: there is no need to support anything other than Firefox 3.6+, please don't provide suggestions for IE 6.0

Here’s what you can do:
function getThumbnail(original, scale) {
var canvas = document.createElement("canvas");
canvas.width = original.width * scale;
canvas.height = original.height * scale;
canvas.getContext("2d").drawImage(original, 0, 0, canvas.width, canvas.height);
return canvas
}
Now, to create thumbnails, you simply do the equivalent of this:
var image = document.getElementsByTagName("img")[0];
var thumbnail = getThumbnail(image, 1/5);
document.body.appendChild(thumbnail);
Note: Remember to make sure that the image is loaded (using onload) before trying to make a thumbnail of it.

Okay, the way I can see this working is drawing the image to the canvas at a smaller size, then exporting the canvas. Say you want a 64px thumbnail:
var thumbSize = 64;
var canvas = document.getElementById("canvas");
canvas.width = thumbSize;
canvas.height = thumbSize;
var c = canvas.getContext("2d");
var img = new Image();
img.onload = function(e) {
c.drawImage(this, 0, 0, thumbSize, thumbSize);
document.getElementById("thumb").src = canvas.toDataURL("image/png");
};
img.src = fileDataURL;
With this code, an image element with the id "thumb" is used as the thumbnail element. fileDataURL is the data URL that you got from the file API.
More information on drawing images to the canvas: http://diveintohtml5.info/canvas.html#images
And on exporting canvas data: http://msdn.microsoft.com/en-us/library/ie/ff975241(v=vs.85).aspx

Related

Write svg latex into a canvas html

My goal is to record maths scripts running on the canvas and at the same time record sound from the mic (I am a math teacher). I would like very much to allow latex formulas. Of course latex formulas do not write directly to canvas. MathJax can produce SVG elements. I wonder if it is possible to go from SVG->image->canvas, using javascript. I don't care if the obtained image on canvas is a little blured.
I couldn't find good examples of this yet on the internet.
Thanks!
Indeed there is no Latex to canvas direct way.
You can however draw an SVG over a canvas. See this Q/A to see how to proceed from an SVG in the DOM (which MathJax should give you).
Indeed that's possible. The trick here is to grab the SVG output of MathJax and draw it to a temporary <img> element, which in-turn is drawn to an on-screen canvas afterwards.
The actual <svg> element is a children of the <mjx-container> element returned by a call to MathJax's tex2svg() method.
Here's an example:
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let equation = "x = \\sin \\left( \\frac{\\pi}{2} \\right)";
let svg = MathJax.tex2svg(equation).firstElementChild;
let img = document.createElement('img');
img.onload = (e) => {
let tempWidth = e.target.naturalWidth;
let tempHeight = e.target.naturalHeight;
ctx.drawImage(e.target, canvas.width / 2 - tempWidth / 2, canvas.height / 2 - tempHeight / 2, tempWidth, tempHeight)
}
img.src = 'data:image/svg+xml;base64,' + btoa('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n' + svg.outerHTML);
#canvas {
background-color: #eeeeee;
}
<script src="https://cdn.jsdelivr.net/npm/mathjax#3/es5/tex-svg.js" type="text/javascript"></script>
<canvas id="canvas"></canvas>

HTML Canvas imageSmoothingEnabled kills Draw Image in Chrome on Windows

We are using a canvas to draw an image, and require that the image is smoothed.
so we use context.imageSmoothingEnabled in the 2d Canvas context.
We notice that if we use a jpg and smoothing is true, then the image fails to scale correctly on some machines (mainly windows 64bit).
In addition, if smoothingQuality is set to 'low' (rather than medium or high) then it works, but of course, who wants low.
If you modify the code to point to a PNG file, it seems to work ok.
Here is the JS Code
// 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.clearRect(0, 0, canvas.width, canvas.height);
ctx.imageSmoothingQuality = "medium";
// set to true and the image fails to scale
ctx.imageSmoothingEnabled = true;
ctx.drawImage(img, 0, 0, 50, 50);
}
// Specify the src to load the image
img.src = "http://i.imgur.com/gwlPu.jpg";
body {
background: #CEF;
}
<canvas id="c" width="800" height="600"></canvas>
Thanks in advance.
I have tried it on a Win10 64bit, Win10 32Bit (64bitCPU) and Win10 32bit on Chrome Beta, & Canary
Can not repeat problems you mention.
The image format (jpeg,png) will not effect the result of any of the smoothing or quality settings (apart from source image quality).
What can make a difference, especially at small scales is the ratio of the scaled down image to the original. Ratios like 1/2 1/4 1/8th will produce far better results than 1/3 2/9 3/19th. When comparing images of different sizes you should compare at same scale ratio rather than same size (if original have different sizes)
Below I used your code and the image you linked to to draw the image at the same size you had. Along the top from left to right is smoothing true from quality high on left to low on right.
The second row is same but smoothing turned off.
Below that is the same but zoomed via copy of canvas and no smoothing to show more details of the differences the setting make (if any).
If as your question outlines this was reproducible it would be a major issue for chrome and would be quickly fixed. I would say it is something very specific, maybe all the graphics cards are the same type and there is a driver issue, or images are cached and some old bad version is appearing.
If you want more help the best you could do is provide some screen shots of the problems, showing the problem and the desired result. That way we can at least narrow it down somewhat.
var ctx = c.getContext('2d');
var img = new Image;
img.src = "http://i.imgur.com/gwlPu.jpg";
img.onload = function () {
ctx.imageSmoothingQuality = "high";
ctx.imageSmoothingEnabled = true;
ctx.drawImage(img, 0, 0,50,50);
ctx.imageSmoothingQuality = "medium";
ctx.drawImage(img, 60, 0,50,50);
ctx.imageSmoothingQuality = "low";
ctx.drawImage(img, 120, 0,50,50);
ctx.imageSmoothingQuality = "high";
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 60,50,50);
ctx.imageSmoothingQuality = "medium";
ctx.drawImage(img, 60, 60,50,50);
ctx.imageSmoothingQuality = "low";
ctx.drawImage(img, 120, 60,50,50);
ctx.imageSmoothingQuality = "low"; // turn off all filtering
ctx.imageSmoothingEnabled = false;
ctx.drawImage(c,0,0,170,110,0,120,680,440)
}
body {
background: #CEF;
}
<canvas id="c" width="800" height="600"></canvas>
Following content edited in by OP user2739963
Here is a screen shot of this not working on a machine (We have many of these).

SVG stroke width is messy on a html 5 canvas

I am trying to bind an SVG to a canvas. The SVG has a stroke width setup and it seems to be thicker than what it needs to be when bound to the canvas. What could be causing this and how to fix this?
The library that I use to bind svg to the html5 canvas is canvg
The JS fiddle below shows both the SVG and the bound svg on a canvas.
JS Fiddle: http://jsfiddle.net/fYAAf/111/
var image = new Image();
var canvas = document.createElement('canvas');
canvas.width =1090;
canvas.height = 1875;
var context = canvas.getContext('2d');
context.drawSvg(xml, 0, 0);
image.src = canvas.toDataURL();
According to the link: http://jsfiddle.net/fYAAf/111/
In the javascript code you are embedding the characteristic of SVG in a type tag (image). The result is something like this:

<img src="data:image/png;basQAACAnWQXByGjnghZGYT8......characteristic_of_SVG">
So you should try to put all the XML properties within an SVG tag, as it is written in the HTML document in the top of the example of jsFiddle.
In JavaScript something fast would:
var xml = "<svg> (Write here xml properties) <g><text (Write here text properties)><tspan dy="35" x="0">Test</tspan></text></g></svg>";
document.getElementById('container').innerHTML = xml;
<div id="container"></div>
I don't know what the cause of this behavior in img tags.

how to snapshot a part of HTML5 canvas?

I am drawing a full-window graph with the HTML5 canvas feature, and what I want to do is to define a small square of region inside this canvas, and snapshot that the part of region into certain format, like png, jpg or a base64 text.
First, create a new canvas in background with the width and height of the image you want to take:
var bgCanvas = document.createElement('canvas');
bgCanvas.width = 200;
bgCanvas.height = 150;
Then copy a part of the original canvas to the background canvas using context.drawImage. This example copies the 200x150 section starting at 400:500.
var bgContext = bgCanvas.getContext('2d');
bgContext.drawImage(mainCanvas, // source
400, 500, // source coordinates
200, 150, // source dimension
0, 0, // target coordinates
200, 150); // target dimensions
Now you just have to get the base64-encoded version of the bgCanvas as already explained in question "Getting binary (base64) data from HTML5 Canvas (readAsBinaryString)".

Eraser tool in html5 canvas

Hi i am building a windows store app with html5 and javascript in my app i am trying to implement an eraser tool but this is problematic because if the user moves an image or another layer to where they've previously erased, they see the white drawing where they erased.
i have been trying to do the eraser tool from different ways for example i have changed the default globalCompositeOperation to "destination-out" like this code
//Here is the error.
if (clickTool[j] == "eraser") {
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(255,0,0,0.5);';
ctx.strokeStyle = 'rgba(255,0,0,0.5);';
}
else {
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = clickColor[j];
}
but unfortunately it doesn´t work for me. i have uploaded all my code to this link:
My code
Please i would like to somebody could help me.
Thanks and i'm sorry for my speech , i'm mexican.
Use multiple layers. Have one canvas for the background image and another for the drawing; that why you never erase any of the background image.
If you need to, you can have multiple layers as they don't generally impact performance.
And of course if you can combine layers, say the last drawn squiggle to the background layer, if you deem a drawing to be "permanent".
Maintain a array of mid points. Use the globalCompositeOperation as 'destination-out' first and 'source-over' later to make a transparent eraser trail .
Following is the code that you need to use with a mouse move function
var handleMouseMove = function (event) {
midPt = new createjs.Point(oldPt.x + stage.mouseX>>1, oldPt.y+stage.mouseY>>1);
if(curTool.type=="eraser"){
var tempcanvas = document.getElementById('drawcanvas');
var tempctx=tempcanvas.getContext("2d");
tempctx.beginPath();
tempctx.globalCompositeOperation = "destination-out";
tempctx.arc(midPt.x, midPt.y, 20, 0, Math.PI * 2, false);
tempctx.fill();
tempctx.closePath();
tempctx.globalCompositeOperation = "source-over";
drawingCanvas.graphics.clear();
// keep updating the array for points
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
stage.addChild(drawingCanvas);
stage.update();
}
};
I use this code to make a eraser that behaves like pen and fills up transparent color instead of white