Rescale Image object on Canvas element while maintaining aspect ratio (iOS, Android) - javascript

I am trying to load a HTML file that does one thing: display an image on a canvas element that is auto-resized and auto-rescaled to the maximum dimensions for the device in question.
For example:
User presses button on device.
Device opens WebKit/WebView to http://some.url/page.html.
That page shows image.png in the maximum height/width proportion possible on said device.
Requirements:
Actual HTML file should only contain a canvas element within the body.
Image path should be dynamic and the width/height interpreted after the file has been loaded.
No third party dependencies.
I took a stab at this here, but am running into problems: http://jsfiddle.net/zfG2B/
if (scaledHeight < scaledWidth) {
_config.newImgHeight = _cache.canvas.height;
_config.newImgWidth = Math.round(_config.newImgHeight * _config.imgWidthRatio);
} else if (scaledWidth < scaledHeight) {
_config.newImgWidth = _cache.canvas.width;
_config.newImgHeight = Math.round(_config.newImgWidth * _config.imgHeightRatio);
}
The code I've cobbled together (above, and see jsfiddle) kind of works, but I can only get it to rescale based on the height. Any ideas on what I've done wrong or the best path forward?
For reference, I've attempted to join together the best of:
HTML5 Canvas Resize (Downscale) Image High Quality?
Scaling HTML5 canvas width preserving w/h aspect ratio
Resizing an image in an HTML5 canvas
HTML5 Canvas drawImage ratio bug iOS
scaling a canvas element and keeping the aspect ratio
So here's the question: what's the best way to place an Image on a Canvas in HTML5 and make it auto-rescale based on the current screen size? Bonus points for being able to specify a clipping range!

Related

Background image with filters not stretching to full width of canvas - fabric.js

I am using fabric.js.
I am loading a background image into canvas and the image is not streching.
If i upload just the image everything is good, when i add filters to background image, the background image not stretching to full width of the canvas.
I tried to add filters after loading the image.
Tried also remove background and load again, everything is going to the same place... Image not stretching.
This is a fiddle with only background image:
`https://jsfiddle.net/Music/6mcf4kj0/2/`
This is a fiddle with background image and filters:
`https://jsfiddle.net/Music/q30cfwL7/1/`
I expect the image to be full width and height of the canvas.
Your image is 3000x3000, which is too large for the default fabric.js settings. From the filter docs:
The picture will be painted over a tile of 2048x2048 size, bigger
pictures won't fit. fabric.textureSize set at 2408 is a safe limit.
Most of the hardware will support 4096 and so 4096x4096 is a limit
that will probably work and give you less headaches. Take in mind that
canvas has a max size too. If you are supporting browsers like IE11
you will have probably problems with canvases bigger than 5000 on a
size, whatever your webgl hardware is capable of.
Try this before applying the filter:
fabric.textureSize = 4096
You can also check if Webgl is supported then apply
if (fabric.isWebglSupported()) fabric.textureSize = 65536;

How to decide image upload quality in JS

I'm implementing a graphic related web app and I want to detect the image resolution and validate if the user is uploading an image with too low DPI
How can I achieve this?
Is there a library for this?
Is there a solution in HTML 5 canvas for this, or in Konvajs (HTML canvas library)
Is there any image up-loader that supports determining uploaded image resolution?
Most modern file uploaders will give you access to image dimensions, or you can use a filereader to load the image into a hidden dom image object and get the sizes that way. Example in this SO question.
But they will not tell you if the image is suitable for your intended use. You have to do some math yourself to decide that.
To decide if an image is going to be acceptable, we need to start with the target. We need to know the final output DPI and the measured dimensions. I will look at the width only but the same calculations work for the height too. Example DPI's, for a PC screen the DPI is 96, for a decent inkjet printer it might be up to 4800 by 1200. Commercial printing ranges from 300 to 2400.
Next we need to know the target region size - in other words a measurement. I will use inches here to keep things simple.
The calculation we need to do is:
Image size dots / (target size inches * DPI)
This produces the image scaling that is needed to fit the image in the target space. If the image dot size is twice the size of the target then the scale is 0.5, if the image dot size is 3 times the target then the scale is 3.
Next we need to know the acceptable range of scaling for the image. This is arbitrary and depends on the circumstances in hand.
Let's take an example - making a business card 3.5 ins x 2 ins where we want to put an uploaded picture on the back. We are printing at 300 DPI. The user uploads an image that is 800px wide. I will ignore aspect ratio to keep it simple.
The calculation we need to complete is -
Perfect image dot size would be: 3.5 ins x 300 DPI = 1050 dots.
Scaling of image to target = 800 / 1050 = 0.76
Assume acceptable scale range of 0.8x - 4x.
Conclusion: The image is not suitable because the scale from step 2 is outside the range defined in step 3.

Zooming canvas on mobile

I have a page where a user can upload a photo. Once uploaded they can move it in a canvas and they can crop the image that is over the canvas.
To crop it, I get the image coordinates relative to the canvas and i convert it with toDataURL.
On mobile devices I use zoom in CSS to scale the whole canvas to fit the viewport. I cannot do it in another way because besides the user's photo, the are other elements and various texts that are impossibile to scale to fit each resolution.
The problem is that when cropping on mobile, the position is not exactly the one the user chose, obviously because of the zoom property.
Here is a fiddle https://jsfiddle.net/g6e16xza/ simulating the mobile problem.
I tried working with ctx.scale() to match the css zoom but without any luck.
In the end I need the result image to be always a fixed dimension (500px × 325px), whether the user is uploading from desktop or mobile.
Any suggestions are greatly appreciated.
Thank you

Rendering html canvas images at high resolution

I'm looking to create a system where users create an image in canvas on their browser (with the help of paper.js or processing.js etc) and be able to print a large (up to A3, 300dpi ideally) size representation of what they have created in canvas.
Obviously exporting images straight from the canvas element in the users browser I'm limited to screen size and resolution etc.
So I've looked into the solution of momentarily scaling up the canvas element when the users saves and capturing the image data at the larger size. This could be a solution but I'm pretty sure file size would get out of hand pretty quickly at larger sizes.
I haven't used Node.js very much but was wondering if anyone with experience would know if Node could achieve this and if it would be a better solution and briefly how I'd go about it?
I see two ways to achieve what you want :
use an oversized canvas, that you scale with css.
For instance, you can have a 1000X1000 canvas, that you show within a 200pxX200px smaller view.
<canvas width=1000 height=1000
style = 'width:200px; height:200px;' id='cv'>
</canvas>
use a small canvas for display on screen, and really draw on a backing canvas, that you reproduce on the view canvas at each change.
Both solution cannot solve the issue that mouse coordinates are integer, so to implement a 'pixel perfect' location of object you'll have to implement some kind of zooming. Second solution might be simpler for this.
To retrieve the mouse coordinates, with css scaling do not forget to multiply them by the scale, and in case 2, by the scale you decided.
// formula to get the css scale :
var cssScaleX = canvas.width / canvas.offsetWidth;
var cssScaleY = canvas.height / canvas.offsetHeight;
// then mouse coords are to be multiplied by the scale :
// mouse.x *= cssScaleX;
I tried quickly both solutions, and i was quite surprised to see that css solution is very slow (in both Ch and FF), and it seems faster to copy a back canvas than to have css doing it.
Maybe it depends on some quality settings, but it seems solution 2 is both more flexible and faster.
first css version is here (move mouse to draw 10X10 rect) :
http://jsbin.com/kegohufu/1/
second back canvas + copy version is here (move mouse to draw 10X10 rect) :
http://jsbin.com/qomiqoqi/1/

How to prevent #2x image scaling within javascript on a retina iPad?

I'm developing a web game using html <canvas> and javascript. The game must also be functional on the iPad, preferably both retina and non-retina displays. In this game, I use a spritesheet png. This spritesheet is 3500 pixels wide and 3700 pixels high.
In the logic for my game, I'm using canvas' context.drawImage() to grab the sprites and draw them into my canvas. In a desktop browser, this works perfectly fine, and everything is great. On a retina iPad, the image loads at only a quarter of it's size, which makes many of my drawImage() calls fail, thinking they're trying to grab pixels outside the boundaries of the loaded image. (If I grab a sprite at location 1200, 1400, and the iPad thinks my image is smaller than that, an INDEX_SIZE_ERR error is thrown.)
For example, the code written below is what I have in my project. When alerting the width and the height, I get a result of 875 pixels wide by 925 pixels high - exactly 1/4th of the original image's size.
spritesheet = new Image();
spritesheet.onload = function() {
splashInterval = setInterval(renderFrame, 30);
alert(spritesheet.width); // returns 875 on retina iPad
alert(spritesheet.height); // returns 925 on retina iPad
};
spritesheet.src = "/spritesheet.png";
The normal solution to this for retina displays is to create an image that's increased in size so when the iPad downscales it, everything is fine. However, going by the sizes reported above, I would have to create an image that is 4x the size in width and height. That makes an image that would be 14,000 pixels wide by 14,800 pixels high. Even as a solid white jpg, this image fails to save in Photoshop, and is reported in Gimp to be 1.9GB big. Naturally this isn't a solution. ;)
Therefore my question stands: Is there a way to prevent the iPad retina display from downscaling images that are loaded through Javascript? When I load my 3500x3700 pixel image, I need it to stay at 3500x3700 pixels, so my context.drawImage() calls work as intended.
Any and all ideas would be appreciated. Thanks!
you can find whether the display is retinal or not using following :
var retina = window.devicePixelRatio > 1 ? true : false;
if (retina) {
// the user has a retina display
// do something
}
else {
// the user has a non-retina display
// do something else
}

Categories

Resources