What is the algorithm for calculating the proportions?

I plan to use it with JavaScript to crop the image for the entire window.

Edit : I will use a third-party component that accepts the aspect ratio only in a format such as: 4:3 , 16:9 .

+72
javascript algorithm aspect-ratio crop
Jul 27 '09 at 4:20
source share
17 answers

I believe that you are looking for a suitable integer:integer aspect ratio, for example 16:9 , and not a float:1 solution, for example 1.77778:1 .

If yes, then you need to find the largest common factor (GCD) and divide both values ​​by this. GCD is the largest number that evenly divides both numbers. Thus, the GCD for 6 and 10 is 2, the GCD for 44 and 99 is 11.

For example, a 1024x768 monitor has a GCD of 256. When you divide both values ​​into this, you get 4x3 or 4: 3.

A (recursive) GCD algorithm:

 function gcd (a,b): if b == 0: return a return gcd (b, a mod b) 

In C:

 static int gcd (int a, int b) { return (b == 0) ? a : gcd (b, a%b); } int main(void) { printf ("gcd(1024,768) = %d\n",gcd(1024,768)); } 

And here is some full HTML / Javascript that shows one way to determine screen size and calculate aspect ratio. This works in FF3, I'm not sure if other browsers support screen.width and screen.height .

 <html><body> <script type="text/javascript"> function gcd (a, b) { return (b == 0) ? a : gcd (b, a%b); } var w = screen.width; var h = screen.height; var r = gcd (w, h); document.write ("<pre>"); document.write ("Dimensions = ", w, " x ", h, "<br>"); document.write ("Gcd = ", r, "<br>"); document.write ("Aspect = ", w/r, ":", h/r); document.write ("</pre>"); </script> </body></html> 

It outputs (to my weird widescreen monitor):

 Dimensions = 1680 x 1050 Gcd = 210 Aspect = 8:5 

Others I've tested this on:

 Dimensions = 1280 x 1024 Gcd = 256 Aspect = 5:4 Dimensions = 1152 x 960 Gcd = 192 Aspect = 6:5 Dimensions = 1280 x 960 Gcd = 320 Aspect = 4:3 Dimensions = 1920 x 1080 Gcd = 120 Aspect = 16:9 

I am sorry that I did not have this house, but, unfortunately, this is not a working machine.

What you do if you find that the aspect ratio is not supported by the graphical resizing tool is another matter. I suspect that it is best to add lines with lettering (for example, the ones you get on top and bottom of your old TV when you watch a widescreen movie on it). I would add them at the top / bottom or on the sides (depending on which one leads to the least number of skidding lines) until the image meets the requirements.

One thing you might want to consider is image quality, which was changed from 16: 9 to 5: 4. I still remember the incredibly tall, thin cowboys I watched in my youth on TV before boxing. was submitted. You might be better off having one image per aspect ratio and just resize it to the actual screen size before sending it over the cable.

+179
Jul 27 '09 at 4:41
source share
 aspectRatio = width / height 

if that is what you are after. Then you can multiply it by one of the dimensions of the target space to find out the other (which supports the ratio) for example,

 widthT = heightT * aspectRatio heightT = widthT / aspectRatio 
+39
Jul 27 '09 at 4:23
source share

Paxdiablo's answer is great, but there are many common resolutions that only have a few more or less pixels in a given direction, and the greatest common divider approach gives them terrible results.

Take, for example, the correct resolution of 1360x765, which gives a good 16: 9 ratio using the gcd approach. According to Steam, this resolution is used only by 0.01% of its users, and 1366x768 is used when passing 18.9%. Let's see what happens with the gcd approach:

 1360x765 - 16:9 (0.01%) 1360x768 - 85:48 (2.41%) 1366x768 - 683:384 (18.9%) 

We would like to combine the 683: 384 ratio with the closest 16: 9 ratio.

I wrote a python script that analyzes the text file with the numbers inserted on the Steam Hardware survey page and prints all the permissions and the closest known relationships, as well as the prevalence of each relationship (which was my goal when I started this):

 # Contents pasted from store.steampowered.com/hwsurvey, section 'Primary Display Resolution' steam_file = './steam.txt' # Taken from http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Vector_Video_Standards4.svg/750px-Vector_Video_Standards4.svg.png accepted_ratios = ['5:4', '4:3', '3:2', '8:5', '5:3', '16:9', '17:9'] #------------------------------------------------------- def gcd(a, b): if b == 0: return a return gcd (b, a % b) #------------------------------------------------------- class ResData: #------------------------------------------------------- # Expected format: 1024 x 768 4.37% -0.21% (wxh prevalence% change%) def __init__(self, steam_line): tokens = steam_line.split(' ') self.width = int(tokens[0]) self.height = int(tokens[2]) self.prevalence = float(tokens[3].replace('%', '')) # This part based on pixdiablo gcd answer - http://stackoverflow.com/a/1186465/828681 common = gcd(self.width, self.height) self.ratio = str(self.width / common) + ':' + str(self.height / common) self.ratio_error = 0 # Special case: ratio is not well behaved if not self.ratio in accepted_ratios: lesser_error = 999 lesser_index = -1 my_ratio_normalized = float(self.width) / float(self.height) # Check how far from each known aspect this resolution is, and take one with the smaller error for i in range(len(accepted_ratios)): ratio = accepted_ratios[i].split(':') w = float(ratio[0]) h = float(ratio[1]) known_ratio_normalized = w / h distance = abs(my_ratio_normalized - known_ratio_normalized) if (distance < lesser_error): lesser_index = i lesser_error = distance self.ratio_error = distance self.ratio = accepted_ratios[lesser_index] #------------------------------------------------------- def __str__(self): descr = str(self.width) + 'x' + str(self.height) + ' - ' + self.ratio + ' - ' + str(self.prevalence) + '%' if self.ratio_error > 0: descr += ' error: %.2f' % (self.ratio_error * 100) + '%' return descr #------------------------------------------------------- # Returns a list of ResData def parse_steam_file(steam_file): result = [] for line in file(steam_file): result.append(ResData(line)) return result #------------------------------------------------------- ratios_prevalence = {} data = parse_steam_file(steam_file) print('Known Steam resolutions:') for res in data: print(res) acc_prevalence = ratios_prevalence[res.ratio] if (res.ratio in ratios_prevalence) else 0 ratios_prevalence[res.ratio] = acc_prevalence + res.prevalence # Hack to fix 8:5, more known as 16:10 ratios_prevalence['16:10'] = ratios_prevalence['8:5'] del ratios_prevalence['8:5'] print('\nSteam screen ratio prevalences:') sorted_ratios = sorted(ratios_prevalence.items(), key=lambda x: x[1], reverse=True) for value in sorted_ratios: print(value[0] + ' -> ' + str(value[1]) + '%') 

For the curious, this is the prevalence of screen readings among Steam users (as of October 2012):

 16:9 -> 58.9% 16:10 -> 24.0% 5:4 -> 9.57% 4:3 -> 6.38% 5:3 -> 0.84% 17:9 -> 0.11% 
+12
Nov 20
source share

I think you want to decide which of 4: 3 and 16: 9 works best.

 function getAspectRatio(width, height) { var ratio = width / height; return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9'; } 
+11
Jul 27 '09 at 4:53
source share

Here is the version of the best rational James Farey approximation algorithm with an adjustable fuzziness ported to javascript from the aspect ratio calculation code originally written in python.

The method accepts float ( width/height ) and an upper limit for the numerator / denominator of fractions.

In the example below, I set the upper limit to 50 because I need 1035x582 (1.77835051546) to be processed as 16:9 (1.77777777778) and not 345:194 , which you get with a simple gcd algorithm specified in other answers.

 <html> <body> <script type="text/javascript"> function aspect_ratio(val, lim) { var lower = [0, 1]; var upper = [1, 0]; while (true) { var mediant = [lower[0] + upper[0], lower[1] + upper[1]]; if (val * mediant[1] > mediant[0]) { if (lim < mediant[1]) { return upper; } lower = mediant; } else if (val * mediant[1] == mediant[0]) { if (lim >= mediant[1]) { return mediant; } if (lower[1] < upper[1]) { return lower; } return upper; } else { if (lim < mediant[1]) { return lower; } upper = mediant; } } } document.write (aspect_ratio(800 / 600, 50) +"<br/>"); document.write (aspect_ratio(1035 / 582, 50) + "<br/>"); document.write (aspect_ratio(2560 / 1440, 50) + "<br/>"); </script> </body></html> 

Result:

  4,3 // (1.33333333333) (800 x 600) 16,9 // (1.77777777778) (2560.0 x 1440) 16,9 // (1.77835051546) (1035.0 x 582) 
+3
Mar 25 '17 at 12:41
source share

Just in case you are a performance fan ...

The fastest way (in JavaScript) to calculate the ratio of right-angled nicknames is to use the real binary algorithm of the Great common divisor.

(All speed and time tests were done by others, you can check one test here: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor/ )

Here it is:

 /* the binary Great Common Divisor calculator */ function gcd (u, v) { if (u === v) return u; if (u === 0) return v; if (v === 0) return u; if (~u & 1) if (v & 1) return gcd(u >> 1, v); else return gcd(u >> 1, v >> 1) << 1; if (~v & 1) return gcd(u, v >> 1); if (u > v) return gcd((u - v) >> 1, v); return gcd((v - u) >> 1, u); } /* returns an array with the ratio */ function ratio (w, h) { var d = gcd(w,h); return [w/d, h/d]; } /* example */ var r1 = ratio(1600, 900); var r2 = ratio(1440, 900); var r3 = ratio(1366, 768); var r4 = ratio(1280, 1024); var r5 = ratio(1280, 720); var r6 = ratio(1024, 768); /* will output this: r1: [16, 9] r2: [8, 5] r3: [683, 384] r4: [5, 4] r5: [16, 9] r6: [4, 3] */ 

+3
May 09 '18 at 18:43
source share

I think this does what you ask for:

webdeveloper.com - decimal

Width / height gives you a decimal number converted to a fraction with ":" instead of "/", gives you a "ratio".

+1
Jul 27 '09 at 4:43
source share

This Python algorithm provides you with part of this path.




Tell us what happens if the windows are funny.

Perhaps what you need is a list of all acceptable coefficients (for a third-party component). Then find the closest match to your window and return that ratio from the list.

+1
Jul 27 '09 at 4:44
source share

As an alternative solution for finding GCD, I suggest you check out a set of standard values. You can find the list of Wikipedia .

+1
Jul 27 '09 at 4:55
source share

I assume that you are talking about the video here, in which case you may also need to worry about the aspect ratio of the image of the original video. For example.

PAL DV comes with a resolution of 720x576. Which would be similar to its 4: 3. Now, depending on the aspect ratio of the pixels (PAR), the display coefficient can be either 4: 3 or 16: 9.

For more information see here http://en.wikipedia.org/wiki/Pixel_aspect_ratio

You can get the square pixel aspect ratio and lots of web videos, but you can watch from other cases.

Hope this helps

Mark

+1
Jul 27 '09 at 5:08
source share

Based on other answers, here's how I got the numbers I need in Python;

 from decimal import Decimal def gcd(a,b): if b == 0: return a return gcd(b, a%b) def closest_aspect_ratio(width, height): g = gcd(width, height) x = Decimal(str(float(width)/float(g))) y = Decimal(str(float(height)/float(g))) dec = Decimal(str(x/y)) return dict(x=x, y=y, dec=dec) >>> closest_aspect_ratio(1024, 768) {'y': Decimal('3.0'), 'x': Decimal('4.0'), 'dec': Decimal('1.333333333333333333333333333')} 
+1
Jun 04 '13 at 16:26
source share

Here is my solution, it’s pretty straight forward, since all I care about is not necessarily GCD or even exact ratios: because then you get strange things like 345/113 that are not understandable to humans.

Basically I set an acceptable landscape or portrait relationship and their "value" as a float ... Then I compare my float version of the relationship with each and which ever has the lowest absolute difference in values ​​- this is the ratio closest to the element, Thus when the user does this 16: 9 but then removes 10 pixels from the bottom, it is still considered 16: 9 ...

 accepted_ratios = { 'landscape': ( (u'5:4', 1.25), (u'4:3', 1.33333333333), (u'3:2', 1.5), (u'16:10', 1.6), (u'5:3', 1.66666666667), (u'16:9', 1.77777777778), (u'17:9', 1.88888888889), (u'21:9', 2.33333333333), (u'1:1', 1.0) ), 'portrait': ( (u'4:5', 0.8), (u'3:4', 0.75), (u'2:3', 0.66666666667), (u'10:16', 0.625), (u'3:5', 0.6), (u'9:16', 0.5625), (u'9:17', 0.5294117647), (u'9:21', 0.4285714286), (u'1:1', 1.0) ), } def find_closest_ratio(ratio): lowest_diff, best_std = 9999999999, '1:1' layout = 'portrait' if ratio < 1.0 else 'landscape' for pretty_str, std_ratio in accepted_ratios[layout]: diff = abs(std_ratio - ratio) if diff < lowest_diff: lowest_diff = diff best_std = pretty_str return best_std def extract_ratio(width, height): try: divided = float(width)/float(height) if divided == 1.0: return '1:1' else: return find_closest_ratio(divided) except TypeError: return None 
+1
Mar 16 '17 at
source share

I believe aspect ratio is the width divided by height.

  r = w/h 
0
Jul 27 '09 at 4:24
source share

A bit of a weird way to do this, but use resolution as an aspect. For example.

1024: 768

or you can try

 var w = screen.width; var h = screen.height; for(var i=1,asp=w/h;i<5000;i++){ if(asp*i % 1==0){ i=9999; document.write(asp*i,":",1*i); } } 
0
Apr 17 '12 at 15:05
source share
 function ratio(w, h) { function mdc(w, h) { var resto; do { resto = w % h; w = h; h = resto; } while (resto != 0); return w; } var mdc = mdc(w, h); var width = w/mdc; var height = h/mdc; console.log(width + ':' + height); } ratio(1920, 1080); 
0
Sep 03 '19 at 19:29
source share

in my case i want something like

[10,5,15,20,25] β†’ [2, 1, 3, 4, 5]

 function ratio(array){ let min = Math.min(...array); let ratio = array.map((element)=>{ return element/min; }); return ratio; } document.write(ratio([10,5,15,20,25])); // [ 2, 1, 3, 4, 5 ] 

0
Sep 05 '19 at 10:49
source share
 Width / Height 

?

-2
Jul 27 '09 at 4:22
source share



All Articles