Я планирую использовать его с JavaScript, чтобы обрезать изображение для всего окна.
Изменить: я буду использовать сторонний компонент, который принимает соотношение сторон только в таком формате, как: 4:3
, 16:9
.
Я планирую использовать его с JavaScript, чтобы обрезать изображение для всего окна.
Изменить: я буду использовать сторонний компонент, который принимает соотношение сторон только в таком формате, как: 4:3
, 16:9
.
Полагаю, что вы ищете подходящее соотношение сторон integer:integer
, например 16:9
, а не решение float:1
, например 1.77778:1
.
Если да, то вам нужно найти наибольший общий делитель (GCD) и разделите оба значения на это. GCD - это самое большое число, которое равномерно делит оба числа. Таким образом, GCD для 6 и 10 равен 2, GCD для 44 и 99 составляет 11.
Например, монитор 1024x768 имеет GCD 256. Когда вы разделите оба значения на это, вы получите 4x3 или 4: 3.
A (рекурсивный) алгоритм GCD:
function gcd (a,b):
if b == 0:
return a
return gcd (b, a mod b)
В 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));
}
И вот некоторый полный HTML/Javascript, который показывает один из способов определения размера экрана и вычисления соотношения сторон. Это работает в FF3, я не уверен, что поддерживают другие браузеры для screen.width
и 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>
Он выводит (на мой странный широкоэкранный монитор):
Dimensions = 1680 x 1050
Gcd = 210
Aspect = 8:5
Другие, на которых я тестировал это:
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
Мне жаль, что у меня не было этого дома, но, к сожалению, это не рабочая машина.
Что вы делаете, если вы обнаружите, что соотношение сторон не поддерживается графическим инструментом изменения размера, это другое дело. Я подозреваю, что лучше всего будет добавлять линии с буквенным боксом (например, те, которые вы получаете сверху и снизу вашего старого телевизора, когда вы смотрите на него широкоэкранный фильм). Я бы добавил их сверху/снизу или по бокам (в зависимости от того, какое из них приводит к наименьшему количеству линий буксования), пока изображение не удовлетворит требования.
Одна вещь, которую вы, возможно, захотите рассмотреть, - это качество изображения, которое было изменено с 16: 9 до 5: 4. Я до сих пор помню невероятно высоких, тонких ковбоев, которые я смотрел в юности по телевизору перед бокс-письмом был представлен. Возможно, вам лучше иметь одно изображение на соотношение сторон и просто изменить размер для фактических размеров экрана, прежде чем отправлять его по кабелю.
aspectRatio = width / height
если это то, что вы после. Затем вы можете умножить его на одно из измерений целевого пространства, чтобы узнать другое (которое поддерживает соотношение) например,
widthT = heightT * aspectRatio
heightT = widthT / aspectRatio
Ответ paxdiablo велик, но есть много общих разрешений, которые имеют только несколько более или менее пикселей в заданном направлении, а наибольший общий подход делителя дает им ужасные результаты.
Возьмем, к примеру, правильное разрешение 1360x765, которое дает хорошее соотношение 16: 9, используя подход gcd. Согласно Steam, эта резолюция используется только 0,01% ее пользователей, а 1366x768 используется при прохождении 18,9%. Посмотрим, что получится с помощью подхода gcd:
1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)
Мы хотели бы объединить соотношение 683: 384 с ближайшим соотношением 16: 9.
Я написал python script, который анализирует текстовый файл со вставленными номерами на странице опроса Steam Hardware и печатает все разрешения и самые близкие известные отношения, а также распространенность каждого отношения (что было моей целью, когда я начал это):
# 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 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]) + '%')
Для любопытных это распространенность показаний экрана среди пользователей Steam (по состоянию на октябрь 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%
Я думаю, вы хотите решить, какой из 4: 3 и 16: 9 лучше всего подходит.
function getAspectRatio(width, height) {
var ratio = width / height;
return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}
Вот версия наилучшего рационального алгоритма аппроксимации Джеймса Фарея с регулируемым уровнем нечеткости, портированной на javascript из кода вычисления соотношения сторон, изначально написанного в python.
Метод принимает float (width/height
) и верхний предел для числителя/знаменателя дробей.
В приведенном ниже примере я устанавливаю верхний предел 50
, потому что мне нужно 1035x582
(1.77835051546) обрабатываться как 16:9
(1.77777777778), а не 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>
Результат:
4,3 // (1.33333333333) (800 x 600)
16,9 // (1.77777777778) (2560.0 x 1440)
16,9 // (1.77835051546) (1035.0 x 582)
На всякий случай, если вы фанат производительности...
Самый быстрый способ (в JavaScript) вычислить соотношение прямоangularьников - использовать настоящий двоичный алгоритм Великого общего делителя.
(Все тесты скорости и времени были сделаны другими, вы можете проверить один тест здесь: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor/)
Вот оно:
/* 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]
*/
Я думаю, что это делает то, о чем вы просите:
webdeveloper.com - десятичная дробь
Ширина/высота дает вам десятичное число, преобразованное во фракцию с ":" вместо "/", дает вам "соотношение".
Этот алгоритм в Python предоставляет вам часть этого пути.
Расскажите, что произойдет, если окна смешные.
Возможно, то, что вам нужно, это список всех приемлемых коэффициентов (для стороннего компонента). Затем найдите ближайшее совпадение с вашим окном и верните это соотношение из списка.
Как альтернативное решение для поиска GCD, я предлагаю вам проверить набор стандартных значений. Вы можете найти список Wikipedia.
Я предполагаю, что вы говорите о видео здесь, и в этом случае вам также может понадобиться беспокоиться о соотношении сторон изображения исходного видео. Например.
PAL DV поставляется с разрешением 720x576. Который был бы похож на его 4: 3. Теперь, в зависимости от соотношения сторон пикселей (PAR), коэффициент отображения может быть либо 4: 3, либо 16: 9.
Для получения дополнительной информации см. здесь http://en.wikipedia.org/wiki/Pixel_aspect_ratio
Вы можете получить квадратное соотношение сторон пикселей и много веб-видео, но вы можете смотреть из других случаев.
Надеюсь, что это поможет
Марк
На основании других ответов, вот как я получил числа, которые мне нужны в 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')}
Вот мое решение, это довольно прямолинейно, так как все, о чем я забочусь, это не обязательно GCD или даже точные соотношения: потому что тогда вы получаете странные вещи, такие как 345/113, которые не являются понятными человеку.
В основном я устанавливаю приемлемый ландшафт или отношения портрета и их "значение" как float... Затем я сравниваю свою поплавковую версию отношения с каждой и которая когда-либо имеет самую низкую абсолютную разницу значений - это отношение, самое близкое к элементу, Таким образом, когда пользователь делает это 16: 9, но затем удаляет 10 пикселей со дна, он по-прежнему считается 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
Я считаю, что соотношение сторон - это ширина, разделенная на высоту.
r = w/h
бит странного способа сделать это, но использовать разрешение как аспект. Например.
1024: 768
или вы можете попробовать
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);
}
}
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);
в моем случае я хочу что-то вроде
[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 ]
Width / Height
?