Crop image to canvas - html

I have 2 divs
<div id="image-orig">
<img src="image_example.jpg"/>
</div>
<div id="image-crop">
<canvas id="preview" style="width:548px;height:387px"></canvas>
</div>
image_example.jpg can be image any size.
function updatePreview(c) {
if(parseInt(c.w) > 0) {
var orig = $("#image-orig img")[0];
var canvas = $("#image-crop canvas")[0];
var context = canvas.getContext("2d");
context.drawImage(orig,
c.x*coeff,c.y*coeff,c.w*coeff,c.h*coeff,
0,0,canvas.width,canvas.height
);
}
}
$(function(){
$('#image-orig img').Jcrop({
onSelect: updatePreview,
onChange: updatePreview,
aspectRatio : parseFloat($('#image-orig img').width()/$('#image-orig img').height())
});
});
coeff - it's coefficient if size image larger div preview.
That's problem:
http://dbwap.ru/3725988.png
In second div (canvas). Quality image very low.
SOLUTION IS FOUND
canvas.width = c.w*coeff;
canvas.height = c.h*coeff;
context.drawImage(orig,
c.x*coeff,c.y*coeff,c.w*coeff,c.h*coeff,
0,0,c.w*coeff,c.h*coeff
);
$(that.el).find("#ImageCode").attr('src', canvas.toDataURL());
$(that.el).find("#ImageCode").show();
I'm just creating image tag and copying from canvas to image.

If you have access to .net, you can modify the way your new images are saved with JCrop:
http://mironabramson.com/blog/post/2009/04/Cropping-image-using-jQuery,-Jcrop-and-ASPNET.aspx
Solution available to you without using server-side (.net / php):
First, make sure that when you use JCrop that you have html5 canvas image smoothing enabled:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html
If that is already set, or has no effect, then I think your only other options to investigate image option available to you through each browser:
Enable smoothing in Mozilla - See this article as an example (look for 'mozImageSmoothingEnabled'):https://developer.mozilla.org/en/Canvas_tutorial/Using_images#Controlling_image_scaling_behavior
Apply filters in IE: http://code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/
Note: There may be some sort of Flash solution that could work but it would probably be too difficult to combine any Flash solution with JCrop and html5 canvas.

Related

iOS - Safari - images not rendering fully / cut off

We are loading images in a popup, via an Ajax request, and they intermittently only partially render.
I've basically removed any weird Javascript/nonsense other than the core flow - just a basic HTML image, and it is still happening - only on iOS.
Once you 'rotate' the device, the image renders correctly - so, it's not a weird div floating above or anything (I can select the image in iOS debugger mode when attached to a Mac)
Any help would be most appreciated.
Setting decoding="sync" on the img tag didn't help in my case where a lot of images are loaded simultaneously. Loading the image manually before did the trick though.
const imageLoader = new Image();
imageLoader.src = url;
imageLoader.decoding = 'sync';
imageLoader.onload = () => {
// allow drawing image
};
For anyone who stumbles across this and is working in a react environment
const [didLoadMainImage, setDidLoadMainImage] = useState(false);
useMemo(() => {
setDidLoadMainImage(false);
const imageLoader = new Image();
imageLoader.src = url;
imageLoader.decoding = 'sync';
imageLoader.onload = () => {
setDidLoadMainImage(true);
};
}, [url]);
return (
<div>
{didLoadMainImage ? (
<img src={url} />
) : null}
</div>
);
It seems this is an issue within the iOS image decoder - some kind of race condition.
This has been fixed by forcing the decoder to operate on the main thread, using:
<img decoding="sync" src="#Url" />
Hopefully this helps someone else!
In my case, the solution was to decrease the size of the images I was displaying. Our images were about 10x the size of the HTML element they were displayed in.
Apple's developer document states:

Is it possible to dictate to a browser the order of the images it downloads ?

Ive got a fullscreen image slide with about 20 images each c. 250kb. That is quite allot to download and because i want each image to be seen in order Ive set the slider not to start until the first 4 images are downloaded. The only issue is that when run in a browser (chrome latest version) it seems to download all images at the same time meaning that the first 4 images finish loading about the same time as the other 20.
Is there a way i can tell the browser to download them in cronalogical order ie. if my html is like this :
<div id="slider">
<img src="one.jpg">
<img src="two.jpg">
<img src="three.jpg">
<img src="four.jpg">
<img src="five.jpg">
<img src="six.jpg">
...
</div>
Start on one.jpg wait until complete then start on two.jpeg etc ?
You can use the img onload property in javascript.
var firstImage = new Image();
firstImage.src = 'some url';
firstImage.onload = function(){
var secondImage = new Image();
secondImage.src = 'some url';
secondImage.onload = function(){
//etc
}
}
obviously doing those calls with a recursive function would be the actual implementation, but I wanted to make sure you saw the core concept.

Chart.js canvas resize

In (Android WebView HTML5 canvas error) i posted a question regarding plotting graphs using Graph.js library.
The problem i have now is that if i call the function to plot the graph multiple times, the canvas resizes every time. Each time the graph is redrawn to the same canvas, its size also changes.
I also tried setting the size of the canvas but without success.
What could be the reason? Why does the canvas resize every time?
I had a lot of problems with that, because after all of that my line graphic looked terrible when mouse hovering and I found a simpler way to do it, hope it will help :)
Use these Chart.js options:
// Boolean - whether or not the chart should be responsive and resize when the browser does.
responsive: true,
// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
maintainAspectRatio: false,
What's happening is Chart.js multiplies the size of the canvas when it is called then attempts to scale it back down using CSS, the purpose being to provide higher resolution graphs for high-dpi devices.
The problem is it doesn't realize it has already done this, so when called successive times, it multiplies the already (doubled or whatever) size AGAIN until things start to break. (What's actually happening is it is checking whether it should add more pixels to the canvas by changing the DOM attribute for width and height, if it should, multiplying it by some factor, usually 2, then changing that, and then changing the css style attribute to maintain the same size on the page.)
For example, when you run it once and your canvas width and height are set to 300, it sets them to 600, then changes the style attribute to 300... but if you run it again, it sees that the DOM width and height are 600 (check the other answer to this question to see why) and then sets it to 1200 and the css width and height to 600.
Not the most elegant solution, but I solved this problem while maintaining the enhanced resolution for retina devices by simply setting the width and height of the canvas manually before each successive call to Chart.js
var ctx = document.getElementById("canvas").getContext("2d");
ctx.canvas.width = 300;
ctx.canvas.height = 300;
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);
This works for me:
<body>
<form>
[...]
<div style="position:absolute; top:60px; left:10px; width:500px; height:500px;">
<canvas id="cv_values"></canvas>
<script type="text/javascript">
var indicatedValueData = {
labels: ["1", "2", "3"],
datasets: [
{
[...]
};
var cv_values = document.getElementById("cv_values").getContext("2d");
var myChart = new Chart(cv_values, { type: "line", data: indicatedValueData });
</script>
</div>
</form>
</body>
The essential fact is that we have to set the size of the canvas in the div-tag.
In IOS and Android the browser hides the toolbar when you are scrolling, thereby changing the size of the window which inturn lead chartjs to resize the graph.
The solution is to maintain the aspect ratio.
var options = {
responsive: true,
maintainAspectRatio: true
}
This should solve your problem.
I had to use a combination of multiple answers here with some minor tweaks.
First, it is necessary that you wrap the canvas element within a block-level container. I say to you, do not let the canvas element have any siblings; let it be a lonely child, for it is stubborn and spoiled. (The wrapper may not need any sizing restrictions placed on it, but for safety it may be good to have a max-height applied to it.)
After assuring that the previous conditions are met, when initiating the chart, make sure the following options are used:
var options = {
"responsive": true,
"maintainAspectRatio": false
}
If you want to adjust the height of the chart, do so at the canvas element level.
<canvas height="500"></canvas>
Do not try to deal with the child in any other manner. This should result in a satisfyingly, properly laid-out chart, one that stays in its crib peacefully.
As jcmiller11 suggested, setting the width and height helps.
A slightly nicer solution is to retrieve the width and height of the canvas before drawing the chart.
Then using those numbers for setting the chart on each subsequent re-draw of the chart.
This makes sure there are no constants in the javascript code.
ctx.canvas.originalwidth = ctx.canvas.width;
ctx.canvas.originalheight = ctx.canvas.height;
function drawchart() {
ctx.canvas.width = ctx.canvas.originalwidth;
ctx.canvas.height = ctx.canvas.originalheight;
var chartctx = new Chart(ctx);
myNewBarChart = chartctx.Bar(data, chartSettings);
}
I had a similar problem and found your answer.. I eventually came to a solution.
It looks like the source of Chart.js has the following(presumably because it is not supposed to re-render and entirely different graph in the same canvas):
//High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
if (window.devicePixelRatio) {
context.canvas.style.width = width + "px";
context.canvas.style.height = height + "px";
context.canvas.height = height * window.devicePixelRatio;
context.canvas.width = width * window.devicePixelRatio;
context.scale(window.devicePixelRatio, window.devicePixelRatio);
}
This is fine if it is called once, but when you redraw multiple times you end up changing the size of the canvas DOM element multiple times causing re-size.
Hope that helps!
I was having the same problem. I was able to solve it by setting option:
responsive: false,
maintainAspectRatio: true,
showScale: false,
And in css, set the width of the container div the same as the canvas:
#canvasContainer {
width: 300px;
}
canvas {
width: 300px;
}
If anyone is having problems, I found a solution that doesn't involve sacrificing responsiveness etc.
Simply wrap your canvas in a div container (no styling) and reset the contents of the div to an empty canvas with ID before calling the Chart constructor.
Example:
HTML:
<div id="chartContainer">
<canvas id="myChart"></canvas>
</div>
JS:
$("#chartContainer").html('<canvas id="myChart"></canvas>');
//call new Chart() as usual
I tried to Resize Canvas using jQuery but it din't work well. I think CSS3 is the best option you can try on, if you want on hover zooming at certain level.
Following hover option from other codepan link:
.style_prevu_kit:hover{
z-index: 2;
-webkit-transition: all 200ms ease-in;
-webkit-transform: scale(1.5);
-ms-transition: all 200ms ease-in;
-ms-transform: scale(1.5);
-moz-transition: all 200ms ease-in;
-moz-transform: scale(1.5);
transition: all 200ms ease-in;
transform: scale(1.5);
}
Follow my codepan link:
https://codepen.io/hitman0775/pen/XZZzqN
Here is the official dokumentation: https://www.chartjs.org/docs/latest/general/responsive.html
Detecting when the canvas size changes can not be done directly from the canvas element. Chart.js uses its parent container to update the canvas render and display sizes. However, this method requires the container to be relatively positioned and dedicated to the chart canvas only. Responsiveness can then be achieved by setting relative values for the container size (example):
<div class="chart-container" style="position: relative; height:40vh; width:80vw">
<canvas id="chart"></canvas>
</div>
I had the same kind of scaling issue's using Angular CLI. Was able to get it working by removing this line from the index.html:
<script src="node_modules/chart.js/dist/Chart.bundle.min.js"></script>
and then in the angular-cli.json file, in the scripts section, using this:
"scripts": ["../node_modules/chart.js/dist/Chart.bundle.min.js"]
Source: mikebarr58
I tried multiple answers on this thread and what worked for me was that (Note I am using reactjs), checking my previous props passed into the chart component.
When I was resizing my DOM, the chart was getting re-drawn with empty data.
componentDidUpdate(prevProps: ChartProps) { if(prevProps.data !== props.data) renderChart(); }
The accepted - responsive:true, maintainAspectRatio:false - did not work for my scenario.
But I found we can simply call the update method on the chart.
So I found myself tweaking values inside matchMedia listeners .. like so:
myRadarChart.options.scales.r.pointLabels.font.size = "1rem";
myRadarChart.update();
For me it is working with max-height:none (chart.js v3.9.1 and ng2-charts v3.1.2):
<div *ngIf="shartData">
<canvas style="max-height:none" baseChart [type]="'pie'"
[data]="shartData"
[options]="chartOptions">
</canvas>
</div>
Without max-height the chart height becomes "1".
The same is relevant when using chart.js directly without ng2-charts:
<div *ngIf="shartData">
<canvas style="max-height:none" id="chartID">
</canvas>
</div>
let ctx = <HTMLCanvasElement>document.getElementById("chartID");
let chart = new Chart(ctx, {
type: 'pie',
data: shartData,
options: chartOptions
});
Add div and it will solve the problem
<div style="position:absolute; top:50px; left:10px; width:500px; height:500px;"></div>
let canvasBox = ReactDOM.findDOMNode(this.refs.canvasBox);
let width = canvasBox.clientWidth;
let height = canvasBox.clientHeight;
let charts = ReactDOM.findDOMNode(this.refs.charts);
let ctx = charts.getContext('2d');
ctx.canvas.width = width;
ctx.canvas.height = height;
this.myChart = new Chart(ctx);

whats the difference between html2canvas and rasterizehtml.js

Apparently there are solutions to capturing screenshot of a web page:
Snapabug works by using an applet
GrabzIt I guess this is done on the server side.
Webkit2png is a command line tool, so not really part of the browser code.
There are probably other solutions that use ActiveX.
But I am interested in a Javascript only solution. From what I understand, both html2canvas and rasterizeHTML.js allow to convert html (in a web page) to an image. So, in what way is the implementation of html2canvas vs rasterizehtml.js different ? From what I understand both of them seem to use Canvas to generate the result. So in what way are they different? Which one is better ?
The main difference is that Rasterize is a wrapper around SVG foreignObject and html2canvas is essentially a reimplementation of browser HTML rendering from scratch. There are a lot of security headaches that Rasterize has to handle, but I think that its approach is better, as suggested by its being only 950 lines of code to html2canvas's 2400.
If the HTML you're rendering isn't very complex or doesn't need to be pixel-perfect, you may be able to skip Rasterize and use foreignObject directly, as described in MDN: Drawing DOM objects into a canvas:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
'<foreignObject width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
'<em>I</em> like <span style="color:white; text-shadow:0 0 2px blue;">cheese</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
I tried html2canvas.js and rasterizeHTML.js for visualisation of a piece of html. Both have some issues, though. html2canvas.js can't get through with elements which have transformation (For example, text with css scale transform). As long as, I can't make rasterizeHTML.js to draw a canvas inside the canvas which displays the html.

Hiding the toolbars surrounding an embedded pdf?

Though I think the answer maybe in this other question's answer concerning the pdf specification, is it possible to not display the adobe acrobat toolbars in an embedded pdf document?
If you use any browser besides Firefox browser, then the following code will embed a PDF file without any toolbars:
<embed
src="http://URL_TO_PDF.com/pdf.pdf#toolbar=0&navpanes=0&scrollbar=0"
width="425" height="425" />
Please note that this does not work on Firefox
See the Web Designer's Guide blog post for details.
See the full list of embedded tag parameters for more information.
You can use #toolbar to hide above toolbar.. if toolbar =0, it will disable it.. when toolbar=1, this will enable it.. hope so it will work. this works for me
<embed src="filename.pdf#toolbar=0" width="500" height="375"> (Disable toolbar)
<embed src="path/filename.pdf#toolbar=1" width="500" height="375"> (Enable toolbar
There is no guarantee that using #toolbar=0 in the URL will work, as this is exclusive to browsers that use the Adobe viewer, it may be that other viewers even have similar parameters to maintain compatibility, but certainly not everyone follows that, such as browsers for MacOS browsers or Linux.
In most browsers it is possible to change the view, which also probably will not work with #toolbar=0, because the viewer is something apart from the browser, for example Firefox has its own viewer internally and that does not work with this #toolbar=0, see the result of:
<iframe
src="sample.pdf#toolbar=0"
width="900"
height="200"
></iframe>
<br>
<embed type="application/pdf"
src="sample.pdf#toolbar=0"
width="900"
height="200"
>
And even if it works in Firefox as well as Chrome with extensions, it is possible to change the PDF viewer to anything else that may not support this parameter.
Even if you can remove all the buttons you want, you can still copy your PDF, or images, because everything is downloaded to your computer before rendering, the user can simply press F12 to open DevTools (Chrome / Firefox), look the network tab and filter it to get all PDFs loaded on the current page and by DevTools it will copy the PDF to any folder of it.
There is no way to stop, it is only possible to hinder. As already seen neither "iframe" nor "embed" will solve, I suggest (it's just a suggestion) use PDF.js.
So you can create your own buttons, navigation and the like and everything will run in <canvas>, example:
var url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf';
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 1.5,
canvas = document.getElementById('pdf-example'),
ctx = canvas.getContext('2d');
function renderPage(num) {
pageRendering = true;
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
document.getElementById('page_num').textContent = num;
}
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
/**
* show previous page
*/
function onPrevPage() {
if (pageNum > 1) {
pageNum--;
queueRenderPage(pageNum);
}
}
document.getElementById('prev').addEventListener('click', onPrevPage);
/**
* show next page
*/
function onNextPage() {
if (pageNum < pdfDoc.numPages) {
pageNum++;
queueRenderPage(pageNum);
}
}
document.getElementById('next').addEventListener('click', onNextPage);
/**
* PDF async "download".
*/
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
//Set loaded PDF to main pdfDoc variable
pdfDoc = pdfDoc_;
//Show number of pages in document
document.getElementById('page_count').textContent = pdfDoc.numPages;
renderPage(pageNum);
});
#pdf-example {
border: 1px solid black;
}
<script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>
<div>
<button id="prev">Previous page</button>
<button id="next">Next page</button>
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
</div>
<canvas id="pdf-example"></canvas>
Note that I used 1.5 to scale:
scale = 1.5,
...
var viewport = page.getViewport({scale: scale});
You can change this as needed. I recommend that you adjust it according to the view-port measurement (you can use window.innerWidth to calculate), but also make a minimum measurement, so it will be adaptive to different resolutions.
This works for me for hiding the pdf print view in react application
<iframe src={`${resumeUrl}#toolbar=0`} width="100%" height={500} />