Bir görüntüyü tüm pencereye sığacak şekilde kırpmak için JavaScript ile kullanmayı planlıyorum.
Düzenleme : Yalnızca en boy oranını şu biçimde kabul eden bir 3. taraf bileşeni kullanacağım: 4:3
, 16:9
.
Bir görüntüyü tüm pencereye sığacak şekilde kırpmak için JavaScript ile kullanmayı planlıyorum.
Düzenleme : Yalnızca en boy oranını şu biçimde kabul eden bir 3. taraf bileşeni kullanacağım: 4:3
, 16:9
.
Yanıtlar:
Anladığım kadarıyla bir çözümden çok kullanışlı bir en boy oranı integer:integer
çözümü arıyorsunuz .16:9
float:1
1.77778:1
Öyleyse, yapmanız gereken en büyük ortak böleni (OBEB) bulmak ve her iki değeri de buna bölmektir. OBEB, her iki sayıyı da eşit olarak bölen en yüksek sayıdır. Yani 6 ve 10 için OBEB 2, 44 ve 99 için OBEB 11'dir.
Örneğin, 1024x768'lik bir monitörün GCD'si 256'dır. Her iki değeri de buna böldüğünüzde 4x3 veya 4: 3 elde edersiniz.
A (yinelemeli) GCD algoritması:
function gcd (a,b):
if b == 0:
return a
return gcd (b, a mod b)
C'de:
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));
}
Ve işte, ekran boyutunu algılamanın ve bundan en boy oranını hesaplamanın bir yolunu gösteren bazı eksiksiz HTML / Javascript. FF3 Bu eserler, ben diğer tarayıcıları destekleyen için ne emin değilim screen.width
ve 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>
Çıktılar (garip geniş ekran monitörümde):
Dimensions = 1680 x 1050
Gcd = 210
Aspect = 8:5
Bunu test ettiğim diğerleri:
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
Keşke sonuncusu evde olsaydı ama hayır, maalesef bu bir iş makinesi.
En boy oranının grafiği yeniden boyutlandırma aracınız tarafından desteklenmediğini fark ederseniz ne yapacağınız başka bir konudur. Sanırım en iyi bahis, mektup kutusu satırları eklemek olacaktır (eski TV'nizin üstünde ve altında geniş ekranlı bir film izlerken gördüğünüz gibi). Resim gereksinimleri karşılayana kadar bunları üst / alt veya yan taraflara (hangisi en az mektup kutusu satırıyla sonuçlanırsa) eklerdim.
Göz önünde bulundurmak isteyebileceğiniz bir şey, 16: 9'dan 5: 4'e değiştirilmiş bir resmin kalitesidir - gençliğimde mektup boksunun tanıtılmasından önce televizyonda izlediğim inanılmaz derecede uzun, ince kovboyları hala hatırlıyorum. En boy oranı başına bir farklı görüntüye sahip olmanız daha iyi olabilir ve kabloyu göndermeden önce gerçek ekran boyutları için doğru olanı yeniden boyutlandırabilirsiniz.
728x90
-> 364:45
istenen sonucun bu olduğundan emin değilim
paxdiablo'nun cevabı harika, ancak belirli bir yönde az veya çok piksele sahip birçok ortak çözünürlük var ve en büyük ortak bölme yaklaşımı onlara korkunç sonuçlar veriyor.
Örneğin, gcd yaklaşımını kullanarak güzel bir 16: 9 oranı veren 1360x765'lik iyi davranılmış çözünürlüğü ele alalım. Steam'e göre, bu çözünürlük kullanıcılarının yalnızca% 0,01'i tarafından kullanılırken, 1366x768% 18,9'u tarafından kullanılıyor. Gcd yaklaşımını kullanarak ne elde ettiğimize bakalım:
1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)
Bu 683: 384 oranını en yakın 16: 9 oranına yuvarlamak isterdik.
Steam Donanım anket sayfasından yapıştırılan sayılarla bir metin dosyasını ayrıştıran ve tüm çözünürlükleri ve bilinen en yakın oranları ve her oranın yaygınlığını (bunu başlattığımda amacım buydu) yazdıran bir python betiği yazdım:
# 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]) + '%')
Merak edenler için, Steam kullanıcıları arasında ekran oranlarının yaygınlığı (Ekim 2012 itibariyle):
16:9 -> 58.9%
16:10 -> 24.0%
5:4 -> 9.57%
4:3 -> 6.38%
5:3 -> 0.84%
17:9 -> 0.11%
Sanırım 4: 3 ve 16: 9'dan hangisinin en uygun olduğuna karar vermek istiyorsunuz.
function getAspectRatio(width, height) {
var ratio = width / height;
return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}
James Farey'in en iyi rasyonel yaklaşım algoritmasının, orijinal olarak python'da yazılmış en boy oranı hesaplama kodundan javascript'e taşınan ayarlanabilir bulanıklık seviyesine sahip bir versiyonu .
Yöntem bir float ( width/height
) ve kesir payı / payda için bir üst limit alır .
Aşağıdaki örnekte , diğer yanıtlarda listelenen düz algoritma ile elde ettiğinizden ziyade (1.77835051546) ' nın (1.77777777778) olarak ele alınmasına 50
ihtiyacım olduğu için bir üst sınır 1035x582
ayarlıyorum .16:9
345:194
gcd
<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>
Sonuç:
4,3 // (1.33333333333) (800 x 600)
16,9 // (1.77777777778) (2560.0 x 1440)
16,9 // (1.77835051546) (1035.0 x 582)
Performans manyağı olmanız durumunda ...
Dikdörtgen oranını hesaplamanın en hızlı yolu (JavaScript'te), gerçek bir ikili Büyük Ortak Bölen algoritması kullanmaktır.
(Tüm hız ve zamanlama testleri başkaları tarafından yapılmıştır, burada bir karşılaştırmayı kontrol edebilirsiniz: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor / )
İşte burada:
/* 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]
*/
İşte benim çözümüm oldukça açık, çünkü tek umursadığım GCD veya hatta doğru oranlar değil: çünkü o zaman 345/113 gibi insan tarafından anlaşılamayan garip şeyler elde edersiniz.
Temel olarak kabul edilebilir manzara veya portre oranlarını ve bunların "değerini" kayan nokta olarak ayarlıyorum ... Daha sonra oranın kayan versiyonunu her biri ile karşılaştırıyorum ve en düşük mutlak değer farkına sahip olan, öğeye en yakın orandır. Bu şekilde, kullanıcı bunu 16: 9 yapıp daha sonra alttan 10 pikseli kaldırdığında, yine de 16: 9 olarak sayılır ...
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
GCD aramasına alternatif bir çözüm olarak, bir dizi standart değeri kontrol etmenizi öneririm. Wikipedia'da bir liste bulabilirsiniz .
Burada video hakkında konuştuğunuzu varsayıyorum, bu durumda kaynak videonun piksel en boy oranı hakkında da endişelenmeniz gerekebilir. Örneğin.
PAL DV 720x576 çözünürlükte gelir. Hangisi 4: 3 gibi görünür. Artık Piksel en boy oranına (PAR) bağlı olarak ekran oranı 4: 3 veya 16: 9 olabilir.
Daha fazla bilgi için buraya bakın http://en.wikipedia.org/wiki/Pixel_aspect_ratio
Kare piksel Boyut Oranı elde edebilirsiniz ve birçok web videosu budur, ancak diğer durumları izlemek isteyebilirsiniz.
Bu yardımcı olur umarım
işaret
Diğer cevaplara göre, işte ihtiyacım olan sayıları Python'da nasıl elde ettim;
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')}
En boy oranının genişliğin yüksekliğe bölünmesi olduğuna inanıyorum.
r = w/h
Sanırım bu istediğin şeyi yapıyor:
webdeveloper.com - ondalıktan kesire
Genişlik / yükseklik size bir ondalık sayı verir, '/' yerine ":" ile kesire dönüştürülürse size bir "oran" verir.
Python'daki bu algoritma sizi oradaki yolun bir parçası haline getiriyor.
Pencereler komik bir boyuttaysa ne olacağını söyle.
Belki de sahip olmanız gereken, tüm kabul edilebilir oranların bir listesidir (3. taraf bileşenine göre). Ardından, pencerenize en yakın eşleşmeyi bulun ve bu oranı listeden döndürün.
benim durumumda bir şey istiyorum
[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 ]
Her zaman ortak en boy oranlarına göre bir arama tablosu oluşturarak başlayabilirsiniz. Https://en.wikipedia.org/wiki/Display_aspect_ratio adresini kontrol edin O zaman bölmeyi basitçe yapabilirsiniz
Gerçek hayat problemleri için aşağıdaki gibi bir şey yapabilirsiniz
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'
}
O zaman boyutları herhangi bir sırayla verirsiniz
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