This question already has an answer here:
Html5 Canvas resize
(1 answer)
Closed 5 years ago.
I'm implementing image upload, but before that, I want to do some resizing based on limits (eg. max-width, max-height, max-area). Problem is not resize image, but filesize.
I already gave up with quality, there was no visible differences in results gained from: Canvas, Pica, Hermite, so i decided to go with offscreen canvas.
Filesize is much bigger problem, eg.: if I have PNG image, that is 345x518 (54.2kB) and I want it to fit into area 512x512, after resizing it into 341x512 jpeg (same aspect ratio), filesize became 171.7kB.
Resize function:
function _canvasImageGet(original, dims) {
var canvas = document.createElement("canvas");
canvas.width = dims.w;
canvas.height = dims.h;
canvas.getContext("2d").drawImage(original, 0, 0, canvas.width, canvas.height);
return canvas;
}
Is there any way, how can I get smaller or same filesize after resizing? It doesn't have to be using Canvas, but I will appreciate, if resizing will be on client. Thanks for all anwers.
Canvas and other libraries I have used are not using compression so after resizing, output file is naturally bigger than it was before. I have found exactly what I needed. image-compressor does resizing and compression and all it's done on client-side. There is another library JIC, but it can't do resizing.
Related
I have the following code:
https://jsfiddle.net/8o3sn9mh/17/
<canvas id='c' style='position:absolute; left:0px; top:0px;'>
</canvas>
<script>
var
canvas = document.getElementById('c'),
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var flower = new Image();
flower.src = "http://plainicon.com/dboard/userprod/2803_dd580/prod_thumb/plainicon.com-46129-128px-af2.png"
flower.onload = function(){
ctx.drawImage(flower,0,0,128,128, 0, 0, 30, 30);
ctx.drawImage(flower,0,0,128,128, 0, 0, 218, 218);
</script>
Short story: as you can see the flower doesn't resize well, it's quality is lost.
Long story:
I am making a game with shapes. basically, I use image with ratios such as 128-128 or 80-80 since its designed for phones, and I make sure when I resize the images to keep that 1:1 ratio. With calculations based on the user's window, I decide how much to resize the images proportionally since the canvas is on full screen. It works decent on some screen but on some it doesn't - the images can downscale too much and look poor or upscale too much and look unclear. it is most noticeable on triangle images(I know I can draw pure shapes with canvas but I need to draw faces on them so it is impossible). Any good method to do nicely?
That is the nature of pixel based images.
When downscaling try to keep the image sizes whole ratios, it will improve the quality.
Eg you have 128, then you reduce it to 30, that means pixels are reduced by 128/30 = 4.2666. Pixels are discrete units of information and can not easily be cut into smaller units without loss of quality.
If you changed the size to 32 pixels 128/32 = 4 you get better quality because you are not cutting up any pixels.
For upscaling there is little you can do, Its either blurry or pixelated. Your source images should always be at a higher resolution than you need. Rule of thumb is "only downscale".
If the quality of the images downscaled with whole ratios is not to your liking then the best option is do the scaling in production on photoshop (or the like), then let the device select which images to download. This will give you the best possible quality for all devices and save you and the users some bandwidth (for smaller res devices)
When I first started this project that I'm working on, my canvas size with 1400px wide and 480px tall. I realized that I am going to need to make the canvas the same size as the window itself later, so I did that and everything inside of the canvas zoomed in or something. I set a drawImage(); to be 300 px wide and 180 px tall, and it is a LOT bigger than that, the image is actually the same width as the canvas now. Any suggestions? Here's the link to the project:
http://brycemckenney.com/animation-app
Thank you guys!
You have set the dimensions through css, instead of the physical dimensions of the (image) canvas.
The relevant piece (for others to read in the future) of your code is:
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
var windowHeight = $(window).height();
var windowWidth = $(window).width();
$(canvas).css({
height: windowHeight - 8,
width: windowWidth - 8
});
Think of it like this: suppose you have a normal jpg-image.
That jpg has it's own 'physical' dimensions (aka width and height).
In both HTML and CSS you can set the dimensions (in px, percent, etc) that you'd like the browser to render (scale) the picture (hey, the picture already has a immutable size right?).
Now for canvas:
In order for canvas to have a physical width/height, you have to set the .width and .height of the canvas-element itself, either in HTML or per javascript (a side-effect is that setting the physical dimensions is that the canvas will clear itself, as per spec).
Then to scale the image (like you did with the above jpg example) you use css (again in px/percent/etc).
I think this is a clever solution by the way to add that new canvas-element to the HTML-Spec!
So, rounding up:
A canvas with a width and a height of 300 px rendered as 100% of a container (like document.body) that measures 900x900px will be scaled-up 3 times!
The reverse (scaling down) will let you draw even more crisp lines by the way!
Hope this helps your understanding!
This question already has answers here:
Canvas width and height in HTML5
(3 answers)
Closed 8 years ago.
The application lets user save the designs and post it so other users can view it later.
The original canvas saved with the proportions of width=700 and height=600. But when displaying the canvas, I want to resize the canvas to fit into dimensions of (350,300). half of the original. But if I directly apply those dimensions and load width setWidth() and setHeight() it loads with original proportions.
All I want is to display the canvas with new dimensions.
If you are using the library fabric.js, that's not enough.
Considering that 'canvas' is the fabric.js instance object, you should do this to avoid distorsion artifacts:
canvas.setWidth( <desired width> );
canvas.setHeight( <desired height> );
canvas.calcOffset();
Previously answered here.
I'm not sure what you've been trying, but
var canvas = document.getElementsByTagName('canvas')[0];
canvas.width = 800;
canvas.height = 600;
should work fine.
I have been unsuccessfully trying to find documentation that details the limitations regarding the Html5 Canvas Element such as what is the largest image file size it can load etc. The reason I ask is that I have been trying to resize image sizes ranging from 50kb to 2.0mb through ctx.scale(), yet it has been horribly inconsistent in that for the same image sometimes ctx.drawImage() will be successful and other times unsuccessful (unsuccessful being no re-scaled image appears in the canvas).
I have also placed console.log(base64) to monitor the result of var base64 = canvas.toDataURL() and have noticed that when successfully resized the resized base64 will be quite a long string as expected and when unsuccessfully resized a string will still appear yet be relatively short and outputs a blank image.
Does this have something to do with memory limitations and the unsuccessful strings wrapping around themselves? If so, what are the memory limitations imposed on the canvas element?
First:
Hard limitations would depend on the browser, not the canvas API.
Even then, browsers are always trying to improve that performance, so that number would always be changing.
But with WebGL and Canvas being used to make games, texture atlases / sprite atlases are HUGE .jpg/.png files.
Chances are very, very good that your images are smaller, and I've frequently used 4MB/5MB/16MB images in canvas for demonstrations.
A huge image (or dozens of them) might crash the tab, if it's big enough, but until that time, canvas hasn't really complained to me.
Second:
There are security-limitations.
Editing photos in canvas comes down to what browser you're on, and whether the file is on the same domain as your website or not.
Third:
When you say that "large files don't work, but they do sometimes..."
...that leads me to believe that your image-loading method is faulty.
If you do something like this:
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = "//mydomain.com/myimg.png";
context.drawImage(img, 0, 0, img.width, img.height);
...or anything else which isn't either event-based or callback-based,
then your problem has nothing to do with canvas and has everything to do with callbacks, and that you're trying to draw the image to the canvas before the image is done loading.
If your browser has already cached a copy of the large image, or if a small image only takes a fraction of a second to download, then there's no problem.
If you try downloading an 18MB image, and draw it to the canvas as soon as you set the url for the image, then you're going to get a blank screen, because it hasn't finished loading.
Instead, you need to wait for the image to finish loading, and then draw it to the canvas when it's ready.
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
image = new Image();
image.onload = function () {
var img = this,
width = img.width,
height = img.height;
canvas.width = width;
canvas.height = height;
context.drawImage(img, 0, 0, width, height);
document.body.appendChild(canvas);
};
image.src = "//mydomain.com/path-to-really-huge-image.png";
Now it could be a 16MP image. Nothing will happen until the file is done loading.
Then, the onload event fires, and does the rest of the setup.
You could make it more abstract, and turn it into a nifty program, but it feels like this is the key piece you might be missing.
I have an iPad 2 canvas app (game) and would like to get it to run on the new iPad retina display.
Simply put, what is the best method to stretch/shrink my iPad2 image for retina iPad models?
From the googling I've done, I've seen various methods but many include starting with retina sized images and scaling done.
I've also heard the performance of pushing retina quality sized pixels to the screen is slow, and that it is better to use iPad size images at the expense of some quality.
As it is right now, on the new iPad I see the top left quarter of my app, which makes sense, but performance is shocking compared to iPad 2.
Techniques I've seen include CSS media queries, using the pixel density, and CSS transforms - which are apparently quite fast.
Thanks
I've put together a simple function to handle this problem. Basically, it takes the current canvas size and scales it by the device-pixel-ratio, shrinking it back down using CSS. It then scales the context by the ratio so all your original functions work as usual.
You can give it a shot and see how performance fares. If it isn't what you hoped for, you can just remove it.
function enhanceContext(canvas, context) {
var ratio = window.devicePixelRatio || 1,
width = canvas.width,
height = canvas.height;
if (ratio > 1) {
canvas.width = width * ratio;
canvas.height = height * ratio;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
context.scale(ratio, ratio);
}
}