I have an image with height=75pixels and width=75pixels (75x75).
I want to calculate what the resolution for this image would be in different resolutions [480p (640x480), 720p (1280x720), and 1080p (1920x1080)] while still keeping the image's original aspect ratio.
For example, I know if I keep multiplying by 2 that eventually I will reach a number for each resolution like so:
75x75 * 2 = 144x144
144x144 * 2 = 288x288
288x288 * 2 = 576x576
576x576 * 2 = 1152x1152 (This resolution would be just over 480p)
1152x1152 * 2 = 2304x2304 (This resolution would be over 720/1080p)
How can I calculate different resolutions for an image while keeping the original aspect ratio?
Related
Is there a reliable equation to work out pixel size to MM? Or is that not possible cross device?
We are working with a bespoke system that delivers content to many devices with different screen sizes, it can detect the screen width in MM, but we would like to accurately convert this to pixel size to deliver correctly sized images dynamically using a simple jquery script!?
Any ideas?
Cheers
Paul
What i did :
<div id="my_mm" style="height:100mm;display:none"></div>
Then:
var pxTomm = function(px){
return Math.floor(px/($('#my_mm').height()/100)); //JQuery returns sizes in PX
};
tl;dr: If you don't know the DPI of the device, you won't be able to deduce how big the pixel is in the real-world.
Pixels on their own are not real-world units of measurement.
They can become a real-world measurement if you take into account the DPI value of the device that displays them.
The formula is:
mm = ( pixels * 25.4 ) / DPI
So 8 pixels viewed on a 96-DPI screen setting:
( 8 * 25.4 ) / 96 = 2.116mm
All this assuming the device is not scaled/zoomed.
old post but I stumbled upon this today and had to make it work.
the trick is to create an element with dimensions styled in inches and request its width, this will give you the px per inch.
function inch2px(inches) {
$("body").append("<div id='inch2px' style='width:1in;height:1in;display:hidden;'></div>");
var pixels = $("#inch2px").width();
$("#inch2px").remove();
return inches * pixels;
}
function px2inch(px) {
$("body").append("<div id='inch2px' style='width:1in;height:1in;display:hidden;'></div>");
var pixels = $("#inch2px").width();
$("#inch2px").remove();
return px / pixels;
}
now if you need millimetres, just do px2inch(10)*25.4.
You would need to know the DPI of the device and if the display is scaled or not. That would mean that you would have to have a database of the physical screen dimensions and screen resolutions of each device.
No need for jQuery.
function xToPx(x) {
var div = document.createElement('div');
div.style.display = 'block';
div.style.height = x;
document.body.appendChild(div);
var px = parseFloat(window.getComputedStyle(div, null).height);
div.parentNode.removeChild(div);
return px;
}
pixels = xToPx('10cm'); // convert 10cm to pixels
pixels = xToPx('10mm'); // convert 10mm to pixels
Please notice that values in pixels are depending on what resolution the browser of the device tells you. Some browsers (on some phones) lie about this and tell you something different than the actual screen resolution in an attempt to be compatible with older sites. Main important thing is to never port conversion values from one device to another but always use real-time calculations. Even on a desktop the user can change the screen resolution.
To learn more about the units, check out this (short) article on W3:
https://www.w3.org/Style/Examples/007/units.en.html
i use this simple function
function pix2mm(val,dpi){
return (val/0.0393701)/dpi;
}
test outputs it 300,600,900 DPI
var r = pix2mm(100,300); // converting 100 pixels it 300 DPI
console.log(r); // output : 8.4 mm
var r1 = pix2mm(100,600); // converting 100 pixels it 600 DPI
console.log(r1); // output : 4.2 mm
var r2 = pix2mm(100,900); // converting 100 pixels it 900 DPI
console.log(r2); // output : 2.8 mm
DEMO : https://jsfiddle.net/xpvt214o/29044/
You cannot reliably calculate this since there is no way to detect physical screen size.
Based on the #Dawa answer above, this is my solution:
var mmToPx = function(mm) {
var div = document.createElement('div');
div.style.display = 'block';
div.style.height = '100mm';
document.body.appendChild(div);
var convert = div.offsetHeight * mm / 100;
div.parentNode.removeChild(div);
return convert;
};
Just note that the 100mm height, will give you a better precision factor.
The calculation will be instant and the div will not be visible. No need for jQuery
Late but may be useful.
1 px = 0.26458333333719 mm
Milli Meter Pixel
1 mm = 3.779527559 px
So if you have lets say 10px. It will be equal to 10 * 0.26458.. = 2.64mm
ref : https://everythingfonts.com/font/tools/units/px-to-mm
Enjoy :)
I am having trouble converting pixels to metres on my game
how many pixels is a meter in Box2D?
Is an example of my problem, but does not solve it.
This is because this solution, while it works, will not go cross browser, that is, if the conversion rate is something constant like 50px to one meter, than on a device with 400x800 resolution, the objects will appear big, whereas on another device with 4000x8000 resolution (exagurated) the objects will be tiny.
I can understand some solutions to this, but the main reason why I am finding this so hard to implement is because one browser or phone might be 16:9 ratio, whereas another might be 14:7, and these differing ratio's are the kicker, since my entire game is held on the screen as it is not a scrolling game, it is just a simple physics game.
Because of this I understand that It is easier to have to world be a smaller size, and convert it back up when rendering, but these problems that I have mentioned have stumped me, and I was wandering if anyone had any feasible solutions.
Since your
entire game is held on the screen
I suggest you the following:
Decide how many "meters" you need your window width to be. Say you've decided:
any window width (W) is always N "meters"
Then k = W/N where k is a scaling multiplier meaning a part of window width within 1 "meter".
So if W = 400px and N = 100m you have k = 400px/100m = 4px/m.
And when other screen is W = 4000px you have k = 40px/m.
That way you can translate your "meters" to pixels by multiplying your dimensions in "meters" by k and your objects will be always scaled to the screen size.
In JavaScript it looks like:
var N = 100; // window width in "meters"
var k = window.innerWidth / N; // px in 1m
// let's count something simple
var U = 10; // speed in meters per second
var t = 10; // time in seconds
var S = U * t; // distance in meters
var S_px = S * k; // distance in pixels (scaled to the window width)
I have a FabricJS canvas that has to be converted to a PDF that matches the exact fractional inches for print production. Per other questions I have received, my printer is a large format printer and actually needs this/is capable to printing to the exact decimal as follows:
Width (Inches): 38.703111
Height (Inches): 25.999987
Since the requirements are a DPI of 300, I obtained the pixels by multiplying the width and height x 300 as follows:
38.703111 inches x 300 = 11610.9333 px
25.999987 inches x 300 = 7799.9961 px
With these measurements in hand, I created a FabricJS canvas that users could edit and then convert to an image (will need to figure out how to convert it to a PDF server side later/suspecting node.js with the pdfkit module).
Since it is not usable to have a 11610 x 7799px Canvas on a page, I set the size of the canvas as follows:
Width: 650px
Height: 436.6571863 (Orginal Height * New Width / Orginal Width = new height)
Here is what my Canvas looks like (HTML) and corresponding JavaScript code to render it:
<canvas id="c" width="650" height="436.6571863" style="border:1px solid"></canvas>
var canvas = new fabric.Canvas('c', {});
Users are able to edit the canvas and then convert it to an image, but this is the problem occurs. I attempt to scale the canvas via FabricJS' toDataURL method using a multiplier of 17.86297431 (Original Width in Pixels / New Width in Pixels and Original Height in Pixels / New Height in Pixels both equal a multiplier of 17.86297431) as follows:
var dataURL = canvas.toDataURL({
format: 'png',
multiplier: 17.86297431
})
document.write('<img src="' + dataURL + '"/>');
However, once it scales, the width of my outputted image appears correct at 11610, but the height is off at 7788 when it should be 7799. This output does not show fractions, but rather just the whole pixels when I inspect the element.
My question is, how can I get my FabricJS Canvas to properly scale up to the pixels (or inches) so I can have my PDF (converted from my PNG) in the correct dimensions? Is this an issue with pixel fractions not being respected/what can I do about this?
You need to set NUM_FRACTION_DIGITS in fabric.js file
By default this value = 2, you can change it and set for example = 9
Now your multiplier = 9,0123456;
But for Fabric JS your multiplier = 9,012;
If your will set NUM_FRACTION_DIGITS = 9 you will get your multiplier = 9,0123456;
Here the proof link: http://fabricjs.com/docs/fabric.Object.html
That is what you need: NUM_FRACTION_DIGITS - Defines the number of fraction digits to use when serializing object values. You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.
You should not work with float dimensions, that is a bad idea. Why don't you use Math.ceil for your dimensions. This will make no visual difference and this is the approach usually used.
Also you could use the Zoomify alghoritm approach to determine your scale factor. You can start from the original dimensions and divide them by 2 until you get a value smaller than a maximum value defined by you, which you consider acceptable. That way your scale factor will be a power of 2.
I'm using a canvas to resize client-side an image before uploading it on the server.
maxWidth = 500;
maxHeight = 500;
//manage resizing
if (image.width >= image.height) {
var ratio = 1 / (image.width / maxWidth);
}
else {
var ratio = 1 / (image.height / maxHeight);
}
...
canvas.width = image.width * ratio;
canvas.height = image.height * ratio;
var resCtx = canvas.getContext('2d');
resCtx.drawImage(image, 0, 0, image.width * ratio, image.height * ratio);
This works, since on the server is saved the resized image, but there are two points i would like to improve:
image weight in KB is important to me; i want a very light weight image; even if it is resized, the canvas' image is still too heavy; i can see that the image saved on the server has a resolution of 96 DPI and 32-bit of color-depth even if the original image has a resolution of 72 DPI and 24-bit of color-depth; why? Can i set the canvas' image resolution?
the resized image does not look very nice, because the resizing proces introduce distortion... I've tried the custom algorithm by GameAlchemist in this post:
HTML5 Canvas Resize (Downscale) Image High Quality?
getting a very nice result, but then the resized image was more heavy in KB than the original one! Is there a good algorithm in order to get quality resized images keeping them lightweight?
DPI does not matter at all with images. An image at 1k x 1k will be just the same if 892478427 DPI or as 1 DPI. DPI is arbitrary in this context so ignore that part (it is only used as information for DTP programs so they know the relative size compared to document size). Images are only measured in pixels.
Canvas is RGBA based (32-bits, 24-bit colors + 8 bit alpha channel) so it's optimal form for exporting images will be in this format (ie. PNG files). You can however export 24-bits images without the alpha channel by requesting JPEG format as export format.
Compression is basically signal processing. As in all forms of (lossy) compression you try to remove frequencies in the signal in order to reduce the size. The more high frequencies there is the harder it is to compress the image (or sound or anything else signal based).
In images high frequency manifests as small details (thin lines and so forth) and as noise. To reduce the size of a compressed image you need to remove high frequencies. You can do this by using interpolation as a low-pass filter. A blur is a form of low-pass filter as well and they work in the same way in principle.
So in order to reduce image size you can apply a slight blur on the image before compressing it.
The JPEG format support quality settings which can reduce the size as well although this using a different approach than blurring:
// 0.5 = quality, lower = lower quality. Range is [0.0, 1.0]
var dataUri = canvas.toDataURL('image/jpeg', 0.5);
To blur an image you can use a simple and fast method of scaling it to half the size and then back up (with smoothing enabled). This will use interpolation as a low-pass filter by averaging the pixels.
Or you can use a "real" blur algorithm such as Gaussian blur as well as box blur, but only with a small amount.
I am working on an image cropping tool at the moment, the image crop tool comes from jCrop, what I am trying to is make the image the user takes the crop from smaller than the original uploaded. Basically if uploads a landscape image I need to make the image 304px wide without alterting the aspect ratio of the shot.
For instance if the user uploads a portrait shot, I need make the image 237px without altering the aspect ratio of the shot.
Is this possible? I have access to original images sizes in my code, but I cannot work out make sure I am not altering the aspect ratio?
Yes, it's possible if the source image is already wide enough. If it's not wide enough there isn't enough data to crop and if you wanted to maintain aspect ratio, you'd need to scale the image up before the crop.
Something like this should get you started:
CropWidth=237;
AspectRatio= SourceWidth/SourceHeight;
CropHeight = CropWidth*AspectRatio;
To properly maintain aspect ratio you should use GCD:
function gcd(a, b) {
return (b == 0) ? a : gcd(b, a % b);
}
You should then do something like this:
function calcRatio(objectWidth, objectHeight) {
var ratio = gcd(objectWidth, objectHeight),
xRatio = objectWidth / ratio,
yRatio = objectHeight / ratio;
return { "x": xRatio, "y": yRatio };
}
This will get you the ratio of some object. You can use this information to figure out how large the resulting image should be.
function findSize (targetHeight, xRatio, yRatio) {
var widthCalc = Math.round((xRatio * targetHeight) / yRatio);
return { "width" : widthCalc, "height" : targetHeight };
}
var test = calcRatio(1280,720),
dimensions = findSize(400, test.x, test.y);
//400 is what we want the new height of the image to be
Those are your dimensions. If you don't have any extra "space" around your images that you need to account for then your work is done. Otherwise you need to handle a couple cases.