Planuję użyć go z JavaScriptem, aby przyciąć obraz tak, aby pasował do całego okna.
Edycja : będę używać komponentu innej firmy, który akceptuje tylko proporcje w formacie: 4:3
, 16:9
.
javascript
algorithm
crop
aspect-ratio
Nathan
źródło
źródło
Odpowiedzi:
Rozumiem, że szukasz użytecznego
integer:integer
rozwiązania ze współczynnikiem proporcji ,16:9
a nie takiegofloat:1
rozwiązania1.77778:1
.Jeśli tak, to co musisz zrobić, to znaleźć największy wspólny dzielnik (GCD) i podzielić przez niego obie wartości. GCD to najwyższa liczba, która równo dzieli obie liczby. Więc GCD dla 6 i 10 to 2, GCD dla 44 i 99 to 11.
Na przykład monitor 1024x768 ma GCD 256. Dzieląc obie wartości przez, otrzymujemy 4x3 lub 4: 3.
Algorytm (rekurencyjny) GCD:
function gcd (a,b): if b == 0: return a return gcd (b, a mod b)
W 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)); }
A oto kompletny kod HTML / JavaScript, który pokazuje jeden ze sposobów wykrywania rozmiaru ekranu i obliczania współczynnika proporcji z tego. Działa to w FF3, nie jestem pewien, do czego obsługują inne przeglądarki
screen.width
iscreen.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>
Wyprowadza (na moim dziwnym monitorze szerokoekranowym):
Dimensions = 1680 x 1050 Gcd = 210 Aspect = 8:5
Inne, na których to przetestowałem:
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
Żałuję, że nie mam tego ostatniego w domu, ale nie, to niestety maszyna robocza.
To, co zrobisz, jeśli okaże się, że współczynnik proporcji nie jest obsługiwany przez narzędzie do zmiany rozmiaru grafiki, to inna sprawa. Podejrzewam, że najlepszym rozwiązaniem byłoby dodanie linii z literami (jak te, które dostajesz na górze i na dole starego telewizora, gdy oglądasz na nim film szerokoekranowy). Dodawałbym je u góry / dołu lub po bokach (w zależności od tego, który z nich powoduje najmniejszą liczbę linii z czarnymi pasami), aż obraz spełni wymagania.
Jedną rzeczą, którą warto rozważyć, jest jakość obrazu, który został zmieniony z 16: 9 na 5: 4 - wciąż pamiętam niesamowicie wysokich, chudych kowbojów, których oglądałem w telewizji w młodości, zanim wprowadzono skrzynkę pocztową. Lepiej byłoby mieć jeden inny obraz na współczynnik proporcji i po prostu zmienić rozmiar na właściwy dla rzeczywistych wymiarów ekranu przed wysłaniem go dalej.
źródło
728x90
->364:45
nie jestem pewien, czy jest to pożądany wynikjeśli o to ci chodzi. Możesz następnie pomnożyć go przez jeden z wymiarów przestrzeni docelowej, aby znaleźć drugi (który zachowuje stosunek) np.
źródło
Odpowiedź paxdiablo jest świetna, ale istnieje wiele typowych rozdzielczości, które mają tylko kilka mniej lub więcej pikseli w danym kierunku, a zastosowanie największego wspólnego dzielnika daje im okropne wyniki.
Weźmy na przykład dobrze zachowującą się rozdzielczość 1360x765, która daje ładny współczynnik 16: 9 przy zastosowaniu podejścia gcd. Według Steam z tej rozdzielczości korzysta tylko 0,01% użytkowników, a 1366x768 - aż 18,9%. Zobaczmy, co otrzymamy stosując podejście gcd:
1360x765 - 16:9 (0.01%) 1360x768 - 85:48 (2.41%) 1366x768 - 683:384 (18.9%)
Chcielibyśmy zaokrąglić ten stosunek 683: 384 do najbliższego, 16: 9.
Napisałem skrypt w języku Python, który analizuje plik tekstowy z wklejonymi liczbami ze strony ankiety dotyczącej sprzętu Steam i drukuje wszystkie rozdzielczości i najbliższe znane współczynniki, a także rozpowszechnienie każdego współczynnika (co było moim celem, gdy zaczynałam):
# 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% (w x h 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's 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]) + '%')
Dla ciekawskich są to rozpowszechnienie współczynników ekranu wśród użytkowników Steam (stan na październik 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%
źródło
Chyba chcesz zdecydować, która z opcji 4: 3 i 16: 9 jest najlepsza.
function getAspectRatio(width, height) { var ratio = width / height; return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9'; }
źródło
Oto wersja najlepszego racjonalnego algorytmu przybliżenia Jamesa Fareya z regulowanym poziomem nieostrości, przeniesiona do javascript z kodu obliczania współczynnika kształtu pierwotnie napisanego w Pythonie.
Metoda przyjmuje zmiennoprzecinkową (
width/height
) i górną granicę dla licznika / mianownika ułamka.W poniższym przykładzie ustawiam górną granicę,
50
ponieważ potrzebuję1035x582
(1.77835051546), aby być traktowanym jako16:9
(1.77777777778), a nie345:194
za pomocą zwykłegogcd
algorytmu wymienionego w innych odpowiedziach.<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>
4,3 // (1.33333333333) (800 x 600) 16,9 // (1.77777777778) (2560.0 x 1440) 16,9 // (1.77835051546) (1035.0 x 582)
źródło
Na wypadek, gdybyś był maniakiem wydajności ...
Najszybszy sposób (w JavaScript) na obliczenie współczynnika prostokąta przy użyciu prawdziwego binarnego algorytmu Great Common Divisor.
(Wszystkie testy szybkości i czasu zostały wykonane przez innych, jeden test porównawczy można sprawdzić tutaj: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor / )
Tutaj jest to:
źródło
Oto moje rozwiązanie, które jest dość proste, ponieważ wszystko, na czym mi zależy, to niekoniecznie GCD lub nawet dokładne proporcje: ponieważ wtedy otrzymujesz dziwne rzeczy, takie jak 345/113, które nie są zrozumiałe dla człowieka.
Zasadniczo ustawiam akceptowalne proporcje krajobrazu lub portretu i ich „wartość” jako zmienną ... Następnie porównuję moją zmienną wersję współczynnika z każdym i ten, który kiedykolwiek ma najmniejszą bezwzględną różnicę wartości, jest stosunkiem najbliższym pozycji. W ten sposób, gdy użytkownik zrobi 16: 9, ale potem usunie 10 pikseli od dołu, nadal liczy się jako 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' return find_closest_ratio(divided) except TypeError: return None
źródło
Jako alternatywne rozwiązanie do wyszukiwania GCD proponuję sprawdzić zestaw wartości standardowych. Możesz znaleźć listę w Wikipedii .
źródło
Zakładam, że mówisz tutaj o wideo, w takim przypadku możesz również martwić się o proporcje pikseli źródłowego wideo. Na przykład.
PAL DV jest dostępny w rozdzielczości 720x576. Który wyglądałby jak 4: 3. Teraz, w zależności od współczynnika proporcji pikseli (PAR), współczynnik ekranu może wynosić 4: 3 lub 16: 9.
Aby uzyskać więcej informacji, zajrzyj tutaj http://en.wikipedia.org/wiki/Pixel_aspect_ratio
Możesz uzyskać współczynnik proporcji pikseli kwadratowych i jest to dużo wideo w Internecie, ale możesz chcieć uważać na inne przypadki.
Mam nadzieję że to pomoże
znak
źródło
W oparciu o inne odpowiedzi, oto jak uzyskałem liczby, których potrzebowałem w Pythonie;
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')}
źródło
Uważam, że współczynnik proporcji to szerokość podzielona przez wysokość.
źródło
Myślę, że robi to, o co prosisz:
webdeveloper.com - ułamek dziesiętny
Szerokość / wysokość daje ułamek dziesiętny, konwertowany na ułamek z „:” zamiast „/” daje „współczynnik”.
źródło
Ten algorytm w Pythonie prowadzi cię do tego celu.
Powiedz mi, co się stanie, jeśli okna mają zabawny rozmiar.
Może to, co powinieneś mieć, to lista wszystkich akceptowalnych współczynników (do składnika innej firmy). Następnie znajdź najbliższe dopasowanie do swojego okna i zwróć ten współczynnik z listy.
źródło
trochę dziwny sposób, ale użyj rozdzielczości jako aspektu. NA PRZYKŁAD
1024: 768
lub możesz spróbować
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); } }
źródło
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);
źródło
w moim przypadku chcę coś takiego
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 ]
źródło
Zawsze możesz zacząć od utworzenia tabeli odnośników na podstawie typowych współczynników proporcji. Sprawdź https://en.wikipedia.org/wiki/Display_aspect_ratio Następnie możesz po prostu dokonać podziału
W przypadku problemów z życia codziennego możesz zrobić coś takiego jak poniżej
let ERROR_ALLOWED = 0.05 let STANDARD_ASPECT_RATIOS = [ [1, '1:1'], [4/3, '4:3'], [5/4, '5:4'], [3/2, '3:2'], [16/10, '16:10'], [16/9, '16:9'], [21/9, '21:9'], [32/9, '32:9'], ] let RATIOS = STANDARD_ASPECT_RATIOS.map(function(tpl){return tpl[0]}).sort() let LOOKUP = Object() for (let i=0; i < STANDARD_ASPECT_RATIOS.length; i++){ LOOKUP[STANDARD_ASPECT_RATIOS[i][0]] = STANDARD_ASPECT_RATIOS[i][1] } /* Find the closest value in a sorted array */ function findClosest(arrSorted, value){ closest = arrSorted[0] closestDiff = Math.abs(arrSorted[0] - value) for (let i=1; i<arrSorted.length; i++){ let diff = Math.abs(arrSorted[i] - value) if (diff < closestDiff){ closestDiff = diff closest = arrSorted[i] } else { return closest } } return arrSorted[arrSorted.length-1] } /* Estimate the aspect ratio based on width x height (order doesn't matter) */ function estimateAspectRatio(dim1, dim2){ let ratio = Math.max(dim1, dim2) / Math.min(dim1, dim2) if (ratio in LOOKUP){ return LOOKUP[ratio] } // Look by approximation closest = findClosest(RATIOS, ratio) if (Math.abs(closest - ratio) <= ERROR_ALLOWED){ return '~' + LOOKUP[closest] } return 'non standard ratio: ' + Math.round(ratio * 100) / 100 + ':1' }
Następnie po prostu podajesz wymiary w dowolnej kolejności
estimateAspectRatio(1920, 1080) // 16:9 estimateAspectRatio(1920, 1085) // ~16:9 estimateAspectRatio(1920, 1150) // non standard ratio: 1.65:1 estimateAspectRatio(1920, 1200) // 16:10 estimateAspectRatio(1920, 1220) // ~16:10
źródło
?
źródło